]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-bdb/id2entry.c
Relax entry_header, zero-length entries are valid.
[openldap] / servers / slapd / back-bdb / id2entry.c
index 14efa8b9001db10f5363cc56b50503397a8e8de5..51238a151a68512db174c0a46fc82a4d9f6ee0ff 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2000-2007 The OpenLDAP Foundation.
+ * Copyright 2000-2011 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -93,7 +93,6 @@ int bdb_id2entry_update(
 int bdb_id2entry(
        BackendDB *be,
        DB_TXN *tid,
-       BDB_LOCKER locker,
        ID id,
        Entry **e )
 {
@@ -120,11 +119,6 @@ int bdb_id2entry(
        rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
        if ( rc ) return rc;
 
-       /* Use our own locker if needed */
-       if ( !tid && locker ) {
-               CURSOR_SETLOCKER( cursor, locker );
-       }
-
        /* Get the nattrs / nvals counts first */
        data.ulen = data.dlen = sizeof(buf);
        data.data = buf;
@@ -137,24 +131,26 @@ int bdb_id2entry(
        rc = entry_header( &eh );
        if ( rc ) goto finish;
 
-       /* 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 );
+       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 );
@@ -163,11 +159,15 @@ finish:
                return rc;
        }
 
+       if ( eh.nvals ) {
 #ifdef SLAP_ZONE_ALLOC
-       rc = entry_decode(&eh, e, bdb->bi_cache.c_zctx);
+               rc = entry_decode(&eh, e, bdb->bi_cache.c_zctx);
 #else
-       rc = entry_decode(&eh, e);
+               rc = entry_decode(&eh, e);
 #endif
+       } else {
+               *e = entry_alloc();
+       }
 
        if( rc == 0 ) {
                (*e)->e_id = id;
@@ -242,7 +242,8 @@ int bdb_entry_release(
        int rw )
 {
        struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
-       struct bdb_op_info *boi = NULL;
+       struct bdb_op_info *boi;
+       OpExtra *oex;
  
        /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE,
                        SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */
@@ -257,7 +258,10 @@ int bdb_entry_release(
 #endif
                }
                /* free entry and reader or writer lock */
-               boi = (struct bdb_op_info *)op->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 ) {
@@ -269,13 +273,18 @@ int bdb_entry_release(
                                if ( bli->bli_id == e->e_id ) {
                                        bdb_cache_return_entry_rw( bdb, e, rw, &bli->bli_lock );
                                        prev->bli_next = bli->bli_next;
-                                       op->o_tmpfree( bli, op->o_tmpmemctx );
+                                       /* 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 ) {
-                               op->o_tmpfree( boi, op->o_tmpmemctx );
-                               op->o_private = NULL;
+                               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 {
@@ -318,9 +327,7 @@ int bdb_entry_get(
        int     rc;
        const char *at_name = at ? at->ad_cname.bv_val : "(null)";
 
-       BDB_LOCKER      locker = 0;
        DB_LOCK         lock;
-       int             free_lock_id = 0;
 
        Debug( LDAP_DEBUG_ARGS,
                "=> bdb_entry_get: ndn: \"%s\"\n", ndn->bv_val, 0, 0 ); 
@@ -328,16 +335,18 @@ int bdb_entry_get(
                "=> bdb_entry_get: oc: \"%s\", at: \"%s\"\n",
                oc ? oc->soc_cname.bv_val : "(null)", at_name, 0);
 
-       if( op ) boi = (struct bdb_op_info *) op->o_private;
-       if( boi != NULL && op->o_bd->be_private == boi->boi_bdb->be_private ) {
-               txn = boi->boi_txn;
+       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 {
-               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;
@@ -348,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:
@@ -357,16 +366,13 @@ 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;
@@ -374,9 +380,6 @@ dn2entry_retry:
                Debug( LDAP_DEBUG_ACL,
                        "=> bdb_entry_get: cannot find entry: \"%s\"\n",
                                ndn->bv_val, 0, 0 ); 
-               if ( free_lock_id ) {
-                       LOCK_ID_FREE( bdb->bi_dbenv, locker );
-               }
                return LDAP_NO_SUCH_OBJECT; 
        }
        
@@ -392,6 +395,15 @@ dn2entry_retry:
                goto return_results;
        }
 
+       /* 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 attribute %s\n",
+                       at->ad_cname.bv_val, 0, 0 ); 
+               rc = LDAP_NO_SUCH_ATTRIBUTE;
+               goto return_results;
+       }
+
 return_results:
        if( rc != LDAP_SUCCESS ) {
                /* free entry */
@@ -407,8 +419,8 @@ return_results:
                        if ( op ) {
                                if ( !boi ) {
                                        boi = op->o_tmpcalloc(1,sizeof(struct bdb_op_info),op->o_tmpmemctx);
-                                       boi->boi_bdb = op->o_bd;
-                                       op->o_private = boi;
+                                       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;
@@ -416,6 +428,7 @@ return_results:
                                                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;
                                }
@@ -426,10 +439,6 @@ return_results:
                }
        }
 
-       if ( free_lock_id ) {
-               LOCK_ID_FREE( bdb->bi_dbenv, locker );
-       }
-
        Debug( LDAP_DEBUG_TRACE,
                "bdb_entry_get: rc=%d\n",
                rc, 0, 0 );