Example #1
0
/* Find each id in ids that is a child of base and move it to res.
 */
int
mdb_idscope(
	Operation *op,
	MDB_txn *txn,
	ID base,
	ID *ids,
	ID *res )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
	MDB_dbi dbi = mdb->mi_dn2id;
	MDB_val		key, data;
	MDB_cursor	*cursor;
	ID ida, id, cid = 0, ci0 = 0, idc = 0;
	char	*ptr;
	int		rc, copy;

	key.mv_size = sizeof(ID);

	MDB_IDL_ZERO( res );

	rc = mdb_cursor_open( txn, dbi, &cursor );
	if ( rc ) return rc;

	ida = mdb_idl_first( ids, &cid );

	/* Don't bother moving out of ids if it's a range */
	if (!MDB_IDL_IS_RANGE(ids)) {
		idc = ids[0];
		ci0 = cid;
	}

	while (ida != NOID) {
		copy = 1;
		id = ida;
		while (id) {
			key.mv_data = &id;
			rc = mdb_cursor_get( cursor, &key, &data, MDB_SET );
			if ( rc ) {
				/* not found, drop this from ids */
				copy = 0;
				break;
			}
			ptr = data.mv_data;
			ptr += data.mv_size - sizeof(ID);
			memcpy( &id, ptr, sizeof(ID) );
			if ( id == base ) {
				if ( res[0] >= MDB_IDL_DB_SIZE-1 ) {
					/* too many aliases in scope. Fallback to range */
					MDB_IDL_RANGE( res, MDB_IDL_FIRST( ids ), MDB_IDL_LAST( ids ));
					goto leave;
				}
				res[0]++;
				res[res[0]] = ida;
				copy = 0;
				break;
			}
			if ( op->ors_scope == LDAP_SCOPE_ONELEVEL )
				break;
		}
		if (idc) {
			if (copy) {
				if (ci0 != cid)
					ids[ci0] = ids[cid];
				ci0++;
			} else
				idc--;
		}
		ida = mdb_idl_next( ids, &cid );
	}
	if (!MDB_IDL_IS_RANGE( ids ))
		ids[0] = idc;

leave:
	mdb_cursor_close( cursor );
	return rc;
}
Example #2
0
int
mdb_idl_fetch_key(
	BackendDB	*be,
	MDB_txn		*txn,
	MDB_dbi		dbi,
	MDB_val		*key,
	ID			*ids,
	MDB_cursor	**saved_cursor,
	int			get_flag )
{
	MDB_val data, key2, *kptr;
	MDB_cursor *cursor;
	ID *i;
	size_t len;
	int rc;
	MDB_cursor_op opflag;

	char keybuf[16];

	Debug( LDAP_DEBUG_ARGS,
		"mdb_idl_fetch_key: %s\n", 
		mdb_show_key( keybuf, key->mv_data, key->mv_size ), 0, 0 );

	assert( ids != NULL );

	if ( saved_cursor && *saved_cursor ) {
		opflag = MDB_NEXT;
	} else if ( get_flag == LDAP_FILTER_GE ) {
		opflag = MDB_SET_RANGE;
	} else if ( get_flag == LDAP_FILTER_LE ) {
		opflag = MDB_FIRST;
	} else {
		opflag = MDB_SET;
	}

	/* If we're not reusing an existing cursor, get a new one */
	if( opflag != MDB_NEXT ) {
		rc = mdb_cursor_open( txn, dbi, &cursor );
		if( rc != 0 ) {
			Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: "
				"cursor failed: %s (%d)\n", mdb_strerror(rc), rc, 0 );
			return rc;
		}
	} else {
		cursor = *saved_cursor;
	}
	
	/* If this is a LE lookup, save original key so we can determine
	 * when to stop. If this is a GE lookup, save the key since it
	 * will be overwritten.
	 */
	if ( get_flag == LDAP_FILTER_LE || get_flag == LDAP_FILTER_GE ) {
		key2.mv_data = keybuf;
		key2.mv_size = key->mv_size;
		AC_MEMCPY( keybuf, key->mv_data, key->mv_size );
		kptr = &key2;
	} else {
		kptr = key;
	}
	len = key->mv_size;
	rc = mdb_cursor_get( cursor, kptr, &data, opflag );

	/* skip presence key on range inequality lookups */
	while (rc == 0 && kptr->mv_size != len) {
		rc = mdb_cursor_get( cursor, kptr, &data, MDB_NEXT_NODUP );
	}
	/* If we're doing a LE compare and the new key is greater than
	 * our search key, we're done
	 */
	if (rc == 0 && get_flag == LDAP_FILTER_LE && memcmp( kptr->mv_data,
		key->mv_data, key->mv_size ) > 0 ) {
		rc = MDB_NOTFOUND;
	}
	if (rc == 0) {
		i = ids+1;
		rc = mdb_cursor_get( cursor, key, &data, MDB_GET_MULTIPLE );
		while (rc == 0) {
			memcpy( i, data.mv_data, data.mv_size );
			i += data.mv_size / sizeof(ID);
			rc = mdb_cursor_get( cursor, key, &data, MDB_NEXT_MULTIPLE );
		}
		if ( rc == MDB_NOTFOUND ) rc = 0;
		ids[0] = i - &ids[1];
		/* On disk, a range is denoted by 0 in the first element */
		if (ids[1] == 0) {
			if (ids[0] != MDB_IDL_RANGE_SIZE) {
				Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: "
					"range size mismatch: expected %d, got %ld\n",
					MDB_IDL_RANGE_SIZE, ids[0], 0 );
				mdb_cursor_close( cursor );
				return -1;
			}
			MDB_IDL_RANGE( ids, ids[2], ids[3] );
		}
		data.mv_size = MDB_IDL_SIZEOF(ids);
	}

	if ( saved_cursor && rc == 0 ) {
		if ( !*saved_cursor )
			*saved_cursor = cursor;
	}
	else
		mdb_cursor_close( cursor );

	if( rc == MDB_NOTFOUND ) {
		return rc;

	} else if( rc != 0 ) {
		Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: "
			"get failed: %s (%d)\n",
			mdb_strerror(rc), rc, 0 );
		return rc;

	} else if ( data.mv_size == 0 || data.mv_size % sizeof( ID ) ) {
		/* size not multiple of ID size */
		Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: "
			"odd size: expected %ld multiple, got %ld\n",
			(long) sizeof( ID ), (long) data.mv_size, 0 );
		return -1;

	} else if ( data.mv_size != MDB_IDL_SIZEOF(ids) ) {
		/* size mismatch */
		Debug( LDAP_DEBUG_ANY, "=> mdb_idl_fetch_key: "
			"get size mismatch: expected %ld, got %ld\n",
			(long) ((1 + ids[0]) * sizeof( ID )), (long) data.mv_size, 0 );
		return -1;
	}

	return rc;
}