X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-bdb%2Fid2entry.c;h=6bb5278a627c0b3e3a3159cb380fb07be51d0f54;hb=55339651d6d6e21dc85dca7949cb094e57a1f6b2;hp=d4eb26711119a21037a44c44bfb0832f1362fcf5;hpb=c3984d9f596ca79f6755012f997070c189a533fe;p=openldap diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c index d4eb267111..6bb5278a62 100644 --- a/servers/slapd/back-bdb/id2entry.c +++ b/servers/slapd/back-bdb/id2entry.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2000-2004 The OpenLDAP Foundation. + * Copyright 2000-2012 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -18,9 +18,9 @@ #include #include +#include #include "back-bdb.h" -#include "external.h" static int bdb_id2entry_put( BackendDB *be, @@ -33,6 +33,7 @@ static int bdb_id2entry_put( DBT key, data; struct berval bv; int rc; + ID nid; #ifdef BDB_HIER struct berval odn, ondn; @@ -44,8 +45,11 @@ static int bdb_id2entry_put( e->e_nname = slap_empty_bv; #endif DBTzero( &key ); - key.data = (char *) &e->e_id; + + /* Store ID in BigEndian format */ + key.data = &nid; key.size = sizeof(ID); + BDB_ID2DISK( e->e_id, &nid ); rc = entry_encode( e, &bv ); #ifdef BDB_HIER @@ -95,28 +99,75 @@ int bdb_id2entry( struct bdb_info *bdb = (struct bdb_info *) be->be_private; DB *db = bdb->bi_id2entry->bdi_db; DBT key, data; - struct berval bv; - int rc = 0, ret = 0; + DBC *cursor; + EntryHeader eh; + char buf[16]; + int rc = 0, off; + ID nid; *e = NULL; DBTzero( &key ); - key.data = (char *) &id; + key.data = &nid; key.size = sizeof(ID); + BDB_ID2DISK( id, &nid ); DBTzero( &data ); - data.flags = DB_DBT_MALLOC; + data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; /* fetch it */ - rc = db->get( db, tid, &key, &data, bdb->bi_db_opflags ); + rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); + if ( rc ) return rc; + + /* Get the nattrs / nvals counts first */ + data.ulen = data.dlen = sizeof(buf); + data.data = buf; + rc = cursor->c_get( cursor, &key, &data, DB_SET ); + if ( rc ) goto finish; + + + eh.bv.bv_val = buf; + eh.bv.bv_len = data.size; + rc = entry_header( &eh ); + if ( rc ) goto finish; + + if ( eh.nvals ) { + /* Get the size */ + data.flags ^= DB_DBT_PARTIAL; + data.ulen = 0; + rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); + if ( rc != DB_BUFFER_SMALL ) goto finish; + + /* Allocate a block and retrieve the data */ + off = eh.data - eh.bv.bv_val; + eh.bv.bv_len = eh.nvals * sizeof( struct berval ) + data.size; + eh.bv.bv_val = ch_malloc( eh.bv.bv_len ); + eh.data = eh.bv.bv_val + eh.nvals * sizeof( struct berval ); + data.data = eh.data; + data.ulen = data.size; + + /* skip past already parsed nattr/nvals */ + eh.data += off; + + rc = cursor->c_get( cursor, &key, &data, DB_CURRENT ); + } + +finish: + cursor->c_close( cursor ); if( rc != 0 ) { return rc; } - DBT2bv( &data, &bv ); - - rc = entry_decode( &bv, e ); + if ( eh.nvals ) { +#ifdef SLAP_ZONE_ALLOC + rc = entry_decode(&eh, e, bdb->bi_cache.c_zctx); +#else + rc = entry_decode(&eh, e); +#endif + } else { + *e = entry_alloc(); + } if( rc == 0 ) { (*e)->e_id = id; @@ -124,8 +175,13 @@ int bdb_id2entry( /* only free on error. On success, the entry was * decoded in place. */ - ch_free( data.data ); +#ifndef SLAP_ZONE_ALLOC + ch_free(eh.bv.bv_val); +#endif } +#ifdef SLAP_ZONE_ALLOC + ch_free(eh.bv.bv_val); +#endif return rc; } @@ -139,10 +195,12 @@ int bdb_id2entry_delete( DB *db = bdb->bi_id2entry->bdi_db; DBT key; int rc; + ID nid; DBTzero( &key ); - key.data = (char *) &e->e_id; + key.data = &nid; key.size = sizeof(ID); + BDB_ID2DISK( e->e_id, &nid ); /* delete from database */ rc = db->del( db, tid, &key, 0 ); @@ -151,52 +209,41 @@ int bdb_id2entry_delete( } int bdb_entry_return( - Entry *e ) + Entry *e +) { /* Our entries are allocated in two blocks; the data comes from * the db itself and the Entry structure and associated pointers * are allocated in entry_decode. The db data pointer is saved - * in e_bv. Since the Entry structure is allocated as a single - * block, e_attrs is always a fixed offset from e. The exception - * is when an entry has been modified, in which case we also need - * to free e_attrs. + * in e_bv. */ - if( !e->e_bv.bv_val ) { /* A regular entry, from do_add */ - entry_free( e ); - return 0; - } - if( (void *) e->e_attrs != (void *) (e+1)) { - attrs_free( e->e_attrs ); - } - - /* See if the DNs were changed by modrdn */ - if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val > - e->e_bv.bv_val + e->e_bv.bv_len ) { - ch_free(e->e_name.bv_val); - ch_free(e->e_nname.bv_val); + if ( e->e_bv.bv_val ) { + /* See if the DNs were changed by modrdn */ + if( e->e_nname.bv_val < e->e_bv.bv_val || e->e_nname.bv_val > + e->e_bv.bv_val + e->e_bv.bv_len ) { + ch_free(e->e_name.bv_val); + ch_free(e->e_nname.bv_val); + } e->e_name.bv_val = NULL; e->e_nname.bv_val = NULL; + /* In tool mode the e_bv buffer is realloc'd, leave it alone */ + if( !(slapMode & SLAP_TOOL_MODE) ) { + free( e->e_bv.bv_val ); + } + BER_BVZERO( &e->e_bv ); } -#ifndef BDB_HIER - /* In tool mode the e_bv buffer is realloc'd, leave it alone */ - if( !(slapMode & SLAP_TOOL_MODE) ) { - free( e->e_bv.bv_val ); - } -#else - free( e->e_bv.bv_val ); -#endif - free( e ); - + entry_free( e ); return 0; } int bdb_entry_release( - Operation *o, + Operation *op, Entry *e, int rw ) { - struct bdb_info *bdb = (struct bdb_info *) o->o_bd->be_private; - struct bdb_op_info *boi = NULL; + struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; + struct bdb_op_info *boi; + OpExtra *oex; /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE, SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */ @@ -204,25 +251,59 @@ int bdb_entry_release( if ( slapMode == SLAP_SERVER_MODE ) { /* If not in our cache, just free it */ if ( !e->e_private ) { +#ifdef SLAP_ZONE_ALLOC + return bdb_entry_return( bdb, e, -1 ); +#else return bdb_entry_return( e ); +#endif } /* free entry and reader or writer lock */ - if ( o ) { - boi = (struct bdb_op_info *)o->o_private; + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == bdb ) break; } + boi = (struct bdb_op_info *)oex; + /* lock is freed with txn */ if ( !boi || boi->boi_txn ) { - bdb_unlocked_cache_return_entry_rw( &bdb->bi_cache, e, rw ); + bdb_unlocked_cache_return_entry_rw( bdb, e, rw ); } else { - bdb_cache_return_entry_rw( bdb->bi_dbenv, &bdb->bi_cache, e, rw, &boi->boi_lock ); - o->o_tmpfree( boi, o->o_tmpmemctx ); - o->o_private = NULL; + struct bdb_lock_info *bli, *prev; + for ( prev=(struct bdb_lock_info *)&boi->boi_locks, + bli = boi->boi_locks; bli; prev=bli, bli=bli->bli_next ) { + if ( bli->bli_id == e->e_id ) { + bdb_cache_return_entry_rw( bdb, e, rw, &bli->bli_lock ); + prev->bli_next = bli->bli_next; + /* Cleanup, or let caller know we unlocked */ + if ( bli->bli_flag & BLI_DONTFREE ) + bli->bli_flag = 0; + else + op->o_tmpfree( bli, op->o_tmpmemctx ); + break; + } + } + if ( !boi->boi_locks ) { + LDAP_SLIST_REMOVE( &op->o_extra, &boi->boi_oe, OpExtra, oe_next ); + if ( !(boi->boi_flag & BOI_DONTFREE)) + op->o_tmpfree( boi, op->o_tmpmemctx ); + } } } else { +#ifdef SLAP_ZONE_ALLOC + int zseq = -1; + if (e->e_private != NULL) { + BEI(e)->bei_e = NULL; + zseq = BEI(e)->bei_zseq; + } +#else if (e->e_private != NULL) BEI(e)->bei_e = NULL; +#endif e->e_private = NULL; +#ifdef SLAP_ZONE_ALLOC + bdb_entry_return ( bdb, e, zseq ); +#else bdb_entry_return ( e ); +#endif } return 0; @@ -246,35 +327,26 @@ int bdb_entry_get( int rc; const char *at_name = at ? at->ad_cname.bv_val : "(null)"; - u_int32_t locker = 0; DB_LOCK lock; - int free_lock_id = 0; -#ifdef NEW_LOGGING - LDAP_LOG( BACK_BDB, ARGS, - "bdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 ); - LDAP_LOG( BACK_BDB, ARGS, - "bdb_entry_get: oc: \"%s\", at: \"%s\"\n", - oc ? oc->soc_cname.bv_val : "(null)", at_name, 0); -#else Debug( LDAP_DEBUG_ARGS, "=> bdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 ); Debug( LDAP_DEBUG_ARGS, "=> bdb_entry_get: oc: \"%s\", at: \"%s\"\n", oc ? oc->soc_cname.bv_val : "(null)", at_name, 0); -#endif - if( op ) boi = (struct bdb_op_info *) op->o_private; - if( boi != NULL && op->o_bd == boi->boi_bdb ) { - txn = boi->boi_txn; - locker = boi->boi_locker; + if( op ) { + OpExtra *oex; + LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { + if ( oex->oe_key == bdb ) break; + } + boi = (struct bdb_op_info *)oex; + if ( boi ) + txn = boi->boi_txn; } - if ( txn != NULL ) { - locker = TXN_ID ( txn ); - } else if ( !locker ) { - rc = LOCK_ID ( bdb->bi_dbenv, &locker ); - free_lock_id = 1; + if ( !txn ) { + rc = bdb_reader_get( op, bdb->bi_dbenv, &txn ); switch(rc) { case 0: break; @@ -285,7 +357,7 @@ int bdb_entry_get( dn2entry_retry: /* can we find entry */ - rc = bdb_dn2entry( op, txn, ndn, &ei, 0, locker, &lock ); + rc = bdb_dn2entry( op, txn, ndn, &ei, 0, &lock ); switch( rc ) { case DB_NOTFOUND: case 0: @@ -294,80 +366,40 @@ dn2entry_retry: case DB_LOCK_NOTGRANTED: /* the txn must abort and retry */ if ( txn ) { - boi->boi_err = rc; + if ( boi ) boi->boi_err = rc; return LDAP_BUSY; } ldap_pvt_thread_yield(); goto dn2entry_retry; default: if ( boi ) boi->boi_err = rc; - if ( free_lock_id ) { - LOCK_ID_FREE( bdb->bi_dbenv, locker ); - } return (rc != LDAP_BUSY) ? LDAP_OTHER : LDAP_BUSY; } if (ei) e = ei->bei_e; if (e == NULL) { -#ifdef NEW_LOGGING - LDAP_LOG( BACK_BDB, INFO, - "bdb_entry_get: cannot find entry (%s)\n", - ndn->bv_val, 0, 0 ); -#else Debug( LDAP_DEBUG_ACL, "=> bdb_entry_get: cannot find entry: \"%s\"\n", ndn->bv_val, 0, 0 ); -#endif - if ( free_lock_id ) { - LOCK_ID_FREE( bdb->bi_dbenv, locker ); - } return LDAP_NO_SUCH_OBJECT; } -#ifdef NEW_LOGGING - LDAP_LOG( BACK_BDB, DETAIL1, "bdb_entry_get: found entry (%s)\n", - ndn->bv_val, 0, 0 ); -#else Debug( LDAP_DEBUG_ACL, "=> bdb_entry_get: found entry: \"%s\"\n", ndn->bv_val, 0, 0 ); -#endif - -#ifdef BDB_ALIASES - /* find attribute values */ - if( is_entry_alias( e ) ) { -#ifdef NEW_LOGGING - LDAP_LOG( BACK_BDB, INFO, - "bdb_entry_get: entry (%s) is an alias\n", e->e_name.bv_val, 0, 0 ); -#else - Debug( LDAP_DEBUG_ACL, - "<= bdb_entry_get: entry is an alias\n", 0, 0, 0 ); -#endif - rc = LDAP_ALIAS_PROBLEM; - goto return_results; - } -#endif - if( is_entry_referral( e ) ) { -#ifdef NEW_LOGGING - LDAP_LOG( BACK_BDB, INFO, - "bdb_entry_get: entry (%s) is a referral.\n", e->e_name.bv_val, 0, 0); -#else + if ( oc && !is_entry_objectclass( e, oc, 0 )) { Debug( LDAP_DEBUG_ACL, - "<= bdb_entry_get: entry is a referral\n", 0, 0, 0 ); -#endif - rc = LDAP_REFERRAL; + "<= bdb_entry_get: failed to find objectClass %s\n", + oc->soc_cname.bv_val, 0, 0 ); + rc = LDAP_NO_SUCH_ATTRIBUTE; goto return_results; } - if ( oc && !is_entry_objectclass( e, oc, 0 )) { -#ifdef NEW_LOGGING - LDAP_LOG( BACK_BDB, INFO, - "bdb_entry_get: failed to find objectClass.\n", 0, 0, 0 ); -#else + /* NOTE: attr_find() or attrs_find()? */ + if ( at && attr_find( e->e_attrs, at ) == NULL ) { Debug( LDAP_DEBUG_ACL, - "<= bdb_entry_get: failed to find objectClass\n", - 0, 0, 0 ); -#endif + "<= bdb_entry_get: failed to find attribute %s\n", + at->ad_cname.bv_val, 0, 0 ); rc = LDAP_NO_SUCH_ATTRIBUTE; goto return_results; } @@ -375,29 +407,40 @@ dn2entry_retry: return_results: if( rc != LDAP_SUCCESS ) { /* free entry */ - bdb_cache_return_entry_rw(bdb->bi_dbenv, &bdb->bi_cache, e, rw, &lock); + bdb_cache_return_entry_rw(bdb, e, rw, &lock); + } else { - *ent = e; - /* big drag. we need a place to store a read lock so we can - * release it later?? - */ - if ( op && !boi ) { - boi = op->o_tmpcalloc(1,sizeof(struct bdb_op_info),op->o_tmpmemctx); - boi->boi_lock = lock; - op->o_private = boi; + if ( slapMode == SLAP_SERVER_MODE ) { + *ent = e; + /* big drag. we need a place to store a read lock so we can + * release it later?? If we're in a txn, nothing is needed + * here because the locks will go away with the txn. + */ + if ( op ) { + if ( !boi ) { + boi = op->o_tmpcalloc(1,sizeof(struct bdb_op_info),op->o_tmpmemctx); + boi->boi_oe.oe_key = bdb; + LDAP_SLIST_INSERT_HEAD( &op->o_extra, &boi->boi_oe, oe_next ); + } + if ( !boi->boi_txn ) { + struct bdb_lock_info *bli; + bli = op->o_tmpalloc( sizeof(struct bdb_lock_info), + op->o_tmpmemctx ); + bli->bli_next = boi->boi_locks; + bli->bli_id = e->e_id; + bli->bli_flag = 0; + bli->bli_lock = lock; + boi->boi_locks = bli; + } + } + } else { + *ent = entry_dup( e ); + bdb_cache_return_entry_rw(bdb, e, rw, &lock); } } - if ( free_lock_id ) { - LOCK_ID_FREE( bdb->bi_dbenv, locker ); - } - -#ifdef NEW_LOGGING - LDAP_LOG( BACK_BDB, ENTRY, "bdb_entry_get: rc=%d\n", rc, 0, 0 ); -#else Debug( LDAP_DEBUG_TRACE, "bdb_entry_get: rc=%d\n", rc, 0, 0 ); -#endif return(rc); }