Commit 19deaedb authored by Howard Chu's avatar Howard Chu
Browse files

ITS#5262 fixes from HEAD

parent 23a0a9ea
......@@ -83,7 +83,7 @@ typedef struct bdb_entry_info {
* to avoid conflicting with BDB's internal locks. So add a byte here
* that is always zero.
*/
char bei_lockpad;
short bei_lockpad;
short bei_state;
#define CACHE_ENTRY_DELETED 1
......
......@@ -252,6 +252,8 @@ bdb_entryinfo_add_internal(
ei->bei_rdn.bv_val = NULL;
#endif
} else {
int rc;
bdb->bi_cache.c_eiused++;
ber_dupbv( &ei2->bei_nrdn, &ei->bei_nrdn );
......@@ -261,8 +263,13 @@ bdb_entryinfo_add_internal(
*/
if ( ei->bei_parent->bei_kids || !ei->bei_parent->bei_id )
bdb->bi_cache.c_leaves++;
avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp,
rc = avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp,
avl_dup_error );
if ( rc ) {
/* This should never happen; entry cache is corrupt */
bdb->bi_dbenv->log_flush( bdb->bi_dbenv, NULL );
assert( !rc );
}
#ifdef BDB_HIER
ei->bei_parent->bei_ckids++;
#endif
......@@ -281,7 +288,7 @@ bdb_entryinfo_add_internal(
int
bdb_cache_find_ndn(
Operation *op,
DB_TXN *txn,
u_int32_t locker,
struct berval *ndn,
EntryInfo **res )
{
......@@ -318,6 +325,7 @@ bdb_cache_find_ndn(
ei.bei_parent = eip;
ei2 = (EntryInfo *)avl_find( eip->bei_kids, &ei, bdb_rdn_cmp );
if ( !ei2 ) {
DB_LOCK lock;
int len = ei.bei_nrdn.bv_len;
if ( BER_BVISEMPTY( ndn )) {
......@@ -329,9 +337,11 @@ bdb_cache_find_ndn(
(ei.bei_nrdn.bv_val - ndn->bv_val);
bdb_cache_entryinfo_unlock( eip );
rc = bdb_dn2id( op, txn, &ei.bei_nrdn, &ei );
lock.mode = DB_LOCK_NG;
rc = bdb_dn2id( op, &ei.bei_nrdn, &ei, locker, &lock );
if (rc) {
bdb_cache_entryinfo_lock( eip );
bdb_cache_entry_db_unlock( bdb->bi_dbenv, &lock );
*res = eip;
return rc;
}
......@@ -341,6 +351,7 @@ bdb_cache_find_ndn(
rc = bdb_entryinfo_add_internal( bdb, &ei, &ei2 );
/* add_internal left eip and c_rwlock locked */
ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock );
bdb_cache_entry_db_unlock( bdb->bi_dbenv, &lock );
if ( rc ) {
*res = eip;
return rc;
......@@ -384,7 +395,6 @@ bdb_cache_find_ndn(
int
hdb_cache_find_parent(
Operation *op,
DB_TXN *txn,
u_int32_t locker,
ID id,
EntryInfo **res )
......@@ -399,7 +409,7 @@ hdb_cache_find_parent(
ei.bei_ckids = 0;
for (;;) {
rc = hdb_dn2id_parent( op, txn, locker, &ei, &eip.bei_id );
rc = hdb_dn2id_parent( op, locker, &ei, &eip.bei_id );
if ( rc ) break;
/* Save the previous node, if any */
......@@ -703,7 +713,7 @@ again: ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock );
#ifndef BDB_HIER
rc = bdb_id2entry( op->o_bd, tid, locker, id, &ep );
if ( rc == 0 ) {
rc = bdb_cache_find_ndn( op, tid,
rc = bdb_cache_find_ndn( op, locker,
&ep->e_nname, eip );
if ( *eip ) islocked = 1;
if ( rc ) {
......@@ -717,7 +727,7 @@ again: ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock );
}
}
#else
rc = hdb_cache_find_parent(op, tid, locker, id, eip );
rc = hdb_cache_find_parent(op, locker, id, eip );
if ( rc == 0 ) islocked = 1;
#endif
}
......
......@@ -45,7 +45,7 @@ bdb_dn2entry(
*e = NULL;
rc = bdb_cache_find_ndn( op, tid, dn, &ei );
rc = bdb_cache_find_ndn( op, locker, dn, &ei );
if ( rc ) {
if ( matched && rc == DB_NOTFOUND ) {
/* Set the return value, whether we have its entry
......
......@@ -23,6 +23,29 @@
#include "idl.h"
#include "lutil.h"
#define bdb_dn2id_lock BDB_SYMBOL(dn2id_lock)
static int
bdb_dn2id_lock( struct bdb_info *bdb, struct berval *dn,
int rw, u_int32_t locker, DB_LOCK *lock )
{
int rc;
DBT lockobj;
int db_rw;
if (rw)
db_rw = DB_LOCK_WRITE;
else
db_rw = DB_LOCK_READ;
lockobj.data = dn->bv_val;
lockobj.size = dn->bv_len;
rc = LOCK_GET(bdb->bi_dbenv, locker, DB_LOCK_NOWAIT,
&lockobj, db_rw, lock);
return rc;
}
#ifndef BDB_HIER
int
bdb_dn2id_add(
......@@ -39,8 +62,8 @@ bdb_dn2id_add(
char *buf;
struct berval ptr, pdn;
Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add( \"%s\", 0x%08lx )\n",
e->e_ndn, (long) e->e_id, 0 );
Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add 0x%lx: \"%s\"\n",
e->e_id, e->e_ndn, 0 );
assert( e->e_id != NOID );
DBTzero( &key );
......@@ -63,8 +86,8 @@ bdb_dn2id_add(
/* store it -- don't override */
rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add: put failed: %s %d\n",
db_strerror(rc), rc, 0 );
Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add 0x%lx: put failed: %s %d\n",
e->e_id, db_strerror(rc), rc );
goto done;
}
......@@ -76,8 +99,8 @@ bdb_dn2id_add(
rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_dn2id_add: subtree (%s) put failed: %d\n",
ptr.bv_val, rc, 0 );
"=> bdb_dn2id_add 0x%lx: subtree (%s) put failed: %d\n",
e->e_id, ptr.bv_val, rc );
goto done;
}
......@@ -97,8 +120,8 @@ bdb_dn2id_add(
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_dn2id_add: parent (%s) insert failed: %d\n",
ptr.bv_val, rc, 0 );
"=> bdb_dn2id_add 0x%lx: parent (%s) insert failed: %d\n",
e->e_id, ptr.bv_val, rc );
goto done;
}
}
......@@ -115,8 +138,8 @@ bdb_dn2id_add(
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_dn2id_add: subtree (%s) insert failed: %d\n",
ptr.bv_val, rc, 0 );
"=> bdb_dn2id_add 0x%lx: subtree (%s) insert failed: %d\n",
e->e_id, ptr.bv_val, rc );
break;
}
#ifdef BDB_MULTIPLE_SUFFIXES
......@@ -133,7 +156,7 @@ bdb_dn2id_add(
done:
op->o_tmpfree( buf, op->o_tmpmemctx );
Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add: %d\n", rc, 0, 0 );
Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 );
return rc;
}
......@@ -146,13 +169,14 @@ bdb_dn2id_delete(
{
struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
DB *db = bdb->bi_dn2id->bdi_db;
int rc;
DBT key;
char *buf;
DBT key;
DB_LOCK lock;
struct berval pdn, ptr;
int rc;
Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete( \"%s\", 0x%08lx )\n",
e->e_ndn, e->e_id, 0 );
Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete 0x%lx: \"%s\"\n",
e->e_id, e->e_ndn, 0 );
DBTzero( &key );
key.size = e->e_nname.bv_len + 2;
......@@ -165,11 +189,15 @@ bdb_dn2id_delete(
AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len );
ptr.bv_val[ptr.bv_len] = '\0';
/* We hold this lock until the TXN completes */
rc = bdb_dn2id_lock( bdb, &e->e_nname, 1, TXN_ID( txn ), &lock );
if ( rc ) goto done;
/* delete it */
rc = db->del( db, txn, &key, 0 );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete: delete failed: %s %d\n",
db_strerror(rc), rc, 0 );
Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete 0x%lx: delete failed: %s %d\n",
e->e_id, db_strerror(rc), rc );
goto done;
}
......@@ -181,8 +209,8 @@ bdb_dn2id_delete(
rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
ptr.bv_val, rc, 0 );
"=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n",
e->e_id, ptr.bv_val, rc );
goto done;
}
......@@ -202,8 +230,8 @@ bdb_dn2id_delete(
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_dn2id_delete: parent (%s) delete failed: %d\n",
ptr.bv_val, rc, 0 );
"=> bdb_dn2id_delete 0x%lx: parent (%s) delete failed: %d\n",
e->e_id, ptr.bv_val, rc );
goto done;
}
}
......@@ -219,8 +247,8 @@ bdb_dn2id_delete(
rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id );
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY,
"=> bdb_dn2id_delete: subtree (%s) delete failed: %d\n",
ptr.bv_val, rc, 0 );
"=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n",
e->e_id, ptr.bv_val, rc );
goto done;
}
#ifdef BDB_MULTIPLE_SUFFIXES
......@@ -237,24 +265,27 @@ bdb_dn2id_delete(
done:
op->o_tmpfree( buf, op->o_tmpmemctx );
Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete %d\n", rc, 0, 0 );
Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 );
return rc;
}
int
bdb_dn2id(
Operation *op,
DB_TXN *txn,
struct berval *dn,
EntryInfo *ei )
EntryInfo *ei,
u_int32_t locker,
DB_LOCK *lock )
{
struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
DB *db = bdb->bi_dn2id->bdi_db;
DBC *cursor;
int rc;
DBT key, data;
ID nid;
Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id(\"%s\")\n", dn->bv_val, 0, 0 );
DBTzero( &key );
key.size = dn->bv_len + 2;
key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx );
......@@ -267,18 +298,31 @@ bdb_dn2id(
data.ulen = sizeof(ID);
data.flags = DB_DBT_USERMEM;
rc = db->cursor( db, NULL, &cursor, bdb->bi_db_opflags );
if ( rc ) goto leave;
rc = bdb_dn2id_lock( bdb, dn, 0, locker, lock );
if ( rc ) goto nolock;
if ( locker ) {
cursor->locker = locker;
}
/* fetch it */
rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags );
rc = cursor->c_get( cursor, &key, &data, DB_SET );
nolock:
cursor->c_close( cursor );
leave:
if( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n",
db_strerror( rc ), rc, 0 );
} else {
BDB_DISK2ID( &nid, &ei->bei_id );
Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%08lx\n",
Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%lx\n",
ei->bei_id, 0, 0 );
}
op->o_tmpfree( key.data, op->o_tmpmemctx );
return rc;
}
......@@ -404,6 +448,31 @@ typedef struct diskNode {
unsigned char entryID[sizeof(ID)]; /* variable placement */
} diskNode;
/* Sort function for the sorted duplicate data items of a dn2id key.
* Sorts based on normalized RDN, in length order.
*/
int
hdb_dup_compare(
DB *db,
const DBT *usrkey,
const DBT *curkey
)
{
diskNode *un, *cn;
int rc, ul, cl;
un = (diskNode *)usrkey->data;
cn = (diskNode *)curkey->data;
/* data is not aligned, cannot compare directly */
rc = un->nrdnlen[0] - cn->nrdnlen[0];
if ( rc ) return rc;
rc = un->nrdnlen[1] - cn->nrdnlen[1];
if ( rc ) return rc;
return strcmp( un->nrdn, cn->nrdn );
}
/* This function constructs a full DN for a given entry.
*/
int hdb_fix_dn(
......@@ -479,6 +548,9 @@ hdb_dn2id_add(
diskNode *d;
char *ptr;
Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_add 0x%lx: \"%s\"\n",
e->e_id, e->e_ndn, 0 );
nrlen = dn_rdnlen( op->o_bd, &e->e_nname );
if (nrlen) {
rlen = dn_rdnlen( op->o_bd, &e->e_name );
......@@ -545,7 +617,10 @@ hdb_dn2id_add(
bdb_idl_cache_add_id( bdb, db, &key, e->e_id );
}
}
leave:
op->o_tmpfree( d, op->o_tmpmemctx );
Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 );
return rc;
}
......@@ -565,6 +640,10 @@ hdb_dn2id_delete(
int rc;
ID nid;
unsigned char dlen[2];
DB_LOCK lock;
Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_delete 0x%lx: \"%s\"\n",
e->e_id, e->e_ndn, 0 );
DBTzero(&key);
key.size = sizeof(ID);
......@@ -579,8 +658,6 @@ hdb_dn2id_delete(
data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
key.data = &nid;
rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
if ( rc ) return rc;
d = op->o_tmpalloc( data.size, op->o_tmpmemctx );
d->nrdnlen[1] = BEI(e)->bei_nrdn.bv_len & 0xff;
......@@ -590,6 +667,13 @@ hdb_dn2id_delete(
strcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val );
data.data = d;
rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
if ( rc ) goto leave;
/* We hold this lock until the TXN completes */
rc = bdb_dn2id_lock( bdb, &e->e_nname, 1, TXN_ID( txn ), &lock );
if ( rc ) goto nolock;
/* Delete our ID from the parent's list */
rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE );
if ( rc == 0 ) {
......@@ -610,7 +694,10 @@ hdb_dn2id_delete(
if ( rc == 0 )
rc = cursor->c_del( cursor, 0 );
}
nolock:
cursor->c_close( cursor );
leave:
op->o_tmpfree( d, op->o_tmpmemctx );
/* Delete IDL cache entries */
......@@ -628,6 +715,7 @@ hdb_dn2id_delete(
bdb_idl_cache_del_id( bdb, db, &key, e->e_id );
}
}
Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 );
return rc;
}
......@@ -635,9 +723,10 @@ hdb_dn2id_delete(
int
hdb_dn2id(
Operation *op,
DB_TXN *txn,
struct berval *in,
EntryInfo *ei )
EntryInfo *ei,
u_int32_t locker,
DB_LOCK *lock )
{
struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
DB *db = bdb->bi_dn2id->bdi_db;
......@@ -649,6 +738,8 @@ hdb_dn2id(
unsigned char dlen[2];
ID idp, parentID;
Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id(\"%s\")\n", in->bv_val, 0, 0 );
nrlen = dn_rdnlen( op->o_bd, in );
if (!nrlen) nrlen = in->bv_len;
......@@ -666,8 +757,11 @@ hdb_dn2id(
data.dlen = data.ulen;
data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
rc = db->cursor( db, NULL, &cursor, bdb->bi_db_opflags );
if ( rc ) return rc;
if ( locker ) {
cursor->locker = locker;
}
d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx );
d->nrdnlen[1] = nrlen & 0xff;
......@@ -678,6 +772,9 @@ hdb_dn2id(
*ptr = '\0';
data.data = d;
rc = bdb_dn2id_lock( bdb, in, 0, locker, lock );
if ( rc ) goto leave;
rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE );
if ( rc == 0 && (dlen[1] != d->nrdnlen[1] || dlen[0] != d->nrdnlen[0] ||
strncmp( d->nrdn, in->bv_val, nrlen ))) {
......@@ -699,8 +796,17 @@ hdb_dn2id(
ei->bei_parent->bei_dkids = dkids;
}
}
leave:
cursor->c_close( cursor );
op->o_tmpfree( d, op->o_tmpmemctx );
if( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: get failed: %s (%d)\n",
db_strerror( rc ), rc, 0 );
} else {
Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: got id=0x%lx\n",
ei->bei_id, 0, 0 );
}
return rc;
}
......@@ -708,7 +814,6 @@ hdb_dn2id(
int
hdb_dn2id_parent(
Operation *op,
DB_TXN *txn,
u_int32_t locker,
EntryInfo *ei,
ID *idp )
......@@ -732,9 +837,9 @@ hdb_dn2id_parent(
DBTzero(&data);
data.flags = DB_DBT_USERMEM;
rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags );
rc = db->cursor( db, NULL, &cursor, bdb->bi_db_opflags );
if ( rc ) return rc;
if ( !txn && locker ) {
if ( locker ) {
cursor->locker = locker;
}
......
......@@ -381,6 +381,8 @@ shm_retry:
flags |= DB_CREATE;
}
#else
rc = db->bdi_db->set_dup_compare( db->bdi_db,
bdb_dup_compare );
if ( slapMode & (SLAP_TOOL_READONLY|SLAP_TOOL_READMAIN) ) {
flags |= DB_RDONLY;
} else {
......
......@@ -510,7 +510,7 @@ retry: /* transaction retry */
/* Shortcut the search */
nei = neip ? neip : eip;
rs->sr_err = bdb_cache_find_ndn ( op, ltid, &new_ndn, &nei );
rs->sr_err = bdb_cache_find_ndn ( op, locker, &new_ndn, &nei );
if ( nei ) bdb_cache_entryinfo_unlock( nei );
switch( rs->sr_err ) {
case DB_LOCK_DEADLOCK:
......
......@@ -97,9 +97,10 @@ int bdb_dn2entry LDAP_P(( Operation *op, DB_TXN *tid,
int bdb_dn2id(
Operation *op,
DB_TXN *tid,
struct berval *dn,
EntryInfo *ei );
EntryInfo *ei,
u_int32_t locker,
DB_LOCK *lock );
int bdb_dn2id_add(
Operation *op,
......@@ -126,15 +127,20 @@ int bdb_dn2idl(
#ifdef BDB_HIER
#define bdb_dn2id_parent BDB_SYMBOL(dn2id_parent)
#define bdb_dup_compare BDB_SYMBOL(dup_compare)
#define bdb_fix_dn BDB_SYMBOL(fix_dn)
int bdb_dn2id_parent(
Operation *op,
DB_TXN *txn,
u_int32_t locker,
EntryInfo *ei,
ID *idp );
int bdb_dup_compare(
DB *db,
const DBT *usrkey,
const DBT *curkey );
int bdb_fix_dn( Entry *e, int checkit );
#endif
......@@ -506,7 +512,7 @@ int bdb_cache_modify(
);
int bdb_cache_find_ndn(
Operation *op,
DB_TXN *txn,
u_int32_t locker,
struct berval *ndn,
EntryInfo **res
);
......@@ -526,7 +532,6 @@ int bdb_cache_find_id(
int
bdb_cache_find_parent(
Operation *op,
DB_TXN *txn,
u_int32_t locker,
ID id,
EntryInfo **res
......
......@@ -214,7 +214,7 @@ ID bdb_tool_dn2id_get(
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
rc = bdb_cache_find_ndn( &op, NULL, dn, &ei );
rc = bdb_cache_find_ndn( &op, 0, dn, &ei );
if ( ei ) bdb_cache_entryinfo_unlock( ei );
if ( rc == DB_NOTFOUND )
return NOID;
......@@ -280,7 +280,7 @@ Entry* bdb_tool_entry_get( BackendDB *be, ID id )
op.o_tmpmemctx = NULL;
op.o_tmpmfuncs = &ch_mfuncs;
rc = bdb_cache_find_parent( &op, NULL, cursor->locker, id, &ei );
rc = bdb_cache_find_parent( &op, cursor->locker, id, &ei );
if ( rc == LDAP_SUCCESS ) {
bdb_cache_entryinfo_unlock( ei );
e->e_private = ei;
......@@ -312,7 +312,7 @@ static int bdb_tool_next_id(
return 0;
}
rc = bdb_cache_find_ndn( op, tid, &ndn, &ei );
rc = bdb_cache_find_ndn( op, TXN_ID( tid ), &ndn, &ei );
if ( ei ) bdb_cache_entryinfo_unlock( ei );
if ( rc == DB_NOTFOUND ) {
if ( !be_issuffix( op->o_bd, &ndn ) ) {