📄 idl.c
字号:
# if BDB_IDL_DB_SIZE < 4096# define BDB_ENOUGH 2048# else# define BDB_ENOUGH 1# endif#endif ID buf[BDB_IDL_DB_SIZE*BDB_ENOUGH]; char keybuf[16]; Debug( LDAP_DEBUG_ARGS, "bdb_idl_fetch_key: %s\n", bdb_show_key( key, keybuf ), 0, 0 ); assert( ids != NULL ); if ( saved_cursor && *saved_cursor ) { opflag = DB_NEXT; } else if ( get_flag == LDAP_FILTER_GE ) { opflag = DB_SET_RANGE; } else if ( get_flag == LDAP_FILTER_LE ) { opflag = DB_FIRST; } else { opflag = DB_SET; } /* only non-range lookups can use the IDL cache */ if ( bdb->bi_idl_cache_size && opflag == DB_SET ) { rc = bdb_idl_cache_get( bdb, db, key, ids ); if ( rc != LDAP_NO_SUCH_OBJECT ) return rc; } DBTzero( &data ); data.data = buf; data.ulen = sizeof(buf); data.flags = DB_DBT_USERMEM; /* If we're not reusing an existing cursor, get a new one */ if( opflag != DB_NEXT ) { rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "cursor failed: %s (%d)\n", db_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 ) { DBTzero( &key2 ); key2.flags = DB_DBT_USERMEM; key2.ulen = sizeof(keybuf); key2.data = keybuf; key2.size = key->size; AC_MEMCPY( keybuf, key->data, key->size ); kptr = &key2; } else { kptr = key; } len = key->size; rc = cursor->c_get( cursor, kptr, &data, flags | opflag ); /* skip presence key on range inequality lookups */ while (rc == 0 && kptr->size != len) { rc = cursor->c_get( cursor, kptr, &data, flags | DB_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->data, key->data, key->size ) > 0 ) { rc = DB_NOTFOUND; } if (rc == 0) { i = ids; while (rc == 0) { u_int8_t *j; DB_MULTIPLE_INIT( ptr, &data ); while (ptr) { DB_MULTIPLE_NEXT(ptr, &data, j, len); if (j) { ++i; BDB_DISK2ID( j, i ); } } rc = cursor->c_get( cursor, key, &data, flags | DB_NEXT_DUP ); } if ( rc == DB_NOTFOUND ) rc = 0; ids[0] = i - ids; /* On disk, a range is denoted by 0 in the first element */ if (ids[1] == 0) { if (ids[0] != BDB_IDL_RANGE_SIZE) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "range size mismatch: expected %d, got %ld\n", BDB_IDL_RANGE_SIZE, ids[0], 0 ); cursor->c_close( cursor ); return -1; } BDB_IDL_RANGE( ids, ids[2], ids[3] ); } data.size = BDB_IDL_SIZEOF(ids); } if ( saved_cursor && rc == 0 ) { if ( !*saved_cursor ) *saved_cursor = cursor; rc2 = 0; } else rc2 = cursor->c_close( cursor ); if (rc2) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 ); return rc2; } if( rc == DB_NOTFOUND ) { return rc; } else if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "get failed: %s (%d)\n", db_strerror(rc), rc, 0 ); return rc; } else if ( data.size == 0 || data.size % sizeof( ID ) ) { /* size not multiple of ID size */ Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "odd size: expected %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.size, 0 ); return -1; } else if ( data.size != BDB_IDL_SIZEOF(ids) ) { /* size mismatch */ Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "get size mismatch: expected %ld, got %ld\n", (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 ); return -1; } if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_put( bdb, db, key, ids, rc ); } return rc;}intbdb_idl_insert_key( BackendDB *be, DB *db, DB_TXN *tid, DBT *key, ID id ){ struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBT data; DBC *cursor; ID lo, hi, nlo, nhi, nid; char *err; { char buf[16]; Debug( LDAP_DEBUG_ARGS, "bdb_idl_insert_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); } assert( id != NOID ); if ( bdb->bi_idl_cache_size ) { bdb_idl_cache_del( bdb, db, key ); } DBTzero( &data ); data.size = sizeof( ID ); data.ulen = data.size; data.flags = DB_DBT_USERMEM; BDB_ID2DISK( id, &nid ); rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); return rc; } data.data = &nlo; /* Fetch the first data item for this key, to see if it * exists and if it's a range. */ rc = cursor->c_get( cursor, key, &data, DB_SET ); err = "c_get"; if ( rc == 0 ) { if ( nlo != 0 ) { /* not a range, count the number of items */ db_recno_t count; rc = cursor->c_count( cursor, &count, 0 ); if ( rc != 0 ) { err = "c_count"; goto fail; } if ( count >= BDB_IDL_DB_MAX ) { /* No room, convert to a range */ DBT key2 = *key; db_recno_t i; key2.dlen = key2.ulen; key2.flags |= DB_DBT_PARTIAL; BDB_DISK2ID( &nlo, &lo ); data.data = &nhi; rc = cursor->c_get( cursor, &key2, &data, DB_NEXT_NODUP ); if ( rc != 0 && rc != DB_NOTFOUND ) { err = "c_get next_nodup"; goto fail; } if ( rc == DB_NOTFOUND ) { rc = cursor->c_get( cursor, key, &data, DB_LAST ); if ( rc != 0 ) { err = "c_get last"; goto fail; } } else { rc = cursor->c_get( cursor, key, &data, DB_PREV ); if ( rc != 0 ) { err = "c_get prev"; goto fail; } } BDB_DISK2ID( &nhi, &hi ); /* Update hi/lo if needed, then delete all the items * between lo and hi */ if ( id < lo ) { lo = id; nlo = nid; } else if ( id > hi ) { hi = id; nhi = nid; } data.data = &nid; /* Don't fetch anything, just position cursor */ data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; data.dlen = data.ulen = 0; rc = cursor->c_get( cursor, key, &data, DB_SET ); if ( rc != 0 ) { err = "c_get 2"; goto fail; } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del range1"; goto fail; } /* Delete all the records */ for ( i=1; i<count; i++ ) { rc = cursor->c_get( cursor, &key2, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get next_dup"; goto fail; } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del range"; goto fail; } } /* Store the range marker */ data.size = data.ulen = sizeof(ID); data.flags = DB_DBT_USERMEM; nid = 0; rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); if ( rc != 0 ) { err = "c_put range"; goto fail; } nid = nlo; rc = cursor->c_put( cursor, key, &data, DB_KEYLAST ); if ( rc != 0 ) { err = "c_put lo"; goto fail; } nid = nhi; rc = cursor->c_put( cursor, key, &data, DB_KEYLAST ); if ( rc != 0 ) { err = "c_put hi"; goto fail; } } else { /* There's room, just store it */ goto put1; } } else { /* It's a range, see if we need to rewrite * the boundaries */ hi = id; data.data = &nlo; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get lo"; goto fail; } BDB_DISK2ID( &nlo, &lo ); if ( id > lo ) { data.data = &nhi; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get hi"; goto fail; } BDB_DISK2ID( &nhi, &hi ); } if ( id < lo || id > hi ) { /* Delete the current lo/hi */ rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del"; goto fail; } data.data = &nid; rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); if ( rc != 0 ) { err = "c_put lo/hi"; goto fail; } } } } else if ( rc == DB_NOTFOUND ) {put1: data.data = &nid; rc = cursor->c_put( cursor, key, &data, DB_NODUPDATA ); /* Don't worry if it's already there */ if ( rc != 0 && rc != DB_KEYEXIST ) { err = "c_put id"; goto fail; } } else { /* initial c_get failed, nothing was done */fail: Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); cursor->c_close( cursor ); return rc; } rc = cursor->c_close( cursor ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); } return rc;}intbdb_idl_delete_key( BackendDB *be, DB *db, DB_TXN *tid, DBT *key, ID id ){ struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBT data; DBC *cursor; ID lo, hi, tmp, nid, nlo, nhi; char *err; { char buf[16]; Debug( LDAP_DEBUG_ARGS, "bdb_idl_delete_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); } assert( id != NOID ); if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_del( bdb, db, key ); } BDB_ID2DISK( id, &nid ); DBTzero( &data ); data.data = &tmp; data.size = sizeof( id ); data.ulen = data.size; data.flags = DB_DBT_USERMEM; rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); return rc; } /* Fetch the first data item for this key, to see if it * exists and if it's a range. */ rc = cursor->c_get( cursor, key, &data, DB_SET ); err = "c_get"; if ( rc == 0 ) { if ( tmp != 0 ) { /* Not a range, just delete it */ if (tmp != nid) { /* position to correct item */ tmp = nid; rc = cursor->c_get( cursor, key, &data, DB_GET_BOTH ); if ( rc != 0 ) { err = "c_get id"; goto fail; } } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del id"; goto fail; } } else { /* It's a range, see if we need to rewrite * the boundaries */ data.data = &nlo; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get lo"; goto fail; } BDB_DISK2ID( &nlo, &lo ); data.data = &nhi; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get hi"; goto fail; } BDB_DISK2ID( &nhi, &hi ); if ( id == lo || id == hi ) { if ( id == lo ) { id++; lo = id; } else if ( id == hi ) { id--; hi = id; } if ( lo >= hi ) { /* The range has collapsed... */ rc = db->del( db, tid, key, 0 ); if ( rc != 0 ) { err = "del"; goto fail; } } else { if ( id == lo ) { /* reposition on lo slot */ data.data = &nlo; cursor->c_get( cursor, key, &data, DB_PREV ); } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del"; goto fail; } } if ( lo <= hi ) { BDB_ID2DISK( id, &nid ); data.data = &nid; rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); if ( rc != 0 ) { err = "c_put lo/hi"; goto fail; } } } } } else { /* initial c_get failed, nothing was done */fail: if ( rc != DB_NOTFOUND ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); } cursor->c_close( cursor ); return rc; } rc = cursor->c_close( cursor ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); } return rc;}/* * idl_intersection - return a = a intersection b */intbdb_idl_intersection( ID *a, ID *b ){ ID ida, idb; ID idmax, idmin; ID cursora = 0, cursorb = 0, cursorc; int swap = 0; if ( BDB_IDL_IS_ZERO( a ) || BDB_IDL_IS_ZERO( b ) ) { a[0] = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -