+ 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 );