Example #1
0
static int
apply_func(
	void *data,
	void *arg )
{
	EntryInfo *ei = data;
	ID *idl = arg;

	bdb_idl_append_one( idl, ei->bei_id );
	return 0;
}
Example #2
0
File: idl.c Project: MPlatform/mdb
/* Append sorted list b to sorted list a. The result is unsorted but
 * a[1] is the min of the result and a[a[0]] is the max.
 */
int bdb_idl_append( ID *a, ID *b )
{
	ID ida, idb, tmp, swap = 0;

	if ( BDB_IDL_IS_ZERO( b ) ) {
		return 0;
	}

	if ( BDB_IDL_IS_ZERO( a ) ) {
		BDB_IDL_CPY( a, b );
		return 0;
	}

	if ( b[0] == 1 ) {
		return bdb_idl_append_one( a, BDB_IDL_FIRST( b ));
	}

	ida = BDB_IDL_LAST( a );
	idb = BDB_IDL_LAST( b );
	if ( BDB_IDL_IS_RANGE( a ) || BDB_IDL_IS_RANGE(b) ||
		a[0] + b[0] >= BDB_IDL_UM_MAX ) {
		a[2] = IDL_MAX( ida, idb );
		a[1] = IDL_MIN( a[1], b[1] );
		a[0] = NOID;
		return 0;
	}

	if ( ida > idb ) {
		swap = idb;
		a[a[0]] = idb;
		b[b[0]] = ida;
	}

	if ( b[1] < a[1] ) {
		tmp = a[1];
		a[1] = b[1];
	} else {
		tmp = b[1];
	}
	a[0]++;
	a[a[0]] = tmp;

	{
		int i = b[0] - 1;
		AC_MEMCPY(a+a[0]+1, b+2, i * sizeof(ID));
		a[0] += i;
	}
	if ( swap ) {
		b[b[0]] = swap;
	}
	return 0;
}
Example #3
0
static int
hdb_dn2idl_internal(
	struct dn2id_cookie *cx
)
{
	BDB_IDL_ZERO( cx->tmp );

	if ( cx->bdb->bi_idl_cache_size ) {
		char *ptr = ((char *)&cx->id)-1;

		cx->key.data = ptr;
		cx->key.size = sizeof(ID)+1;
		if ( cx->prefix == DN_SUBTREE_PREFIX ) {
			ID *ids = cx->depth ? cx->tmp : cx->ids;
			*ptr = cx->prefix;
			cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, ids);
			if ( cx->rc == LDAP_SUCCESS ) {
				if ( cx->depth ) {
					bdb_idl_delete( cx->tmp, cx->id );	/* ITS#6983, drop our own ID */
					bdb_idl_append( cx->ids, cx->tmp );
					cx->need_sort = 1;
				}
				return cx->rc;
			}
		}
		*ptr = DN_ONE_PREFIX;
		cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp);
		if ( cx->rc == LDAP_SUCCESS ) {
			goto gotit;
		}
		if ( cx->rc == DB_NOTFOUND ) {
			return cx->rc;
		}
	}

	bdb_cache_entryinfo_lock( cx->ei );

	/* If number of kids in the cache differs from on-disk, load
	 * up all the kids from the database
	 */
	if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) {
		EntryInfo ei;
		db_recno_t dkids = cx->ei->bei_dkids;
		ei.bei_parent = cx->ei;

		/* Only one thread should load the cache */
		while ( cx->ei->bei_state & CACHE_ENTRY_ONELEVEL ) {
			bdb_cache_entryinfo_unlock( cx->ei );
			ldap_pvt_thread_yield();
			bdb_cache_entryinfo_lock( cx->ei );
			if ( cx->ei->bei_ckids+1 == cx->ei->bei_dkids ) {
				goto synced;
			}
		}

		cx->ei->bei_state |= CACHE_ENTRY_ONELEVEL;

		bdb_cache_entryinfo_unlock( cx->ei );

		cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc,
			cx->bdb->bi_db_opflags );
		if ( cx->rc )
			goto done_one;

		cx->data.data = &cx->dbuf;
		cx->data.ulen = sizeof(ID);
		cx->data.dlen = sizeof(ID);
		cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;

		/* The first item holds the parent ID. Ignore it. */
		cx->key.data = &cx->nid;
		cx->key.size = sizeof(ID);
		cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET );
		if ( cx->rc ) {
			cx->dbc->c_close( cx->dbc );
			goto done_one;
		}

		/* If the on-disk count is zero we've never checked it.
		 * Count it now.
		 */
		if ( !dkids ) {
			cx->dbc->c_count( cx->dbc, &dkids, 0 );
			cx->ei->bei_dkids = dkids;
		}

		cx->data.data = cx->buf;
		cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID);
		cx->data.flags = DB_DBT_USERMEM;

		if ( dkids > 1 ) {
			/* Fetch the rest of the IDs in a loop... */
			while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data,
				DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) {
				u_int8_t *j;
				size_t len;
				void *ptr;
				DB_MULTIPLE_INIT( ptr, &cx->data );
				while (ptr) {
					DB_MULTIPLE_NEXT( ptr, &cx->data, j, len );
					if (j) {
						EntryInfo *ei2;
						diskNode *d = (diskNode *)j;
						short nrlen;

						BDB_DISK2ID( j + len - sizeof(ID), &ei.bei_id );
						nrlen = ((d->nrdnlen[0] ^ 0x80) << 8) | d->nrdnlen[1];
						ei.bei_nrdn.bv_len = nrlen;
						/* nrdn/rdn are set in-place.
						 * hdb_cache_load will copy them as needed
						 */
						ei.bei_nrdn.bv_val = d->nrdn;
						ei.bei_rdn.bv_len = len - sizeof(diskNode)
							- ei.bei_nrdn.bv_len;
						ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1;
						bdb_idl_append_one( cx->tmp, ei.bei_id );
						hdb_cache_load( cx->bdb, &ei, &ei2 );
					}
				}
			}
		}

		cx->rc = cx->dbc->c_close( cx->dbc );
done_one:
		bdb_cache_entryinfo_lock( cx->ei );
		cx->ei->bei_state &= ~CACHE_ENTRY_ONELEVEL;
		bdb_cache_entryinfo_unlock( cx->ei );
		if ( cx->rc )
			return cx->rc;

	} else {
		/* The in-memory cache is in sync with the on-disk data.
		 * do we have any kids?
		 */
synced:
		cx->rc = 0;
		if ( cx->ei->bei_ckids > 0 ) {
			/* Walk the kids tree; order is irrelevant since bdb_idl_sort
			 * will sort it later.
			 */
			avl_apply( cx->ei->bei_kids, apply_func,
				cx->tmp, -1, AVL_POSTORDER );
		}
		bdb_cache_entryinfo_unlock( cx->ei );
	}

	if ( !BDB_IDL_IS_RANGE( cx->tmp ) && cx->tmp[0] > 3 )
		bdb_idl_sort( cx->tmp, cx->buf );
	if ( cx->bdb->bi_idl_cache_max_size && !BDB_IDL_IS_ZERO( cx->tmp )) {
		char *ptr = ((char *)&cx->id)-1;
		cx->key.data = ptr;
		cx->key.size = sizeof(ID)+1;
		*ptr = DN_ONE_PREFIX;
		bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc );
	}

gotit:
	if ( !BDB_IDL_IS_ZERO( cx->tmp )) {
		if ( cx->prefix == DN_SUBTREE_PREFIX ) {
			bdb_idl_append( cx->ids, cx->tmp );
			cx->need_sort = 1;
			if ( !(cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS)) {
				ID *save, idcurs;
				EntryInfo *ei = cx->ei;
				int nokids = 1;
				save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ),
					cx->op->o_tmpmemctx );
				BDB_IDL_CPY( save, cx->tmp );

				idcurs = 0;
				cx->depth++;
				for ( cx->id = bdb_idl_first( save, &idcurs );
					cx->id != NOID;
					cx->id = bdb_idl_next( save, &idcurs )) {
					EntryInfo *ei2;
					cx->ei = NULL;
					if ( bdb_cache_find_id( cx->op, cx->txn, cx->id, &cx->ei,
						ID_NOENTRY, NULL ))
						continue;
					if ( cx->ei ) {
						ei2 = cx->ei;
						if ( !( ei2->bei_state & CACHE_ENTRY_NO_KIDS )) {
							BDB_ID2DISK( cx->id, &cx->nid );
							hdb_dn2idl_internal( cx );
							if ( !BDB_IDL_IS_ZERO( cx->tmp ))
								nokids = 0;
						}
						bdb_cache_entryinfo_lock( ei2 );
						ei2->bei_finders--;
						bdb_cache_entryinfo_unlock( ei2 );
					}
				}
				cx->depth--;
				cx->op->o_tmpfree( save, cx->op->o_tmpmemctx );
				if ( nokids ) {
					bdb_cache_entryinfo_lock( ei );
					ei->bei_state |= CACHE_ENTRY_NO_GRANDKIDS;
					bdb_cache_entryinfo_unlock( ei );
				}
			}
			/* Make sure caller knows it had kids! */
			cx->tmp[0]=1;

			cx->rc = 0;
		} else {
			BDB_IDL_CPY( cx->ids, cx->tmp );
		}
	}
	return cx->rc;
}