From 81d986952736b5157ea1622b5be7fe1641a2ead3 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Fri, 16 Jul 2004 21:51:42 +0000 Subject: [PATCH] Changes from HEAD, namely back-bdb updates but also SASL, DN, matchedValues, and misc other fixes --- CHANGES | 7 +- libraries/libldap/cyrus.c | 19 ++- libraries/libldap/getdn.c | 54 ++++++-- libraries/libldap/options.c | 23 +++- libraries/libldap_r/rdwr.c | 42 ++++++- servers/slapd/back-bdb/back-bdb.h | 8 +- servers/slapd/back-bdb/cache.c | 179 ++++++++++++++++++++++----- servers/slapd/back-bdb/config.c | 3 - servers/slapd/back-bdb/ctxcsn.c | 46 +++---- servers/slapd/back-bdb/dn2id.c | 12 -- servers/slapd/back-bdb/id2entry.c | 4 + servers/slapd/back-bdb/idl.c | 15 --- servers/slapd/back-bdb/init.c | 19 ++- servers/slapd/back-bdb/modify.c | 26 ++-- servers/slapd/back-bdb/modrdn.c | 56 ++++----- servers/slapd/back-bdb/operational.c | 12 ++ servers/slapd/back-bdb/proto-bdb.h | 2 - servers/slapd/back-bdb/search.c | 32 +++-- servers/slapd/ctxcsn.c | 2 +- servers/slapd/matchedValues.c | 20 +-- 20 files changed, 383 insertions(+), 198 deletions(-) diff --git a/CHANGES b/CHANGES index a5a6d2abbb..9d1d0482bb 100644 --- a/CHANGES +++ b/CHANGES @@ -6,15 +6,20 @@ OpenLDAP 2.2.15 Engineering Fixed back-bdb ctxcsn locking bug Fixed back-ldap validate/pretty values (ITS#3218) Fixed back-ldap shared connections failover (ITS#3217) + Fixed slapi slapi_int_compute_output_ber attrs bug Fixed slapd oidValidate 0 bug (ITS#3211) Fixed slapd uniqueMember/nameUID bugs (ITS#3210) Fixed slapd operational attribute log message bug (ITS#3205) Fixed slapd invalid cookie in pagedResults control (ITS#3089) Fixed slapd group ACL locking bug (ITS#3173) - Fixed slapi slapi_int_compute_output_ber attrs bug + Fixed slapd abandon/cancel pending bug + Fixed slapd attribute description syntax bug + Fixed libldap SASL re-encode bug Fixed libldap sasl_encode 64-bit bug (ITS#3054,3212) Fixed libldap matchedValues parsing bug (ITS#3208,3216) + Fixed libldap DN '=' handling Fixed libldap_r runqueue bug + Updated libldap_r read/writer locks Build environments Added additional res_query detection for MacOS X Added default ldapi:// SSF build setting diff --git a/libraries/libldap/cyrus.c b/libraries/libldap/cyrus.c index 2c55ce0d21..3eb8480845 100644 --- a/libraries/libldap/cyrus.c +++ b/libraries/libldap/cyrus.c @@ -347,12 +347,12 @@ sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) /* Are there anything left in the buffer? */ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); - if ( ret < 0 ) - return ret; + if ( ret < 0 ) return ret; + /* Still have something left?? */ if ( p->buf_out.buf_ptr != p->buf_out.buf_end ) { errno = EAGAIN; - return 0; + return -1; } } @@ -378,16 +378,16 @@ sb_sasl_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) ber_log_printf( LDAP_DEBUG_ANY, sbiod->sbiod_sb->sb_debug, "sb_sasl_write: failed to encode packet: %s\n", sasl_errstring( ret, NULL, NULL ) ); + errno = EIO; return -1; } p->buf_out.buf_end = p->buf_out.buf_size; ret = ber_pvt_sb_do_write( sbiod, &p->buf_out ); - if ( ret <= 0 ) { - /* caller will retry, so clear this buffer out */ - p->buf_out.buf_ptr = p->buf_out.buf_end; - return ret; - } + + /* return number of bytes encoded, not written, to ensure + * no byte is encoded twice (even if only sent once). + */ return len; } @@ -399,8 +399,7 @@ sb_sasl_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg ) p = (struct sb_sasl_data *)sbiod->sbiod_pvt; if ( opt == LBER_SB_OPT_DATA_READY ) { - if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) - return 1; + if ( p->buf_in.buf_ptr != p->buf_in.buf_end ) return 1; } return LBER_SBIOD_CTRL_NEXT( sbiod, opt, arg ); diff --git a/libraries/libldap/getdn.c b/libraries/libldap/getdn.c index af3b8f0da8..0f68bfdc76 100644 --- a/libraries/libldap/getdn.c +++ b/libraries/libldap/getdn.c @@ -469,6 +469,26 @@ ldap_dn_normalize( LDAP_CONST char *dnin, #define LDAP_DN_ESCAPE(c) ( (c) == '\\' ) #define LDAP_DN_VALUE_END(c) \ ( LDAP_DN_RDN_SEP(c) || LDAP_DN_AVA_SEP(c) ) + +/* NOTE: according to draft-ietf-ldapbis-dn, '=' can be escaped + * and treated as special, i.e. escaped both as "\" and + * as "\=", but it is treated as a regular char, i.e. it can also + * appear as '='. + * + * As such, we currently choose to allow reading unescaped '=', + * but we always produce escaped '\3D'; this may change in the + * future, if compatibility issues do not arise */ +#ifdef LDAP_DEVEL +#define LDAP_DN_NE(c) \ + ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \ + || LDAP_DN_QUOTES(c) \ + || (c) == '<' || (c) == '>' ) +#define LDAP_DN_MAYESCAPE(c) \ + ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \ + || LDAP_DN_AVA_EQUALS(c) \ + || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) ) +#define LDAP_DN_SHOULDESCAPE(c) ( LDAP_DN_AVA_EQUALS(c) ) +#else /* ! LDAP_DEVEL */ #define LDAP_DN_NE(c) \ ( LDAP_DN_RDN_SEP_V2(c) || LDAP_DN_AVA_SEP(c) \ || LDAP_DN_AVA_EQUALS(c) || LDAP_DN_QUOTES(c) \ @@ -476,6 +496,9 @@ ldap_dn_normalize( LDAP_CONST char *dnin, #define LDAP_DN_MAYESCAPE(c) \ ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) \ || LDAP_DN_ASCII_SPACE(c) || LDAP_DN_OCTOTHORPE(c) ) +#define LDAP_DN_SHOULDESCAPE(c) ( 0 ) +#endif /* ! LDAP_DEVEL */ + #define LDAP_DN_NEEDESCAPE(c) \ ( LDAP_DN_ESCAPE(c) || LDAP_DN_NE(c) ) #define LDAP_DN_NEEDESCAPE_LEAD(c) LDAP_DN_MAYESCAPE(c) @@ -730,9 +753,9 @@ ldap_bv2dn_x( struct berval *bv, LDAPDN *dn, unsigned flags, void *ctx ) assert( dn ); #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ARGS, "ldap_bv2dn(%s,%u)\n%s", str, flags, "" ); + LDAP_LOG ( OPERATION, ARGS, "ldap_bv2dn(%s,%u)\n", str, flags, 0 ); #else - Debug( LDAP_DEBUG_TRACE, "=> ldap_bv2dn(%s,%u)\n%s", str, flags, "" ); + Debug( LDAP_DEBUG_TRACE, "=> ldap_bv2dn(%s,%u)\n", str, flags, 0 ); #endif *dn = NULL; @@ -903,10 +926,11 @@ return_result:; } #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, "<= ldap_bv2dn(%s,%u)=%d\n", - str, flags, rc ); + LDAP_LOG ( OPERATION, RESULTS, "<= ldap_bv2dn(%s)=%d %s\n", + str, rc, ldap_err2string( rc ) ); #else - Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s,%u)=%d\n", str, flags, rc ); + Debug( LDAP_DEBUG_TRACE, "<= ldap_bv2dn(%s)=%d %s\n", str, rc, + ldap_err2string( rc ) ); #endif *dn = newDN; @@ -1497,7 +1521,7 @@ str2strval( const char *str, ber_len_t stoplen, struct berval *val, const char * */ return( 1 ); - } else if (!LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) { + } else if ( !LDAP_DN_ASCII_PRINTABLE( p[ 0 ] ) ) { if ( p[ 0 ] == '\0' ) { return( 1 ); } @@ -2082,6 +2106,7 @@ strval2strlen( struct berval *val, unsigned flags, ber_len_t *len ) l += escaped_byte_len * cl; } else if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) + || LDAP_DN_SHOULDESCAPE( p[ 0 ] ) || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) { #ifdef PRETTY_ESCAPE @@ -2172,6 +2197,7 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) #endif #else /* ! PRETTY_ESCAPE */ || LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) + || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) @@ -2192,6 +2218,7 @@ strval2str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) } else { #ifdef PRETTY_ESCAPE if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) + || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( d == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) { str[ d++ ] = '\\'; @@ -2238,6 +2265,7 @@ strval2IA5strlen( struct berval *val, unsigned flags, ber_len_t *len ) } else { for ( l = 0, p = val->bv_val; p[ 0 ]; p++ ) { if ( LDAP_DN_NEEDESCAPE( p[ 0 ] ) + || LDAP_DN_SHOULDESCAPE( p[ 0 ] ) || ( p == val->bv_val && LDAP_DN_NEEDESCAPE_LEAD( p[ 0 ] ) ) || ( !p[ 1 ] && LDAP_DN_NEEDESCAPE_TRAIL( p[ 0 ] ) ) ) { l += 2; @@ -2286,6 +2314,7 @@ strval2IA5str( struct berval *val, char *str, unsigned flags, ber_len_t *len ) for ( s = 0, d = 0, end = val->bv_len - 1; s < val->bv_len; ) { if ( LDAP_DN_NEEDESCAPE( val->bv_val[ s ] ) + || LDAP_DN_SHOULDESCAPE( val->bv_val[ s ] ) || ( s == 0 && LDAP_DN_NEEDESCAPE_LEAD( val->bv_val[ s ] ) ) || ( s == end && LDAP_DN_NEEDESCAPE_TRAIL( val->bv_val[ s ] ) ) ) { str[ d++ ] = '\\'; @@ -3013,10 +3042,9 @@ int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx ) bv->bv_val = NULL; #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ARGS, "=> ldap_dn2bv(%u)\n%s%s", - flags, "", "" ); + LDAP_LOG ( OPERATION, ARGS, "=> ldap_dn2bv(%u)\n", flags, 0, 0 ); #else - Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n%s%s", flags, "", "" ); + Debug( LDAP_DEBUG_TRACE, "=> ldap_dn2bv(%u)\n", flags, 0, 0 ); #endif /* @@ -3327,11 +3355,11 @@ int ldap_dn2bv_x( LDAPDN dn, struct berval *bv, unsigned flags, void *ctx ) } #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, "<= ldap_dn2bv(%s,%u)=%d\n", - bv->bv_val, flags, rc ); + LDAP_LOG ( OPERATION, RESULTS, "<= ldap_dn2bv(%s)=%d %s\n", + bv->bv_val, rc, ldap_err2string( rc ) ); #else - Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s,%u)=%d\n", - bv->bv_val, flags, rc ); + Debug( LDAP_DEBUG_TRACE, "<= ldap_dn2bv(%s)=%d %s\n", + bv->bv_val, rc, ldap_err2string( rc ) ); #endif return_results:; diff --git a/libraries/libldap/options.c b/libraries/libldap/options.c index c8b2ac286a..f191cb8161 100644 --- a/libraries/libldap/options.c +++ b/libraries/libldap/options.c @@ -529,7 +529,6 @@ ldap_set_option( if(urls != NULL) { rc = ldap_url_parselist(&ludlist, urls); - } else if(ld == NULL) { /* * must want global default returned @@ -548,6 +547,28 @@ ldap_set_option( rc = LDAP_NO_MEMORY; } + switch (rc) { + case LDAP_URL_SUCCESS: /* Success */ + rc = LDAP_SUCCESS; + break; + + case LDAP_URL_ERR_MEM: /* can't allocate memory space */ + rc = LDAP_NO_MEMORY; + break; + + case LDAP_URL_ERR_PARAM: /* parameter is bad */ + case LDAP_URL_ERR_BADSCHEME: /* URL doesn't begin with "ldap[si]://" */ + case LDAP_URL_ERR_BADENCLOSURE: /* URL is missing trailing ">" */ + case LDAP_URL_ERR_BADURL: /* URL is bad */ + case LDAP_URL_ERR_BADHOST: /* host port is bad */ + case LDAP_URL_ERR_BADATTRS: /* bad (or missing) attributes */ + case LDAP_URL_ERR_BADSCOPE: /* scope string is invalid (or missing) */ + case LDAP_URL_ERR_BADFILTER: /* bad or missing filter */ + case LDAP_URL_ERR_BADEXTS: /* bad or missing extensions */ + rc = LDAP_PARAM_ERROR; + break; + } + if (rc == LDAP_OPT_SUCCESS) { if (lo->ldo_defludp != NULL) ldap_free_urllist(lo->ldo_defludp); diff --git a/libraries/libldap_r/rdwr.c b/libraries/libldap_r/rdwr.c index dc9dcedc4b..b0613c0751 100644 --- a/libraries/libldap_r/rdwr.c +++ b/libraries/libldap_r/rdwr.c @@ -59,6 +59,12 @@ struct ldap_int_thread_rdwr_s { int ltrw_w_active; int ltrw_r_wait; int ltrw_w_wait; +#ifdef LDAP_RDWR_DEBUG + /* keep track of who has these locks */ +#define MAX_READERS 32 + ldap_pvt_thread_t ltrw_readers[MAX_READERS]; + ldap_pvt_thread_t ltrw_writer; +#endif }; int @@ -162,8 +168,12 @@ int ldap_pvt_thread_rdwr_rlock( ldap_pvt_thread_rdwr_t *rwlock ) assert( rw->ltrw_r_wait >= 0 ); } +#ifdef LDAP_RDWR_DEBUG + rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self(); +#endif rw->ltrw_r_active++; + ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; @@ -194,6 +204,9 @@ int ldap_pvt_thread_rdwr_rtrylock( ldap_pvt_thread_rdwr_t *rwlock ) return LDAP_PVT_THREAD_EBUSY; } +#ifdef LDAP_RDWR_DEBUG + rw->ltrw_readers[rw->ltrw_r_active] = ldap_pvt_thread_self(); +#endif rw->ltrw_r_active++; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); @@ -216,6 +229,22 @@ int ldap_pvt_thread_rdwr_runlock( ldap_pvt_thread_rdwr_t *rwlock ) ldap_pvt_thread_mutex_lock( &rw->ltrw_mutex ); +#ifdef LDAP_RDWR_DEBUG + /* Remove us from the list of readers */ + { int i, j; + ldap_pvt_thread_t self = ldap_pvt_thread_self(); + + for (i=0; iltrw_r_active;i++) + { + if (rw->ltrw_readers[i] == self) { + for (j=i; jltrw_r_active-1; j++) + rw->ltrw_readers[j] = rw->ltrw_readers[j+1]; + rw->ltrw_readers[j] = 0; + break; + } + } + } +#endif rw->ltrw_r_active--; assert( rw->ltrw_w_active >= 0 ); @@ -264,6 +293,9 @@ int ldap_pvt_thread_rdwr_wlock( ldap_pvt_thread_rdwr_t *rwlock ) assert( rw->ltrw_w_wait >= 0 ); } +#ifdef LDAP_RDWR_DEBUG + rw->ltrw_writer = ldap_pvt_thread_self(); +#endif rw->ltrw_w_active++; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); @@ -296,6 +328,9 @@ int ldap_pvt_thread_rdwr_wtrylock( ldap_pvt_thread_rdwr_t *rwlock ) return LDAP_PVT_THREAD_EBUSY; } +#ifdef LDAP_RDWR_DEBUG + rw->ltrw_writer = ldap_pvt_thread_self(); +#endif rw->ltrw_w_active++; ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); @@ -332,6 +367,9 @@ int ldap_pvt_thread_rdwr_wunlock( ldap_pvt_thread_rdwr_t *rwlock ) ldap_pvt_thread_cond_signal( &rw->ltrw_write ); } +#ifdef LDAP_RDWR_DEBUG + rw->ltrw_writer = 0; +#endif ldap_pvt_thread_mutex_unlock( &rw->ltrw_mutex ); return 0; @@ -397,8 +435,8 @@ int ldap_pvt_thread_rdwr_active(ldap_pvt_thread_rdwr_t *rwlock) assert( rw->ltrw_r_active >= 0 ); assert( rw->ltrw_r_wait >= 0 ); - return(ldap_pvt_thread_rdwr_readers(rw) + - ldap_pvt_thread_rdwr_writers(rw)); + return(ldap_pvt_thread_rdwr_readers(rwlock) + + ldap_pvt_thread_rdwr_writers(rwlock)); } #endif /* LDAP_DEBUG */ diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index e3846c9b9b..3dcbc6de96 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -73,10 +73,6 @@ LDAP_BEGIN_DECL /* The minimum we can function with */ #define MINIMUM_SEARCH_STACK_DEPTH 8 -/* for the IDL cache */ -#define SLAP_IDL_CACHE 1 - -#ifdef SLAP_IDL_CACHE typedef struct bdb_idl_cache_entry_s { struct berval kstr; ldap_pvt_thread_rdwr_t idl_entry_rwlock; @@ -85,7 +81,6 @@ typedef struct bdb_idl_cache_entry_s { struct bdb_idl_cache_entry_s* idl_lru_prev; struct bdb_idl_cache_entry_s* idl_lru_next; } bdb_idl_cache_entry_t; -#endif /* BDB backend specific entry info */ typedef struct bdb_entry_info { @@ -103,6 +98,7 @@ typedef struct bdb_entry_info { #define CACHE_ENTRY_NO_KIDS 2 #define CACHE_ENTRY_NOT_LINKED 4 #define CACHE_ENTRY_NO_GRANDKIDS 8 +#define CACHE_ENTRY_LOADING 0x10 /* * remaining fields require backend cache lock to access @@ -180,7 +176,6 @@ struct bdb_info { LDAP_LIST_HEAD(pl, slap_op) bi_psearch_list; ldap_pvt_thread_rdwr_t bi_pslist_rwlock; LDAP_LIST_HEAD(se, slap_session_entry) bi_session_list; -#ifdef SLAP_IDL_CACHE int bi_idl_cache_max_size; int bi_idl_cache_size; Avlnode *bi_idl_tree; @@ -188,7 +183,6 @@ struct bdb_info { bdb_idl_cache_entry_t *bi_idl_lru_tail; ldap_pvt_thread_rdwr_t bi_idl_tree_rwlock; ldap_pvt_thread_mutex_t bi_idl_tree_lrulock; -#endif }; #define bi_id2entry bi_databases[BDB_ID2ENTRY] diff --git a/servers/slapd/back-bdb/cache.c b/servers/slapd/back-bdb/cache.c index 85d4d052d4..d306add2a5 100644 --- a/servers/slapd/back-bdb/cache.c +++ b/servers/slapd/back-bdb/cache.c @@ -31,6 +31,8 @@ static int bdb_cache_delete_internal(Cache *cache, EntryInfo *e); static void bdb_lru_print(Cache *cache); #endif +static int bdb_txn_get( Operation *op, DB_ENV *env, DB_TXN **txn ); + static EntryInfo * bdb_cache_entryinfo_new( Cache *cache ) { @@ -86,7 +88,7 @@ bdb_cache_entry_db_relock( rc = env->lock_vec(env, locker, tryOnly ? DB_LOCK_NOWAIT : 0, list, 2, NULL ); - if (rc) { + if (rc && !tryOnly) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_entry_db_relock: entry %ld, rw %d, rc %d\n", @@ -126,7 +128,7 @@ bdb_cache_entry_db_lock( DB_ENV *env, u_int32_t locker, EntryInfo *ei, rc = LOCK_GET(env, locker, tryOnly ? DB_LOCK_NOWAIT : 0, &lockobj, db_rw, lock); - if (rc) { + if (rc && !tryOnly) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_entry_db_lock: entry %ld, rw %d, rc %d\n", @@ -179,6 +181,7 @@ bdb_cache_entryinfo_destroy( EntryInfo *e ) } else { \ (cache)->c_lrutail = (ei)->bei_lruprev; \ } \ + (ei)->bei_lrunext = (ei)->bei_lruprev = NULL; \ } while(0) #define LRU_ADD( cache, ei ) do { \ @@ -593,7 +596,6 @@ bdb_cache_find_id( Entry *ep = NULL; int rc = 0; EntryInfo ei; - int lru_del = 0; ei.bei_id = id; @@ -655,40 +657,88 @@ again: ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock ); if ( (*eip)->bei_state & CACHE_ENTRY_DELETED ) { rc = DB_NOTFOUND; } else { - rc = bdb_cache_entry_db_lock( bdb->bi_dbenv, locker, *eip, 0, 0, lock ); - /* entry is protected now, we don't need to hold the entryinfo */ + int load = 0; + /* Make sure only one thread tries to load the entry */ +load1: if ( !(*eip)->bei_e && !((*eip)->bei_state & CACHE_ENTRY_LOADING)) { + load = 1; + (*eip)->bei_state |= CACHE_ENTRY_LOADING; + } if ( islocked ) { bdb_cache_entryinfo_unlock( *eip ); islocked = 0; } - if ( rc == 0 ) { - if ( !(*eip)->bei_e ) { - if (!ep) { - rc = bdb_id2entry( op->o_bd, tid, id, &ep ); + rc = bdb_cache_entry_db_lock( bdb->bi_dbenv, locker, *eip, 0, 0, lock ); + if ( (*eip)->bei_state & CACHE_ENTRY_DELETED ) { + rc = DB_NOTFOUND; + bdb_cache_entry_db_unlock( bdb->bi_dbenv, lock ); + } else if ( rc == 0 ) { + if ( load ) { + DB_TXN *ltid; + u_int32_t locker2 = locker; + + /* We don't wrap entire read operations in txn's, but + * we need our cache entry lock and any DB page locks + * to be associated, in order for deadlock detection + * to work properly. So if we need to read from the DB, + * we use a long-lived per-thread txn for this step. + */ + if ( !ep && !tid ) { + rc = bdb_txn_get( op, bdb->bi_dbenv, <id ); + if ( ltid ) + locker2 = TXN_ID( ltid ); + } else { + ltid = tid; } - if ( rc == 0 ) { - bdb_cache_entry_db_relock( bdb->bi_dbenv, locker, + /* Give up original read lock, obtain write lock with + * (possibly) new locker ID. + */ + if ( rc == 0 ) { + rc = bdb_cache_entry_db_relock( bdb->bi_dbenv, locker2, *eip, 1, 0, lock ); - /* Make sure no other modifier beat us to it */ - if ( (*eip)->bei_e ) { - bdb_entry_return( ep ); - ep = NULL; - } else { - ep->e_private = *eip; + } + if ( rc == 0 && !ep) { + rc = bdb_id2entry( op->o_bd, ltid, id, &ep ); + } + if ( rc == 0 ) { + ep->e_private = *eip; #ifdef BDB_HIER - bdb_fix_dn( ep, 0 ); + bdb_fix_dn( ep, 0 ); #endif - (*eip)->bei_e = ep; - } - bdb_cache_entry_db_relock( bdb->bi_dbenv, locker, + (*eip)->bei_e = ep; + ep = NULL; + } + (*eip)->bei_state ^= CACHE_ENTRY_LOADING; + if ( rc == 0 ) { + /* If we succeeded, downgrade back to a readlock. */ + rc = bdb_cache_entry_db_relock( bdb->bi_dbenv, locker, *eip, 0, 0, lock ); + } else { + /* Otherwise, release the lock. */ + bdb_cache_entry_db_unlock( bdb->bi_dbenv, lock ); } - } else { - /* If we had the entry already, this item - * is on the LRU list. + if ( locker2 != locker ) { + /* If we're using the per-thread txn, release all + * of its page locks now. + */ + DB_LOCKREQ list; + list.op = DB_LOCK_PUT_ALL; + list.obj = NULL; + bdb->bi_dbenv->lock_vec( bdb->bi_dbenv, locker2, + 0, &list, 1, NULL ); + } + } else if ( !(*eip)->bei_e ) { + /* Some other thread is trying to load the entry, + * give it a chance to finish. */ - lru_del = 1; + bdb_cache_entry_db_unlock( bdb->bi_dbenv, lock ); + ldap_pvt_thread_yield(); + bdb_cache_entryinfo_lock( *eip ); + islocked = 1; + goto load1; #ifdef BDB_HIER + } else { + /* Check for subtree renames + */ rc = bdb_fix_dn( (*eip)->bei_e, 1 ); if ( rc ) { bdb_cache_entry_db_relock( bdb->bi_dbenv, @@ -705,11 +755,17 @@ again: ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock ); } } } + if ( islocked ) { + bdb_cache_entryinfo_unlock( *eip ); + } + if ( ep ) { + bdb_entry_return( ep ); + } if ( rc == 0 ) { /* set lru mutex */ ldap_pvt_thread_mutex_lock( &bdb->bi_cache.lru_mutex ); - /* if entry is old, remove from old spot on LRU list */ - if ( lru_del ) { + /* if entry is on LRU list, remove from old spot */ + if ( (*eip)->bei_lrunext || (*eip)->bei_lruprev ) { LRU_DELETE( &bdb->bi_cache, *eip ); } else { /* if entry is new, bump cache size */ @@ -719,9 +775,6 @@ again: ldap_pvt_thread_rdwr_rlock( &bdb->bi_cache.c_rwlock ); bdb_cache_lru_add( bdb, locker, *eip ); } - if ( islocked ) { - bdb_cache_entryinfo_unlock( *eip ); - } return rc; } @@ -785,7 +838,10 @@ bdb_cache_add( rc = bdb_entryinfo_add_internal( bdb, &ei, &new ); /* bdb_csn_commit can cause this when adding the database root entry */ - if ( new->bei_e ) bdb_entry_return( new->bei_e ); + if ( new->bei_e ) { + new->bei_e->e_private = NULL; + bdb_entry_return( new->bei_e ); + } new->bei_e = e; e->e_private = new; new->bei_state = CACHE_ENTRY_NO_KIDS | CACHE_ENTRY_NO_GRANDKIDS; @@ -1069,6 +1125,10 @@ bdb_cache_release_all( Cache *cache ) avl_free( cache->c_dntree.bei_kids, NULL ); avl_free( cache->c_idtree, bdb_entryinfo_release ); + for (;cache->c_eifree;cache->c_eifree = cache->c_lruhead) { + cache->c_lruhead = cache->c_eifree->bei_lrunext; + bdb_cache_entryinfo_destroy(cache->c_eifree); + } cache->c_lruhead = NULL; cache->c_lrutail = NULL; @@ -1097,6 +1157,60 @@ bdb_lru_print( Cache *cache ) } #endif +static void +bdb_txn_free( void *key, void *data ) +{ + DB_TXN *txn = data; + TXN_ABORT( txn ); +} + +/* Obtain a long-lived transaction for the current thread */ +static int +bdb_txn_get( Operation *op, DB_ENV *env, DB_TXN **txn ) +{ + int i, rc, lockid; + void *ctx, *data; + + /* If no op was provided, try to find the ctx anyway... */ + if ( op ) { + ctx = op->o_threadctx; + } else { + ctx = ldap_pvt_thread_pool_context(); + } + + /* Shouldn't happen unless we're single-threaded */ + if ( !ctx ) { + *txn = NULL; + return 0; + } + + if ( ldap_pvt_thread_pool_getkey( ctx, ((char *)env)+1, &data, NULL ) ) { + for ( i=0, rc=1; rc != 0 && i<4; i++ ) { + rc = TXN_BEGIN( env, NULL, txn, 0 ); + if (rc) ldap_pvt_thread_yield(); + } + if ( rc != 0) { + return rc; + } + if ( ( rc = ldap_pvt_thread_pool_setkey( ctx, ((char *)env)+1, + *txn, bdb_txn_free ) ) ) { + TXN_ABORT( *txn ); +#ifdef NEW_LOGGING + LDAP_LOG( BACK_BDB, ERR, "bdb_txn_get: err %s(%d)\n", + db_strerror(rc), rc, 0 ); +#else + Debug( LDAP_DEBUG_ANY, "bdb_txn_get: err %s(%d)\n", + db_strerror(rc), rc, 0 ); +#endif + + return rc; + } + } else { + *txn = data; + } + return 0; +} + #ifdef BDB_REUSE_LOCKERS static void bdb_locker_id_free( void *key, void *data ) @@ -1117,10 +1231,9 @@ bdb_locker_id_free( void *key, void *data ) "bdb_locker_id_free: %d err %s(%d)\n", lockid, db_strerror(rc), rc ); #endif - memset( &lr, 0, sizeof(lr) ); - /* release all locks held by this locker. */ lr.op = DB_LOCK_PUT_ALL; + lr.obj = NULL; env->lock_vec( env, lockid, 0, &lr, 1, NULL ); XLOCK_ID_FREE( env, lockid ); } diff --git a/servers/slapd/back-bdb/config.c b/servers/slapd/back-bdb/config.c index 31164d91c7..4d2dbbbaba 100644 --- a/servers/slapd/back-bdb/config.c +++ b/servers/slapd/back-bdb/config.c @@ -172,7 +172,6 @@ bdb_db_config( bdb->bi_search_stack_depth = MINIMUM_SEARCH_STACK_DEPTH; } -#ifdef SLAP_IDL_CACHE /* size of the IDL cache in entries */ } else if ( strcasecmp( argv[0], "idlcachesize" ) == 0 ) { if ( argc < 2 ) { @@ -183,8 +182,6 @@ bdb_db_config( } if ( !( slapMode & SLAP_TOOL_MODE ) ) bdb->bi_idl_cache_max_size = atoi( argv[1] ); -#endif - } else if ( strcasecmp( argv[0], "sessionlog" ) == 0 ) { int se_id = 0, se_size = 0; struct slap_session_entry *sent; diff --git a/servers/slapd/back-bdb/ctxcsn.c b/servers/slapd/back-bdb/ctxcsn.c index 294362430f..7c2b31ec36 100644 --- a/servers/slapd/back-bdb/ctxcsn.c +++ b/servers/slapd/back-bdb/ctxcsn.c @@ -39,7 +39,6 @@ bdb_csn_commit( ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; - struct berval ctxcsn_ndn = BER_BVNULL; EntryInfo *ctxcsn_ei = NULL; DB_LOCK ctxcsn_lock; struct berval max_committed_csn; @@ -51,20 +50,17 @@ bdb_csn_commit( size_t textlen = sizeof textbuf; EntryInfo *eip = NULL; + assert( !BER_BVISNULL( &op->o_bd->be_context_csn ) ); + if ( ei ) { e = ei->bei_e; } - build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], - (struct berval *)&slap_ldapsync_cn_bv, op->o_tmpmemctx ); - - rc = bdb_dn2entry( op, tid, &ctxcsn_ndn, &ctxcsn_ei, + rc = bdb_dn2entry( op, tid, &op->o_bd->be_context_csn, &ctxcsn_ei, 1, locker, &ctxcsn_lock ); *ctxcsn_e = ctxcsn_ei->bei_e; - op->o_tmpfree( ctxcsn_ndn.bv_val, op->o_tmpmemctx ); - slap_get_commit_csn( op, &max_committed_csn ); if ( max_committed_csn.bv_val == NULL ) { @@ -78,7 +74,7 @@ bdb_csn_commit( if ( !*ctxcsn_e ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "context csn not present"; - ch_free( max_committed_csn.bv_val ); + op->o_tmpfree( max_committed_csn.bv_val, op->o_tmpmemctx ); return BDB_CSN_ABORT; } else { Modifications mod; @@ -99,7 +95,7 @@ bdb_csn_commit( dummy = **ctxcsn_e; ret = bdb_modify_internal( op, tid, &mod, &dummy, &rs->sr_text, textbuf, textlen ); - ch_free( max_committed_csn.bv_val ); + op->o_tmpfree( max_committed_csn.bv_val, op->o_tmpmemctx ); if ( ret != LDAP_SUCCESS ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, @@ -158,7 +154,7 @@ bdb_csn_commit( } *ctxcsn_e = slap_create_context_csn_entry( op->o_bd, &max_committed_csn ); - ch_free( max_committed_csn.bv_val ); + op->o_tmpfree( max_committed_csn.bv_val, op->o_tmpmemctx ); (*ctxcsn_e)->e_id = ctxcsn_id; *ctxcsn_added = 1; @@ -245,7 +241,6 @@ bdb_get_commit_csn( ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; - struct berval ctxcsn_ndn = BER_BVNULL; struct berval csn = BER_BVNULL; EntryInfo *ctxcsn_ei = NULL; EntryInfo *suffix_ei = NULL; @@ -264,34 +259,34 @@ bdb_get_commit_csn( if ( op->o_sync_mode != SLAP_SYNC_NONE && !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { char substr[67]; + struct berval ctxcsn_ndn = BER_BVNULL; struct berval bv; LDAP_STAILQ_FOREACH( si, &op->o_bd->be_syncinfo, si_next ) { sprintf( substr, "cn=syncrepl%ld", si->si_rid ); ber_str2bv( substr, 0, 0, &bv ); - build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &bv, NULL ); + build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &bv, op->o_tmpmemctx ); consumer_ctxcsn_retry : rs->sr_err = bdb_dn2entry( op, NULL, &ctxcsn_ndn, &ctxcsn_ei, 0, locker, ctxcsn_lock ); switch(rs->sr_err) { + case DB_LOCK_DEADLOCK: + case DB_LOCK_NOTGRANTED: + goto consumer_ctxcsn_retry; case 0: - ch_free( ctxcsn_ndn.bv_val ); + op->o_tmpfree( ctxcsn_ndn.bv_val, op->o_tmpmemctx ); ctxcsn_ndn.bv_val = NULL; if ( ctxcsn_ei ) { ctxcsn_e = ctxcsn_ei->bei_e; } break; - case LDAP_BUSY: - goto done; - case DB_LOCK_DEADLOCK: - case DB_LOCK_NOTGRANTED: - goto consumer_ctxcsn_retry; case DB_NOTFOUND: - rs->sr_err = LDAP_OTHER; - goto done; default: rs->sr_err = LDAP_OTHER; + case LDAP_BUSY: + op->o_tmpfree( ctxcsn_ndn.bv_val, op->o_tmpmemctx ); + ctxcsn_ndn.bv_val = NULL; goto done; } @@ -333,11 +328,9 @@ consumer_ctxcsn_retry : } } else if ( op->o_sync_mode != SLAP_SYNC_NONE && LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { - build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], - (struct berval *)&slap_ldapsync_cn_bv, NULL ); provider_ctxcsn_retry : - rs->sr_err = bdb_dn2entry( op, NULL, &ctxcsn_ndn, &ctxcsn_ei, + rs->sr_err = bdb_dn2entry( op, NULL, &op->o_bd->be_context_csn, &ctxcsn_ei, 0, locker, ctxcsn_lock ); switch(rs->sr_err) { case 0: @@ -401,10 +394,8 @@ txn_retry: goto done; } - rs->sr_err = bdb_dn2entry( op, NULL, &ctxcsn_ndn, &ctxcsn_ei, + rs->sr_err = bdb_dn2entry( op, NULL, &op->o_bd->be_context_csn, &ctxcsn_ei, 0, ctxcsn_locker, ctxcsn_lock ); - ch_free( ctxcsn_ndn.bv_val ); - ctxcsn_ndn.bv_val = NULL; if ( ctxcsn_ei ) { ctxcsn_e = ctxcsn_ei->bei_e; @@ -437,8 +428,5 @@ done: TXN_ABORT( ltid ); } - if ( ctxcsn_ndn.bv_val != NULL ) - ch_free( ctxcsn_ndn.bv_val ); - return rs->sr_err; } diff --git a/servers/slapd/back-bdb/dn2id.c b/servers/slapd/back-bdb/dn2id.c index 528c57815f..14e94d301d 100644 --- a/servers/slapd/back-bdb/dn2id.c +++ b/servers/slapd/back-bdb/dn2id.c @@ -382,7 +382,6 @@ bdb_dn2id_children( ((char *)key.data)[0] = DN_ONE_PREFIX; AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 ); -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_size ) { rc = bdb_idl_cache_get( bdb, db, &key, NULL ); if ( rc != LDAP_NO_SUCH_OBJECT ) { @@ -390,7 +389,6 @@ bdb_dn2id_children( return rc; } } -#endif /* we actually could do a empty get... */ DBTzero( &data ); data.data = &id; @@ -642,11 +640,9 @@ hdb_dn2id_add( db->put( db, txn, &key, &data, DB_NODUPDATA ); } -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_size ) { bdb_idl_cache_del( bdb, db, &key ); } -#endif data.data = d; data.size = sizeof(diskNode) + rlen + nrlen; data.flags = DB_DBT_USERMEM; @@ -692,11 +688,9 @@ hdb_dn2id_delete( data.dlen = data.size; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_size ) { bdb_idl_cache_del( bdb, db, &key ); } -#endif rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; @@ -863,14 +857,12 @@ hdb_dn2id_children( key.data = &e->e_id; key.flags = DB_DBT_USERMEM; -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_size ) { rc = bdb_idl_cache_get( bdb, db, &key, NULL ); if ( rc != LDAP_NO_SUCH_OBJECT ) { return rc; } } -#endif DBTzero(&data); data.data = &d; data.ulen = sizeof(d); @@ -938,7 +930,6 @@ hdb_dn2idl_internal( struct dn2id_cookie *cx ) { -#ifdef SLAP_IDL_CACHE if ( cx->bdb->bi_idl_cache_size ) { cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp); if ( cx->rc == DB_NOTFOUND ) { @@ -948,7 +939,6 @@ hdb_dn2idl_internal( goto gotit; } } -#endif BDB_IDL_ZERO( cx->tmp ); if ( !cx->ei ) { @@ -1044,11 +1034,9 @@ hdb_dn2idl_internal( } saveit: -#ifdef SLAP_IDL_CACHE if ( cx->bdb->bi_idl_cache_max_size ) { bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc ); } -#endif ; gotit: if ( !BDB_IDL_IS_ZERO( cx->tmp )) { diff --git a/servers/slapd/back-bdb/id2entry.c b/servers/slapd/back-bdb/id2entry.c index fce1fcdc63..d4eb267111 100644 --- a/servers/slapd/back-bdb/id2entry.c +++ b/servers/slapd/back-bdb/id2entry.c @@ -202,6 +202,10 @@ int bdb_entry_release( SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */ if ( slapMode == SLAP_SERVER_MODE ) { + /* If not in our cache, just free it */ + if ( !e->e_private ) { + return bdb_entry_return( e ); + } /* free entry and reader or writer lock */ if ( o ) { boi = (struct bdb_op_info *)o->o_private; diff --git a/servers/slapd/back-bdb/idl.c b/servers/slapd/back-bdb/idl.c index d6a29083d6..a7980a3f7a 100644 --- a/servers/slapd/back-bdb/idl.c +++ b/servers/slapd/back-bdb/idl.c @@ -27,7 +27,6 @@ #define IDL_CMP(x,y) ( x < y ? -1 : ( x > y ? 1 : 0 ) ) -#ifdef SLAP_IDL_CACHE #define IDL_LRU_DELETE( bdb, e ) do { \ if ( e->idl_lru_prev != NULL ) { \ e->idl_lru_prev->idl_lru_next = e->idl_lru_next; \ @@ -63,7 +62,6 @@ bdb_idl_entry_cmp( const void *v_idl1, const void *v_idl2 ) if ((rc = idl1->kstr.bv_len - idl2->kstr.bv_len )) return rc; return ( memcmp ( idl1->kstr.bv_val, idl2->kstr.bv_val , idl1->kstr.bv_len ) ); } -#endif #if IDL_DEBUG > 0 static void idl_check( ID *ids ) @@ -304,8 +302,6 @@ bdb_show_key( } } -#ifdef SLAP_IDL_CACHE - /* Find a db/key pair in the IDL cache. If ids is non-NULL, * copy the cached IDL into it, otherwise just return the status. */ @@ -444,7 +440,6 @@ bdb_idl_cache_del( } ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock ); } -#endif int bdb_idl_fetch_key( @@ -495,12 +490,10 @@ bdb_idl_fetch_key( assert( ids != NULL ); -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_size ) { rc = bdb_idl_cache_get( bdb, db, key, ids ); if ( rc != LDAP_NO_SUCH_OBJECT ) return rc; } -#endif DBTzero( &data ); @@ -576,9 +569,7 @@ bdb_idl_fetch_key( } if( rc == DB_NOTFOUND ) { -#ifndef SLAP_IDL_CACHE return rc; -#endif } else if( rc != 0 ) { #ifdef NEW_LOGGING @@ -619,11 +610,9 @@ bdb_idl_fetch_key( return -1; } -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_put( bdb, db, key, ids, rc ); } -#endif return rc; } @@ -659,11 +648,9 @@ bdb_idl_insert_key( assert( id != NOID ); -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_size ) { bdb_idl_cache_del( bdb, db, key ); } -#endif DBTzero( &data ); data.size = sizeof( ID ); @@ -856,11 +843,9 @@ bdb_idl_delete_key( } assert( id != NOID ); -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_del( bdb, db, key ); } -#endif DBTzero( &data ); data.data = &tmp; diff --git a/servers/slapd/back-bdb/init.c b/servers/slapd/back-bdb/init.c index 9742b9ca24..e9f616c602 100644 --- a/servers/slapd/back-bdb/init.c +++ b/servers/slapd/back-bdb/init.c @@ -71,8 +71,8 @@ bdb_db_init( BackendDB *be ) LDAP_LOG( BACK_BDB, ENTRY, "bdb_db_init", 0, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, - "bdb_db_init: Initializing BDB database\n", - 0, 0, 0 ); + "bdb_db_init: Initializing %s database\n", + be->bd_info->bi_type, 0, 0 ); #endif /* allocate backend-database-specific stuff */ @@ -196,14 +196,15 @@ bdb_db_open( BackendDB *be ) bdb->bi_dbenv->set_errcall( bdb->bi_dbenv, bdb_errcall ); bdb->bi_dbenv->set_lk_detect( bdb->bi_dbenv, bdb->bi_lock_detect ); -#ifdef SLAP_IDL_CACHE + /* One long-lived TXN per thread, two TXNs per write op */ + bdb->bi_dbenv->set_tx_max( bdb->bi_dbenv, connection_pool_max * 3 ); + if ( bdb->bi_idl_cache_max_size ) { bdb->bi_idl_tree = NULL; ldap_pvt_thread_rdwr_init( &bdb->bi_idl_tree_rwlock ); ldap_pvt_thread_mutex_init( &bdb->bi_idl_tree_lrulock ); bdb->bi_idl_cache_size = 0; } -#endif #ifdef BDB_SUBDIRS { @@ -447,7 +448,7 @@ bdb_db_open( BackendDB *be ) return rc; } - bdb->bi_dbenv->lock_id(bdb->bi_dbenv, &bdb->bi_cache.c_locker); + XLOCK_ID(bdb->bi_dbenv, &bdb->bi_cache.c_locker); /* open (and create) index databases */ return 0; @@ -459,9 +460,7 @@ bdb_db_close( BackendDB *be ) int rc; struct bdb_info *bdb = (struct bdb_info *) be->be_private; struct bdb_db_info *db; -#ifdef SLAP_IDL_CACHE bdb_idl_cache_entry_t *entry, *next_entry; -#endif while( bdb->bi_ndatabases-- ) { db = bdb->bi_databases[bdb->bi_ndatabases]; @@ -476,7 +475,6 @@ bdb_db_close( BackendDB *be ) bdb_cache_release_all (&bdb->bi_cache); -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { ldap_pvt_thread_rdwr_wlock ( &bdb->bi_idl_tree_rwlock ); avl_free( bdb->bi_idl_tree, NULL ); @@ -491,7 +489,8 @@ bdb_db_close( BackendDB *be ) } ldap_pvt_thread_rdwr_wunlock ( &bdb->bi_idl_tree_rwlock ); } -#endif + + XLOCK_ID_FREE(bdb->bi_dbenv, bdb->bi_cache.c_locker); return 0; } @@ -542,12 +541,10 @@ bdb_db_destroy( BackendDB *be ) ldap_pvt_thread_rdwr_destroy ( &bdb->bi_pslist_rwlock ); ldap_pvt_thread_mutex_destroy( &bdb->bi_lastid_mutex ); ldap_pvt_thread_mutex_destroy( &bdb->bi_database_mutex ); -#ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { ldap_pvt_thread_rdwr_destroy( &bdb->bi_idl_tree_rwlock ); ldap_pvt_thread_mutex_destroy( &bdb->bi_idl_tree_lrulock ); } -#endif ch_free( bdb ); be->be_private = NULL; diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c index ce0195e35d..45d2efeb11 100644 --- a/servers/slapd/back-bdb/modify.c +++ b/servers/slapd/back-bdb/modify.c @@ -266,6 +266,10 @@ int bdb_modify_internal( rc = entry_schema_check( op->o_bd, e, save_attrs, text, textbuf, textlen ); if ( rc != LDAP_SUCCESS || op->o_noop ) { attrs_free( e->e_attrs ); + /* clear the indexing flags */ + for ( ap = save_attrs; ap != NULL; ap = ap->a_next ) { + ap->a_flags = 0; + } e->e_attrs = save_attrs; if ( rc != LDAP_SUCCESS ) { @@ -349,7 +353,7 @@ bdb_modify( Operation *op, SlapReply *rs ) size_t textlen = sizeof textbuf; DB_TXN *ltid = NULL, *lt2; struct bdb_op_info opinfo; - Entry dummy; + Entry dummy = {0}; u_int32_t locker = 0; DB_LOCK lock; @@ -380,6 +384,10 @@ bdb_modify( Operation *op, SlapReply *rs ) if( 0 ) { retry: /* transaction retry */ + if ( dummy.e_attrs ) { + attrs_free( dummy.e_attrs ); + dummy.e_attrs = NULL; + } if( e != NULL ) { bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); e = NULL; @@ -615,11 +623,11 @@ retry: /* transaction retry */ if ( (rs->sr_err == LDAP_INSUFFICIENT_ACCESS) && opinfo.boi_err ) { rs->sr_err = opinfo.boi_err; } + /* Only free attrs if they were dup'd. */ + if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: - attrs_free( dummy.e_attrs ); - dummy.e_attrs = NULL; goto retry; } goto return_results; @@ -639,8 +647,6 @@ retry: /* transaction retry */ switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: - attrs_free( dummy.e_attrs ); - dummy.e_attrs = NULL; goto retry; } rs->sr_text = "entry update failed"; @@ -660,8 +666,6 @@ retry: /* transaction retry */ case BDB_CSN_ABORT : goto return_results; case BDB_CSN_RETRY : - attrs_free( dummy.e_attrs ); - dummy.e_attrs = NULL; goto retry; } } @@ -671,7 +675,7 @@ retry: /* transaction retry */ postread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } - if( slap_read_controls( op, rs, e, + if( slap_read_controls( op, rs, &dummy, &slap_post_read_bv, postread_ctrl ) ) { #ifdef NEW_LOGGING @@ -697,10 +701,9 @@ retry: /* transaction retry */ switch( rc ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: - attrs_free( dummy.e_attrs ); - dummy.e_attrs = NULL; goto retry; } + dummy.e_attrs = NULL; if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { if ( ctxcsn_added ) { @@ -788,6 +791,9 @@ retry: /* transaction retry */ if( num_ctrls ) rs->sr_ctrls = ctrls; return_results: + if( dummy.e_attrs ) { + attrs_free( dummy.e_attrs ); + } send_ldap_result( op, rs ); if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) { diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c index 8d29504e7c..0956d8cdfd 100644 --- a/servers/slapd/back-bdb/modrdn.c +++ b/servers/slapd/back-bdb/modrdn.c @@ -41,7 +41,7 @@ bdb_modrdn( Operation *op, SlapReply *rs ) size_t textlen = sizeof textbuf; DB_TXN *ltid = NULL, *lt2; struct bdb_op_info opinfo; - Entry dummy, *save; + Entry dummy = {0}; ID id; @@ -89,6 +89,10 @@ bdb_modrdn( Operation *op, SlapReply *rs ) if( 0 ) { retry: /* transaction retry */ + if ( dummy.e_attrs ) { + attrs_free( dummy.e_attrs ); + dummy.e_attrs = NULL; + } if (e != NULL) { bdb_unlocked_cache_return_entry_w(&bdb->bi_cache, e); e = NULL; @@ -829,11 +833,7 @@ retry: /* transaction retry */ goto return_results; } - dummy = *e; - save = e; - e = &dummy; - - /* delete old one */ + /* delete old DN */ rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e ); if ( rs->sr_err != 0 ) { #ifdef NEW_LOGGING @@ -855,24 +855,14 @@ retry: /* transaction retry */ goto return_results; } - /* Binary format uses a single contiguous block, cannot - * free individual fields. But if a previous modrdn has - * already happened, must free the names. The frees are - * done in bdb_cache_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 ) - { - e->e_name.bv_val = NULL; - e->e_nname.bv_val = NULL; - } - e->e_name = new_dn; - e->e_nname = new_ndn; - new_dn.bv_val = NULL; - new_ndn.bv_val = NULL; + /* copy the entry, then override some fields */ + dummy = *e; + dummy.e_name = new_dn; + dummy.e_nname = new_ndn; + dummy.e_attrs = NULL; - /* add new one */ - rs->sr_err = bdb_dn2id_add( op, lt2, neip ? neip : eip, e ); + /* add new DN */ + rs->sr_err = bdb_dn2id_add( op, lt2, neip ? neip : eip, &dummy ); if ( rs->sr_err != 0 ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, @@ -893,10 +883,12 @@ retry: /* transaction retry */ goto return_results; } + dummy.e_attrs = e->e_attrs; + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop && !op->o_no_psearch ) { ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock ); LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { - rc = bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY ); + rc = bdb_psearch( op, rs, ps_list, &dummy, LDAP_PSEARCH_BY_PREMODIFY ); if ( rc ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, @@ -912,8 +904,9 @@ retry: /* transaction retry */ ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock ); } + /* modify entry */ - rs->sr_err = bdb_modify_internal( op, lt2, &mod[0], e, + rs->sr_err = bdb_modify_internal( op, lt2, &mod[0], &dummy, &rs->sr_text, textbuf, textlen ); if( rs->sr_err != LDAP_SUCCESS ) { #ifdef NEW_LOGGING @@ -928,6 +921,7 @@ retry: /* transaction retry */ if ( ( rs->sr_err == LDAP_INSUFFICIENT_ACCESS ) && opinfo.boi_err ) { rs->sr_err = opinfo.boi_err; } + if ( dummy.e_attrs == e->e_attrs ) dummy.e_attrs = NULL; switch( rs->sr_err ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: @@ -937,7 +931,7 @@ retry: /* transaction retry */ } /* id2entry index */ - rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, e ); + rs->sr_err = bdb_id2entry_update( op->o_bd, lt2, &dummy ); if ( rs->sr_err != 0 ) { #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, ERR, @@ -1010,7 +1004,7 @@ retry: /* transaction retry */ postread_ctrl = &ctrls[num_ctrls++]; ctrls[num_ctrls] = NULL; } - if( slap_read_controls( op, rs, e, + if( slap_read_controls( op, rs, &dummy, &slap_post_read_bv, postread_ctrl ) ) { #ifdef NEW_LOGGING @@ -1033,13 +1027,16 @@ retry: /* transaction retry */ } } else { - rc = bdb_cache_modrdn( save, &op->orr_nnewrdn, e, neip, + rc = bdb_cache_modrdn( e, &op->orr_nnewrdn, &dummy, neip, bdb->bi_dbenv, locker, &lock ); switch( rc ) { case DB_LOCK_DEADLOCK: case DB_LOCK_NOTGRANTED: goto retry; } + dummy.e_attrs = NULL; + new_dn.bv_val = NULL; + new_ndn.bv_val = NULL; if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { if ( ctxcsn_added ) { @@ -1126,6 +1123,9 @@ retry: /* transaction retry */ if( num_ctrls ) rs->sr_ctrls = ctrls; return_results: + if ( dummy.e_attrs ) { + attrs_free( dummy.e_attrs ); + } send_ldap_result( op, rs ); if( rs->sr_err == LDAP_SUCCESS && bdb->bi_txn_cp ) { diff --git a/servers/slapd/back-bdb/operational.c b/servers/slapd/back-bdb/operational.c index 5250470803..c239908eac 100644 --- a/servers/slapd/back-bdb/operational.c +++ b/servers/slapd/back-bdb/operational.c @@ -39,7 +39,19 @@ bdb_hasSubordinates( assert( e ); + /* NOTE: this should never happen, but it actually happens + * when using back-relay; until we find a better way to + * preserve entry's private information while rewriting it, + * let's disable the hasSubordinate feature for back-relay. + */ + if ( BEI( e ) == NULL ) { + return LDAP_OTHER; + } + retry: + /* FIXME: we can no longer assume the entry's e_private + * field is correctly populated; so we need to reacquire + * it with reader lock */ rc = bdb_cache_children( op, NULL, e ); switch( rc ) { diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index 40a9f5a867..ccdb1aa505 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -203,7 +203,6 @@ BI_entry_get_rw bdb_entry_get; /* * idl.c */ -#ifdef SLAP_IDL_CACHE #define bdb_idl_cache_get BDB_SYMBOL(idl_cache_get) #define bdb_idl_cache_put BDB_SYMBOL(idl_cache_put) @@ -228,7 +227,6 @@ bdb_idl_cache_del( struct bdb_info *bdb, DB *db, DBT *key ); -#endif #define bdb_idl_first BDB_SYMBOL(idl_first) #define bdb_idl_next BDB_SYMBOL(idl_next) diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 31a8776796..5090c695f0 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -149,7 +149,7 @@ static int search_aliases( ID cursora, ida, cursoro, ido, *subscop2; Entry *matched, *a; EntryInfo *ei; - struct berval bv_alias = { sizeof("alias")-1, "alias" }; + struct berval bv_alias = BER_BVC( "alias" ); AttributeAssertion aa_alias; Filter af; DB_LOCK locka, lockr; @@ -215,9 +215,12 @@ static int search_aliases( ida = bdb_idl_next(curscop, &cursora)) { ei = NULL; +retry1: rs->sr_err = bdb_cache_find_id(op, NULL, ida, &ei, 0, locker, &lockr ); if (rs->sr_err != LDAP_SUCCESS) { + if ( rs->sr_err == DB_LOCK_DEADLOCK || + rs->sr_err == DB_LOCK_NOTGRANTED ) goto retry1; continue; } a = ei->bei_e; @@ -281,9 +284,15 @@ nextido: * Set the name so that the scope's IDL can be retrieved. */ ei = NULL; +sameido: rs->sr_err = bdb_cache_find_id(op, NULL, ido, &ei, 0, locker, &locka ); - if ( rs->sr_err != LDAP_SUCCESS ) goto nextido; + if ( rs->sr_err != LDAP_SUCCESS ) { + if ( rs->sr_err == DB_LOCK_DEADLOCK || + rs->sr_err == DB_LOCK_NOTGRANTED ) + goto sameido; + goto nextido; + } e = ei->bei_e; } return rs->sr_err; @@ -495,8 +504,7 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, null_attr.an_desc = NULL; null_attr.an_oc = NULL; null_attr.an_oc_exclude = 0; - null_attr.an_name.bv_len = 0; - null_attr.an_name.bv_val = NULL; + BER_BVZERO( &null_attr.an_name ); for( num_ctrls = 0; num_ctrls < SLAP_MAX_RESPONSE_CONTROLS; num_ctrls++ ) { ctrls[num_ctrls] = NULL; @@ -508,8 +516,7 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, attrs[0].an_desc = NULL; attrs[0].an_oc = NULL; attrs[0].an_oc_exclude = 0; - attrs[0].an_name.bv_len = 0; - attrs[0].an_name.bv_val = NULL; + BER_BVZERO( &attrs[0].an_name ); } manageDSAit = get_manageDSAit( sop ); @@ -546,8 +553,8 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, ei_root.bei_parent = &ei_root; e_root.e_private = &ei_root; e_root.e_id = 0; - e_root.e_nname.bv_val=""; - e_root.e_name.bv_val=""; + BER_BVSTR( &e_root.e_nname, "" ); + BER_BVSTR( &e_root.e_name, "" ); ei = &ei_root; rs->sr_err = LDAP_SUCCESS; } else { @@ -1641,7 +1648,7 @@ static int search_candidates( { if( !get_manageDSAit(op) && !get_domainScope(op) ) { /* match referral objects */ - struct berval bv_ref = { sizeof("referral")-1, "referral" }; + struct berval bv_ref = BER_BVC( "referral" ); rf.f_choice = LDAP_FILTER_EQUALITY; rf.f_ava = &aa_ref; rf.f_av_desc = slap_schema.si_ad_objectClass; @@ -1665,7 +1672,7 @@ static int search_candidates( #ifdef BDB_SUBENTRIES if( get_subentries_visibility( op ) ) { - struct berval bv_subentry = { sizeof("SUBENTRY")-1, "SUBENTRY" }; + struct berval bv_subentry = BER_BVC( "SUBENTRY" ); sf.f_choice = LDAP_FILTER_EQUALITY; sf.f_ava = &aa_subentry; sf.f_av_desc = slap_schema.si_ad_objectClass; @@ -1748,7 +1755,7 @@ send_paged_response( lastid ? *lastid : 0, rs->sr_nentries, NULL ); #endif - ctrl.ldctl_value.bv_val = NULL; + BER_BVZERO( &ctrl.ldctl_value ); ctrls[0] = &ctrl; ctrls[1] = NULL; @@ -1761,8 +1768,7 @@ send_paged_response( } else { respcookie = ( PagedResultsCookie )0; - cookie.bv_val = ""; - cookie.bv_len = 0; + BER_BVSTR( &cookie, "" ); } op->o_conn->c_pagedresults_state.ps_cookie = respcookie; diff --git a/servers/slapd/ctxcsn.c b/servers/slapd/ctxcsn.c index 4672273293..c978ae90cf 100644 --- a/servers/slapd/ctxcsn.c +++ b/servers/slapd/ctxcsn.c @@ -53,7 +53,7 @@ slap_get_commit_csn( Operation *op, struct berval *csn ) if ( csne->ce_state == SLAP_CSN_PENDING ) break; } - if ( committed_csne ) ber_dupbv( csn, committed_csne->ce_csn ); + if ( committed_csne ) ber_dupbv_x( csn, committed_csne->ce_csn, op->o_tmpmemctx ); ldap_pvt_thread_mutex_unlock( &op->o_bd->be_pcl_mutex ); } diff --git a/servers/slapd/matchedValues.c b/servers/slapd/matchedValues.c index b8a8e61c45..eb8aa71c3c 100644 --- a/servers/slapd/matchedValues.c +++ b/servers/slapd/matchedValues.c @@ -339,39 +339,44 @@ test_mra_vrFilter( int i, j; for ( i=0; a != NULL; a = a->a_next, i++ ) { - struct berval *bv, value; + struct berval *bv, assertedValue; if ( mra->ma_desc ) { if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) { continue; } - value = mra->ma_value; + assertedValue = mra->ma_value; } else { int rc; const char *text = NULL; /* check if matching is appropriate */ - if ( strcmp( mra->ma_rule->smr_syntax->ssyn_oid, - a->a_desc->ad_type->sat_syntax->ssyn_oid ) != 0 ) { + if ( !mr_usable_with_at( mra->ma_rule, a->a_desc->ad_type ) ) { continue; } rc = asserted_value_validate_normalize( a->a_desc, mra->ma_rule, SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX, - &mra->ma_value, &value, &text, op->o_tmpmemctx ); + &mra->ma_value, &assertedValue, &text, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) continue; } - bv = a->a_nvals; + /* check match */ + if (mra->ma_rule == a->a_desc->ad_type->sat_equality) { + bv = a->a_nvals; + } else { + bv = a->a_vals; + } + for ( j = 0; bv->bv_val != NULL; bv++, j++ ) { int ret; int rc; const char *text; rc = value_match( &ret, a->a_desc, mra->ma_rule, 0, - bv, &value, &text ); + bv, &assertedValue, &text ); if( rc != LDAP_SUCCESS ) { return rc; } @@ -384,3 +389,4 @@ test_mra_vrFilter( return LDAP_SUCCESS; } + -- 2.39.5