From: Kurt Zeilenga Date: Sat, 23 Sep 2000 23:15:40 +0000 (+0000) Subject: rough in an add/delete and deadlock avoidance X-Git-Tag: LDBM_PRE_GIANT_RWLOCK~1911 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=68a5db572c3542718121119c71c30b6f69660b3c;p=openldap rough in an add/delete and deadlock avoidance --- diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c index f59e5aad60..3d550a9a2c 100644 --- a/servers/slapd/back-bdb/add.c +++ b/servers/slapd/back-bdb/add.c @@ -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, <id, 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; diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index 06361d7530..4abaa3f651 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -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) diff --git a/servers/slapd/back-bdb/backbdb.dsp b/servers/slapd/back-bdb/backbdb.dsp index da06c6bec6..7a92a3532e 100644 --- a/servers/slapd/back-bdb/backbdb.dsp +++ b/servers/slapd/back-bdb/backbdb.dsp @@ -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 index 0000000000..a399301798 --- /dev/null +++ b/servers/slapd/back-bdb/delete.c @@ -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 +#include + +#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, <id, 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; +} diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c index 1e0f0b6d7b..36b1541bd4 100644 --- a/servers/slapd/back-bdb/dn2id.c +++ b/servers/slapd/back-bdb/dn2id.c @@ -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 diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index c7f2d9d4e2..024660ac9f 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -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; } diff --git a/servers/slapd/back-bdb/nextid.c b/servers/slapd/back-bdb/nextid.c index 68f87b3fd9..dbbbfb2633 100644 --- a/servers/slapd/back-bdb/nextid.c +++ b/servers/slapd/back-bdb/nextid.c @@ -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, <id, 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, <id, 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; diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index 1992fe6ed0..c896ec9ed2 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -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