]> git.sur5r.net Git - openldap/commitdiff
rough in an add/delete and deadlock avoidance
authorKurt Zeilenga <kurt@openldap.org>
Sat, 23 Sep 2000 23:15:40 +0000 (23:15 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Sat, 23 Sep 2000 23:15:40 +0000 (23:15 +0000)
servers/slapd/back-bdb/add.c
servers/slapd/back-bdb/back-bdb.h
servers/slapd/back-bdb/backbdb.dsp
servers/slapd/back-bdb/delete.c [new file with mode: 0644]
servers/slapd/back-bdb/dn2id.c
servers/slapd/back-bdb/init.c
servers/slapd/back-bdb/nextid.c
servers/slapd/back-bdb/proto-bdb.h

index f59e5aad60ecead5e62ea1935854dfd836cfd1a8..3d550a9a2c26cd758ef108a7d7822cd7295ceb71 100644 (file)
@@ -22,13 +22,11 @@ bdb_add(
        struct bdb_info *bdb = (struct bdb_info *) be->be_private;
        char            *pdn = NULL;
        Entry           *p = NULL;
-       int                     rootlock = 0;
        int                     rc; 
        const char      *text = NULL;
        AttributeDescription *children = slap_schema.si_ad_children;
        DB_TXN          *ltid = NULL;
 
-
        Debug(LDAP_DEBUG_ARGS, "==> bdb_add: %s\n", e->e_dn, 0, 0);
 
        /* check entry's schema */
@@ -54,6 +52,17 @@ bdb_add(
                goto return_results;
        }
 
+       if (0) {
+retry: rc = txn_abort( ltid );
+               ltid = NULL;
+               op->o_private = NULL;
+               if( rc != 0 ) {
+                       rc = LDAP_OTHER;
+                       text = "internal error";
+                       goto return_results;
+               }
+       }
+
        /* begin transaction */
        rc = txn_begin( bdb->bi_dbenv, NULL, &ltid, 0 );
        if( rc != 0 ) {
@@ -64,6 +73,8 @@ bdb_add(
                text = "internal error";
                goto return_results;
        }
+
+       op->o_private = ltid;
        
        /*
         * Get the parent dn and see if the corresponding entry exists.
@@ -76,13 +87,23 @@ bdb_add(
                Entry *matched = NULL;
 
                /* get parent with reader lock */
-               p = dn2entry_r( be, ltid, pdn, &matched );
+               rc = dn2entry_r( be, ltid, pdn, &p, &matched );
+               ch_free( pdn );
+
+               switch( rc ) {
+               case DB_LOCK_DEADLOCK:
+               case DB_LOCK_NOTGRANTED:
+                       goto retry;
+               default:
+                       rc = LDAP_OTHER;
+                       text = "internal error";
+                       goto return_results;
+               }
+
                if ( p == NULL ) {
                        char *matched_dn;
                        struct berval **refs;
 
-                       ch_free( pdn );
-
                        if ( matched != NULL ) {
                                matched_dn = ch_strdup( matched->e_dn );
                                refs = is_entry_referral( matched )
@@ -109,8 +130,6 @@ bdb_add(
                        goto done;
                }
 
-               ch_free(pdn);
-
                if ( ! access_allowed( be, conn, op, p,
                        children, NULL, ACL_WRITE ) )
                {
@@ -148,6 +167,10 @@ bdb_add(
                        goto done;
                }
 
+               /* free parent and writer lock */
+               bdb_entry_return( be, p );
+               p = NULL;
+
        } else {
                if( pdn != NULL ) {
                        free(pdn);
@@ -172,9 +195,15 @@ bdb_add(
        if ( rc != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "bdb_add: dn2id_add failed: %s (%d)\n",
                        db_strerror(rc), rc, 0 );
-               if( rc == DB_KEYEXIST ) {
+
+               switch( rc ) {
+               case DB_LOCK_DEADLOCK:
+               case DB_LOCK_NOTGRANTED:
+                       goto retry;
+               case DB_KEYEXIST:
                        rc = LDAP_ALREADY_EXISTS;
-               } else {
+                       break;
+               default:
                        rc = LDAP_OTHER;
                }
                goto return_results;
@@ -203,6 +232,7 @@ bdb_add(
 
        rc = txn_commit( ltid, 0 );
        ltid = NULL;
+       op->o_private = NULL;
 
        if( rc == 0 ) {
                Debug( LDAP_DEBUG_TRACE,
@@ -220,8 +250,7 @@ bdb_add(
 
 return_results:
        send_ldap_result( conn, op, rc,
-                       NULL, text, NULL, NULL );
-
+               NULL, text, NULL, NULL );
 
 done:
        if (p != NULL) {
@@ -231,6 +260,7 @@ done:
 
        if( ltid != NULL ) {
                txn_abort( ltid );
+               op->o_private = NULL;
        }
 
        return rc;
index 06361d7530cd0ea2cd37e519877c7cd92e87e1a9..4abaa3f651b069f5cfb29548eb1968847f2092bd 100644 (file)
@@ -16,8 +16,8 @@
 LDAP_BEGIN_DECL
 
 #define BDB_IDL_SIZE   (1<<16)
-#define BDB_IDL_MAX            (BDB_IDL_SIZE-16)
-#define BDB_IDL_ALLOC  (BDB_IDL_MAX * sizeof(ID))
+#define BDB_IDL_MAX            (BDB_IDL_SIZE-32)
+/* #define BDB_IDL_ALLOC       (BDB_IDL_SIZE * sizeof(ID)) */
 
 #define BDB_IS_ALLIDS(ids)     ((ids)[0] == NOID)
 
index da06c6bec62383fc2d9c7f3ad8e84e0e3485168f..7a92a3532e3bff835ebdac6b653a4d50b5a55e5e 100644 (file)
@@ -135,6 +135,10 @@ SOURCE=".\back-bdb.h"
 # End Source File
 # Begin Source File
 
+SOURCE=.\delete.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\dn2id.c
 # End Source File
 # Begin Source File
diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c
new file mode 100644 (file)
index 0000000..a399301
--- /dev/null
@@ -0,0 +1,238 @@
+/* delete.c - ldbm backend delete routine */
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
+ * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+
+#include "back-bdb.h"
+
+int
+bdb_delete(
+    Backend    *be,
+    Connection *conn,
+    Operation  *op,
+    const char *dn,
+    const char *ndn
+)
+{
+       struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+       Entry   *matched;
+       char    *pdn = NULL;
+       Entry   *e, *p = NULL;
+       int     rc;
+       const char *text = NULL;
+       int             manageDSAit = get_manageDSAit( op );
+       AttributeDescription *children = slap_schema.si_ad_children;
+       DB_TXN          *ltid = NULL;
+
+       Debug(LDAP_DEBUG_ARGS, "==> bdb_delete: %s\n", dn, 0, 0);
+
+       if (0) {
+retry: rc = txn_abort( ltid );
+               ltid = NULL;
+               op->o_private = NULL;
+               if( rc != 0 ) {
+                       rc = LDAP_OTHER;
+                       text = "internal error";
+                       goto return_results;
+               }
+       }
+
+       /* begin transaction */
+       rc = txn_begin( bdb->bi_dbenv, NULL, &ltid, 0 );
+       if( rc != 0 ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "bdb_delete: txn_begin failed: %s (%d)\n",
+                       db_strerror(rc), rc, 0 );
+               rc = LDAP_OTHER;
+               text = "internal error";
+               goto return_results;
+       }
+
+       op->o_private = ltid;
+
+       pdn = dn_parent( be, e->e_ndn );
+
+       if( pdn != NULL && *pdn != '\0' ) {
+               /* get parent with reader lock */
+               rc = dn2entry_r( be, ltid, pdn, &p, NULL );
+
+               ch_free( pdn );
+
+               switch( rc ) {
+               case DB_LOCK_DEADLOCK:
+               case DB_LOCK_NOTGRANTED:
+                       goto retry;
+               default:
+                       rc = LDAP_OTHER;
+                       text = "internal error";
+                       goto return_results;
+               }
+
+               if( p == NULL) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- bdb_delete: parent does not exist\n",
+                               0, 0, 0);
+                       rc = LDAP_OTHER;
+                       text = "could not locate parent of entry";
+                       goto return_results;
+               }
+
+               /* check parent for "children" acl */
+               rc = access_allowed( be, conn, op, p,
+                       children, NULL, ACL_WRITE );
+
+               bdb_entry_return( be, p );
+
+               if ( !rc  ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- bdb_delete: no access to parent\n",
+                               0, 0, 0 );
+                       rc = LDAP_INSUFFICIENT_ACCESS;
+                       goto return_results;
+               }
+
+       } else {
+               ch_free( pdn );
+
+               /* no parent, must be root to delete */
+               if( ! be_isroot( be, op->o_ndn ) ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<=- bdb_delete: no parent and not root\n",
+                               0, 0, 0);
+                       rc = LDAP_INSUFFICIENT_ACCESS;
+                       goto return_results;
+               }
+       }
+
+       /* get entry */
+       rc = dn2entry_w( be, ltid, ndn, &e, &matched );
+
+       switch( rc ) {
+       case DB_LOCK_DEADLOCK:
+       case DB_LOCK_NOTGRANTED:
+               goto retry;
+       default:
+               rc = LDAP_OTHER;
+               text = "internal error";
+               goto return_results;
+       }
+
+       if ( e == NULL ) {
+               char *matched_dn = NULL;
+               struct berval **refs = NULL;
+
+               Debug( LDAP_DEBUG_ARGS,
+                       "<=- bdb_delete: no such object %s\n",
+                       dn, 0, 0);
+
+               if ( matched != NULL ) {
+                       matched_dn = ch_strdup( matched->e_dn );
+                       refs = is_entry_referral( matched )
+                               ? get_entry_referrals( be, conn, op, matched )
+                               : NULL;
+                       bdb_entry_return( be, matched );
+               } else {
+                       refs = default_referral;
+               }
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                       matched_dn, NULL, refs, NULL );
+
+               if ( matched != NULL ) {
+                       ber_bvecfree( refs );
+                       free( matched_dn );
+               }
+
+               rc = -1;
+               goto done;
+       }
+
+    if ( !manageDSAit && is_entry_referral( e ) ) {
+               /* parent is a referral, don't allow add */
+               /* parent is an alias, don't allow add */
+               struct berval **refs = get_entry_referrals( be,
+                       conn, op, e );
+
+               Debug( LDAP_DEBUG_TRACE,
+                       "bdb_delete: entry is referral\n",
+                       0, 0, 0 );
+
+               send_ldap_result( conn, op, LDAP_REFERRAL,
+                   e->e_dn, NULL, refs, NULL );
+
+               ber_bvecfree( refs );
+
+               rc = 1;
+               goto done;
+       }
+
+
+       if ( bdb_has_children( be, e ) ) {
+               Debug(LDAP_DEBUG_ARGS,
+                       "<=- bdb_delete: non leaf %s\n",
+                       dn, 0, 0);
+               rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
+               text = "subtree delete not supported";
+               goto return_results;
+       }
+
+       /* delete from dn2id mapping */
+       if ( bdb_dn2id_delete( be, e->e_ndn, e->e_id ) != 0 ) {
+               Debug(LDAP_DEBUG_ARGS,
+                       "<=- ldbm_back_delete: operations error %s\n",
+                       dn, 0, 0);
+               rc = LDAP_OTHER;
+               text = "DN index delete failed";
+               goto return_results;
+       }
+
+       /* delete from disk and cache */
+       if ( bdb_id2entry_delete( be, e ) != 0 ) {
+               Debug(LDAP_DEBUG_ARGS,
+                       "<=- bdb_delete: operations error %s\n",
+                       dn, 0, 0);
+               rc = LDAP_OTHER;
+               text = "entry delete failed";
+               goto return_results;
+       }
+
+       rc = txn_commit( ltid, 0 );
+       ltid = NULL;
+       op->o_private = NULL;
+
+       if( rc == 0 ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "bdb_add: txn_commit failed: %s (%d)\n",
+                       db_strerror(rc), rc, 0 );
+               rc = LDAP_OTHER;
+               text = "commit failed";
+       } else {
+               Debug( LDAP_DEBUG_TRACE,
+                       "bdb_add: added id=%08x dn=\"%s\"\n",
+                       e->e_id, e->e_dn, 0 );
+               rc = LDAP_SUCCESS;
+               text = NULL;
+       }
+
+return_results:
+       send_ldap_result( conn, op, LDAP_SUCCESS,
+               NULL, text, NULL, NULL );
+
+done:
+       /* free entry and writer lock */
+       bdb_entry_return( be, e );
+
+       if( ltid != NULL ) {
+               txn_abort( ltid );
+               op->o_private = NULL;
+       }
+
+       return rc;
+}
index 1e0f0b6d7b841668ab2228d55049e6c8083d13da..36b1541bd456daf06aea4d13f8723c8becac71d8 100644 (file)
@@ -64,7 +64,7 @@ bdb_dn2id_add(
                }
        }
 
-       if ( rc != -1 ) {
+       {
                char **subtree = dn_subtree( NULL, dn );
 
                if( subtree != NULL ) {
@@ -89,7 +89,7 @@ bdb_dn2id_add(
 done:
        ch_free( key.data );
        Debug( LDAP_DEBUG_TRACE, "<= bdb_index_dn_add %d\n", rc, 0, 0 );
-       return( rc );
+       return rc;
 }
 
 #if 0
@@ -314,5 +314,4 @@ dn2entry_rw(
 
        return NULL;
 }
-
 #endif
\ No newline at end of file
index c7f2d9d4e2cbefffbf64954019b8df10c7937c66..024660ac9f099a4f68f683a825bf56d2b16036ff 100644 (file)
@@ -33,6 +33,11 @@ static int
 bdb_open( BackendInfo *bi )
 {
        /* initialize the underlying database system */
+
+       int db_env_set_func_malloc( ch_malloc );
+       int db_env_set_func_realloc( ch_realloc );
+       int db_env_set_func_free( ch_free );
+       int db_env_set_func_yield( ldap_pvt_thread_yield );
        return 0;
 }
 
index 68f87b3fd9fd636c5178176b90f5d1f5698d8605..dbbbfb26332883c6c1c99c19e6810c04a423368c 100644 (file)
@@ -21,11 +21,6 @@ int bdb_next_id( BackendDB *be, DB_TXN *tid, ID *out )
        DBT key, data;
        DB_TXN  *ltid;
 
-       rc = txn_begin( bdb->bi_dbenv, tid, &ltid, 0 );
-       if( rc != 0 ) {
-               return rc;
-       }
-
        DBTzero( &key );
        key.data = (char *) &kid;
        key.size = sizeof( kid );
@@ -35,36 +30,66 @@ int bdb_next_id( BackendDB *be, DB_TXN *tid, ID *out )
        data.ulen = sizeof( id );
        data.flags = DB_DBT_USERMEM;
 
-       /* get exiting value (with write lock) */
+       if( 0 ) {
+retry: if( tid != NULL ) {
+                       /* nested transaction, abort and return */
+                       (void) txn_abort( ltid );
+                       return rc;
+               }
+               rc = txn_abort( ltid );
+               if( rc != 0 ) {
+                       return rc;
+               }
+       }
+
+       rc = txn_begin( bdb->bi_dbenv, tid, &ltid, 0 );
+       if( rc != 0 ) {
+               return rc;
+       }
+
+       /* get existing value for read/modify/write */
        rc = bdb->bi_nextid->bdi_db->get( bdb->bi_nextid->bdi_db,
                ltid, &key, &data, DB_RMW );
 
-       if( rc == DB_NOTFOUND ) {
-               /* must be first add */
+       switch(rc) {
+       case DB_LOCK_DEADLOCK:
+       case DB_LOCK_NOTGRANTED:
+               goto retry;
+
+       case DB_NOTFOUND:
                id = NOID;
+               break;
 
-       } else if( rc != 0 ) {
-               goto done;
+       case 0:
+               if ( data.size != sizeof(ID) ) {
+                       /* size mismatch! */
+                       rc = -1;
+                       goto done;
+               }
+               break;
 
-       } else if ( data.size != sizeof(ID) ) {
-               /* size mismatch! */
-               rc = -1;
+       default:
                goto done;
        }
 
        id++;
 
-       /* store new value */
+       /* put new value */
        rc = bdb->bi_nextid->bdi_db->put( bdb->bi_nextid->bdi_db,
                ltid, &key, &data, 0 );
 
-       *out = id;
+       switch(rc) {
+       case DB_LOCK_DEADLOCK:
+       case DB_LOCK_NOTGRANTED:
+               goto retry;
 
-done:
-       if( rc != 0 ) {
-               (void) txn_abort( ltid );
-       } else {
+       case 0:
+               *out = id;
                rc = txn_commit( ltid, 0 );
+               break;
+
+       default:
+done:  (void) txn_abort( ltid );
        }
 
        return rc;
index 1992fe6ed0fa3934a136577a8717cb559177e3a4..c896ec9ed2f07dd15e2e8f984497a8b6f41e90b0 100644 (file)
@@ -34,11 +34,11 @@ int bdb_dn2id_add(
        const char *dn,
        ID id );
 
-Entry * bdb_dn2entry_rw LDAP_P(( Backend *be, DB_TXN *tid,
-       const char *dn, Entry **matched, int rw ));
+int bdb_dn2entry_rw LDAP_P(( Backend *be, DB_TXN *tid,
+       const char *dn, Entry **e, Entry **matched, int rw ));
 
-#define dn2entry_r(be, tid, dn, m) bdb_dn2entry_rw((be), (tid), (dn), (m), 0)
-#define dn2entry_w(be, tid, dn, m) bdb_dn2entry_rw((be), (tid), (dn), (m), 1)
+#define dn2entry_r(be, tid, dn, p, m) bdb_dn2entry_rw((be), (tid), (dn), (p), (m), 0)
+#define dn2entry_w(be, tid, dn, p, m) bdb_dn2entry_rw((be), (tid), (dn), (p), (m), 1)
 
 /*
  * entry.c