This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.3.6
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.6 by this push:
new f071f26 BZ1518320 - entry cache crash fix
f071f26 is described below
commit f071f260be70fe0ddb568e19fdf25f9c95b4ddad
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Thu Jun 20 15:50:08 2019 -0400
BZ1518320 - entry cache crash fix
Description: THis patch is combination of all the entry cache fixes.
If these fixes are not enough, there is an experimental
"fix" that should prevent the crash. A message will be
logged that reports the crash was averted:
"(avoided crash, but cache was corrupted)"
The customer should monitor the errors log for this text,
and let GSS know if they see it.
---
configure.ac | 2 +-
dirsrvtests/tests/suites/betxns/betxn_test.py | 57 ++++++++++
ldap/servers/slapd/back-ldbm/back-ldbm.h | 4 +
ldap/servers/slapd/back-ldbm/backentry.c | 2 +-
ldap/servers/slapd/back-ldbm/cache.c | 147 ++++++++++++++++++++++++-
ldap/servers/slapd/back-ldbm/ldbm_add.c | 14 +++
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 22 +++-
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 12 ++
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 24 +++-
ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 1 +
ldap/servers/slapd/slapi-plugin.h | 15 +++
ldap/servers/slapd/time.c | 26 +++++
12 files changed, 313 insertions(+), 13 deletions(-)
diff --git a/configure.ac b/configure.ac
index 17831a6..ee9dc01 100644
--- a/configure.ac
+++ b/configure.ac
@@ -70,7 +70,7 @@ AC_FUNC_STAT
AC_FUNC_STRERROR_R
AC_FUNC_STRFTIME
AC_FUNC_VPRINTF
-AC_CHECK_FUNCS([clock_gettime endpwent ftruncate getcwd gethostbyname inet_ntoa
localtime_r memmove memset mkdir munmap putenv rmdir setrlimit socket strcasecmp strchr
strcspn strdup strerror strncasecmp strpbrk strrchr strstr strtol tzset])
+AC_CHECK_FUNCS([endpwent ftruncate getcwd gethostbyname inet_ntoa localtime_r memmove
memset mkdir munmap putenv rmdir setrlimit socket strcasecmp strchr strcspn strdup
strerror strncasecmp strpbrk strrchr strstr strtol tzset])
# This will detect if we need to add the LIBADD_DL value for us.
LT_LIB_DLLOAD
diff --git a/dirsrvtests/tests/suites/betxns/betxn_test.py
b/dirsrvtests/tests/suites/betxns/betxn_test.py
index ed8acbf..0f3d767 100644
--- a/dirsrvtests/tests/suites/betxns/betxn_test.py
+++ b/dirsrvtests/tests/suites/betxns/betxn_test.py
@@ -8,6 +8,7 @@
#
import pytest
import six
+import ldap
from lib389.tasks import *
from lib389.utils import *
from lib389.topologies import topology_st
@@ -195,6 +196,62 @@ def test_betxn_memberof(topology_st):
log.info('test_betxn_memberof: PASSED')
+def test_betxn_modrdn_memberof(topology_st):
+ """Test modrdn operartions and memberOf
+
+ :id: 70d0b96e-b693-4bf7-bbf5-102a66ac5994
+
+ :setup: Standalone instance
+
+ :steps: 1. Enable and configure memberOf plugin
+ 2. Set memberofgroupattr="member" and
memberofAutoAddOC="nsContainer"
+ 3. Create group and user outside of memberOf plugin scope
+ 4. Do modrdn to move group into scope
+ 5. Do modrdn to move group into scope (again)
+
+ :expectedresults:
+ 1. memberOf plugin plugin should be ON
+ 2. Set memberofgroupattr="member" and
memberofAutoAddOC="nsContainer" should PASS
+ 3. Creating group and user should PASS
+ 4. Modrdn should fail with objectclass violation
+ 5. Second modrdn should also fail with objectclass violation
+ """
+
+ peoplebase = 'ou=people,%s' % DEFAULT_SUFFIX
+ memberof = MemberOfPlugin(topology_st.standalone)
+ memberof.enable()
+ memberof.set_autoaddoc('nsContainer') # Bad OC
+ memberof.set('memberOfEntryScope', peoplebase)
+ memberof.set('memberOfAllBackends', 'on')
+ topology_st.standalone.restart()
+
+ groups = Groups(topology_st.standalone, DEFAULT_SUFFIX)
+ group = groups.create(properties={
+ 'cn': 'group',
+ })
+
+ # Create user and add it to group
+ users = UserAccounts(topology_st.standalone, basedn=DEFAULT_SUFFIX)
+ user = users.create(properties=TEST_USER_PROPERTIES)
+ if not ds_is_older('1.3.7'):
+ user.remove('objectClass', 'nsMemberOf')
+
+ group.add_member(user.dn)
+
+ # Attempt modrdn that should fail, but the original entry should stay in the cache
+ with pytest.raises(ldap.OBJECTCLASS_VIOLATION):
+ group.rename('cn=group_to_people', newsuperior=peoplebase)
+
+ # Should fail, but not with NO_SUCH_OBJECT as the original entry should still be in
the cache
+ with pytest.raises(ldap.OBJECTCLASS_VIOLATION):
+ group.rename('cn=group_to_people', newsuperior=peoplebase)
+
+ #
+ # Done
+ #
+ log.info('test_betxn_modrdn_memberof: PASSED')
+
+
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h
b/ldap/servers/slapd/back-ldbm/back-ldbm.h
index 0bb15e3..9e2819a 100644
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
@@ -303,8 +303,10 @@ struct backcommon {
#define ENTRY_STATE_DELETED 0x1 /* entry is marked as deleted */
#define ENTRY_STATE_CREATING 0x2 /* entry is being created; don't touch it */
#define ENTRY_STATE_NOTINCACHE 0x4 /* cache_add failed; not in the cache */
+#define ENTRY_STATE_INVALID 0x8 /* cache entry is invalid and needs to be removed */
int ep_refcnt; /* entry reference cnt */
size_t ep_size; /* for cache tracking */
+ struct timespec ep_create_time; /* the time the entry was added to the cache */
};
/* From ep_type through ep_size MUST be identical to backcommon */
@@ -316,6 +318,7 @@ struct backentry {
char ep_state; /* state in the cache */
int ep_refcnt; /* entry reference cnt */
size_t ep_size; /* for cache tracking */
+ struct timespec ep_create_time; /* the time the entry was added to the cache */
Slapi_Entry *ep_entry; /* real entry */
Slapi_Entry *ep_vlventry;
void * ep_dn_link; /* linkage for the 3 hash */
@@ -333,6 +336,7 @@ struct backdn {
char ep_state; /* state in the cache; share ENTRY_STATE_* */
int ep_refcnt; /* entry reference cnt */
size_t ep_size; /* for cache tracking */
+ struct timespec ep_create_time; /* the time the entry was added to the cache */
Slapi_DN *dn_sdn;
void *dn_id_link; /* for hash table */
};
diff --git a/ldap/servers/slapd/back-ldbm/backentry.c
b/ldap/servers/slapd/back-ldbm/backentry.c
index 844df58..8b76d91 100644
--- a/ldap/servers/slapd/back-ldbm/backentry.c
+++ b/ldap/servers/slapd/back-ldbm/backentry.c
@@ -23,7 +23,7 @@ backentry_free( struct backentry **bep )
return;
}
ep = *bep;
- PR_ASSERT(ep->ep_state & (ENTRY_STATE_DELETED|ENTRY_STATE_NOTINCACHE));
+ PR_ASSERT(ep->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_NOTINCACHE |
ENTRY_STATE_INVALID));
if ( ep->ep_entry != NULL ) {
slapi_entry_free( ep->ep_entry );
}
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
index 3e40eec..24f7795 100644
--- a/ldap/servers/slapd/back-ldbm/cache.c
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -55,6 +55,11 @@
#define LOG(...)
#endif
+typedef enum {
+ ENTRY_CACHE,
+ DN_CACHE,
+} CacheType;
+
#define LRU_DETACH(cache, e) lru_detach((cache), (void *)(e))
#define CACHE_LRU_HEAD(cache, type) ((type)((cache)->c_lruhead))
@@ -180,6 +185,7 @@ Hashtable *new_hash(u_long size, u_long offset, HashFn hfn,
int add_hash(Hashtable *ht, void *key, size_t keylen, void *entry,
void **alt)
{
+ struct backcommon *back_entry = (struct backcommon *)entry;
u_long val, slot;
void *e;
@@ -197,6 +203,7 @@ int add_hash(Hashtable *ht, void *key, size_t keylen, void *entry,
e = HASH_NEXT(ht, e);
}
/* ok, it's not already there, so add it */
+ back_entry->ep_create_time = slapi_current_rel_time_hr();
HASH_NEXT(ht, entry) = ht->slot[slot];
ht->slot[slot] = entry;
return 1;
@@ -487,6 +494,126 @@ static void cache_make_hashes(struct cache *cache, int type)
}
}
+/*
+ * Helper function for flush_hash() to calculate if the entry should be
+ * removed from the cache.
+ */
+static int32_t
+flush_remove_entry(struct timespec *entry_time, struct timespec *start_time)
+{
+ struct timespec diff;
+
+ slapi_timespec_diff(entry_time, start_time, &diff);
+ if (diff.tv_sec >= 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Flush all the cache entries that were added after the "start time"
+ * This is called when a backend transaction plugin fails, and we need
+ * to remove all the possible invalid entries in the cache.
+ *
+ * If the ref count is 0, we can straight up remove it from the cache, but
+ * if the ref count is greater than 1, then the entry is currently in use.
+ * In the later case we set the entry state to ENTRY_STATE_INVALID, and
+ * when the owning thread cache_returns() the cache entry is automatically
+ * removed so another thread can not use/lock the invalid cache entry.
+ */
+static void
+flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
+{
+ Hashtable *ht = cache->c_idtable; /* start with the ID table as it's in both
ENTRY and DN caches */
+ void *e, *laste = NULL;
+
+ cache_lock(cache);
+
+ for (size_t i = 0; i < ht->size; i++) {
+ e = ht->slot[i];
+ while (e) {
+ struct backcommon *entry = (struct backcommon *)e;
+ uint64_t remove_it = 0;
+ if (flush_remove_entry(&entry->ep_create_time, start_time)) {
+ /* Mark the entry to be removed */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash", "[%s]
Removing entry id (%d)\n",
+ type ? "DN CACHE" : "ENTRY CACHE",
entry->ep_id);
+ remove_it = 1;
+ }
+ laste = e;
+ e = HASH_NEXT(ht, e);
+
+ if (remove_it) {
+ /* since we have the cache lock we know we can trust refcnt */
+ entry->ep_state |= ENTRY_STATE_INVALID;
+ if (entry->ep_refcnt == 0) {
+ entry->ep_refcnt++;
+ lru_delete(cache, laste);
+ if (type == ENTRY_CACHE) {
+ entrycache_remove_int(cache, laste);
+ entrycache_return(cache, (struct backentry **)&laste);
+ } else {
+ dncache_remove_int(cache, laste);
+ dncache_return(cache, (struct backdn **)&laste);
+ }
+ } else {
+ /* Entry flagged for removal */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash",
+ "[%s] Flagging entry to be removed later: id (%d)
refcnt: %d\n",
+ type ? "DN CACHE" : "ENTRY CACHE",
entry->ep_id, entry->ep_refcnt);
+ }
+ }
+ }
+ }
+
+ if (type == ENTRY_CACHE) {
+ /* Also check the DN hashtable */
+ ht = cache->c_dntable;
+
+ for (size_t i = 0; i < ht->size; i++) {
+ e = ht->slot[i];
+ while (e) {
+ struct backcommon *entry = (struct backcommon *)e;
+ uint64_t remove_it = 0;
+ if (flush_remove_entry(&entry->ep_create_time, start_time)) {
+ /* Mark the entry to be removed */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash", "[ENTRY
CACHE] Removing entry id (%d)\n",
+ entry->ep_id);
+ remove_it = 1;
+ }
+ laste = e;
+ e = HASH_NEXT(ht, e);
+
+ if (remove_it) {
+ /* since we have the cache lock we know we can trust refcnt */
+ entry->ep_state |= ENTRY_STATE_INVALID;
+ if (entry->ep_refcnt == 0) {
+ entry->ep_refcnt++;
+ lru_delete(cache, laste);
+ entrycache_remove_int(cache, laste);
+ entrycache_return(cache, (struct backentry **)&laste);
+ } else {
+ /* Entry flagged for removal */
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash",
+ "[ENTRY CACHE] Flagging entry to be removed later:
id (%d) refcnt: %d\n",
+ entry->ep_id, entry->ep_refcnt);
+ }
+ }
+ }
+ }
+ }
+
+ cache_unlock(cache);
+}
+
+void
+revert_cache(ldbm_instance *inst, struct timespec *start_time)
+{
+ flush_hash(&inst->inst_cache, start_time, ENTRY_CACHE);
+ flush_hash(&inst->inst_dncache, start_time, DN_CACHE);
+}
+
/* initialize the cache */
int cache_init(struct cache *cache, size_t maxsize, long maxentries, int type)
{
@@ -1139,7 +1266,7 @@ entrycache_return(struct cache *cache, struct backentry **bep)
{
ASSERT(e->ep_refcnt > 0);
if (! --e->ep_refcnt) {
- if (e->ep_state & ENTRY_STATE_DELETED) {
+ if (e->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_INVALID)) {
const char* ndn = slapi_sdn_get_ndn(backentry_get_sdn(e));
if (ndn){
/*
@@ -1151,6 +1278,13 @@ entrycache_return(struct cache *cache, struct backentry **bep)
LOG("entrycache_return -Failed to remove %s from dn
table\n", ndn);
}
}
+ if (e->ep_state & ENTRY_STATE_INVALID) {
+ /* Remove it from the hash table before we free the back entry */
+ slapi_log_err(SLAPI_LOG_CACHE, "entrycache_return",
+ "Finally flushing invalid entry: %d (%s)\n",
+ e->ep_id, backentry_get_ndn(e));
+ entrycache_remove_int(cache, e);
+ }
backentry_free(bep);
} else {
lru_add(cache, e);
@@ -1540,7 +1674,7 @@ int cache_lock_entry(struct cache *cache, struct backentry *e)
/* make sure entry hasn't been deleted now */
cache_lock(cache);
- if (e->ep_state & (ENTRY_STATE_DELETED|ENTRY_STATE_NOTINCACHE)) {
+ if (e->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_NOTINCACHE |
ENTRY_STATE_INVALID)) {
cache_unlock(cache);
PR_ExitMonitor(e->ep_mutexp);
LOG("<= cache_lock_entry (DELETED)\n");
@@ -1708,7 +1842,14 @@ dncache_return(struct cache *cache, struct backdn **bdn)
{
ASSERT((*bdn)->ep_refcnt > 0);
if (! --(*bdn)->ep_refcnt) {
- if ((*bdn)->ep_state & ENTRY_STATE_DELETED) {
+ if ((*bdn)->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_INVALID)) {
+ if ((*bdn)->ep_state & ENTRY_STATE_INVALID) {
+ /* Remove it from the hash table before we free the back dn */
+ slapi_log_err(SLAPI_LOG_CACHE, "dncache_return",
+ "Finally flushing invalid entry: %d (%s)\n",
+ (*bdn)->ep_id, slapi_sdn_get_dn((*bdn)->dn_sdn));
+ dncache_remove_int(cache, (*bdn));
+ }
backdn_free(bdn);
} else {
lru_add(cache, (void *)*bdn);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c
b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index 8acaaeb..0e6d496 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -94,6 +94,9 @@ ldbm_back_add( Slapi_PBlock *pb )
PRUint64 conn_id;
int op_id;
int result_sent = 0;
+ int32_t parent_op = 0;
+ struct timespec parent_time;
+
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
conn_id = 0; /* connection is NULL */
}
@@ -131,6 +134,13 @@ ldbm_back_add( Slapi_PBlock *pb )
slapi_entry_delete_values( e, numsubordinates, NULL );
dblayer_txn_init(li,&txn);
+
+ if (txn.back_txn_txn == NULL) {
+ /* This is the parent operation, get the time */
+ parent_op = 1;
+ parent_time = slapi_current_rel_time_hr();
+ }
+
/* the calls to perform searches require the parent txn if any
so set txn to the parent_txn until we begin the child transaction */
if (parent_txn) {
@@ -1194,6 +1204,10 @@ ldbm_back_add( Slapi_PBlock *pb )
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
if ( addingentry_id_assigned )
{
next_id_return( be, addingentry->ep_id );
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index cfc18b0..8368cf3 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -79,6 +79,8 @@ ldbm_back_delete( Slapi_PBlock *pb )
ID tomb_ep_id = 0;
int result_sent = 0;
Connection *pb_conn;
+ int32_t parent_op = 0;
+ struct timespec parent_time;
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
conn_id = 0; /* connection is NULL */
@@ -98,6 +100,13 @@ ldbm_back_delete( Slapi_PBlock *pb )
/* dblayer_txn_init needs to be called before "goto error_return" */
dblayer_txn_init(li,&txn);
+
+ if (txn.back_txn_txn == NULL) {
+ /* This is the parent operation, get the time */
+ parent_op = 1;
+ parent_time = slapi_current_rel_time_hr();
+ }
+
/* the calls to perform searches require the parent txn if any
so set txn to the parent_txn until we begin the child transaction */
if (parent_txn) {
@@ -208,8 +217,13 @@ ldbm_back_delete( Slapi_PBlock *pb )
ldap_result_code= LDAP_OPERATIONS_ERROR;
goto error_return;
}
- if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
- CACHE_REMOVE(&inst->inst_cache, tombstone);
+ CACHE_REMOVE(&inst->inst_cache, tombstone); /* TEST FIX: Always remove
tombstone from cache */
+ if (cache_is_in_cache(&inst->inst_cache, tombstone) == 0) {
+ /* This really should not happen - means there is cache corruption */
+ slapi_log_err(SLAPI_LOG_ALERT, "ldbm_back_delete",
+ "DEBUG [retry: %d] - tombstone NOT in cache (%s) orig dn (%s) state
(%d), "
+ "but it should be in the cache (avoided crash, but
cache was corrupted)\n",
+ retry_count, backentry_get_ndn(tombstone), dn, tombstone->ep_state);
}
CACHE_RETURN(&inst->inst_cache, &tombstone);
if (tombstone) {
@@ -1312,6 +1326,10 @@ ldbm_back_delete( Slapi_PBlock *pb )
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
if (tombstone) {
if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
tomb_ep_id = tombstone->ep_id; /* Otherwise, tombstone might have been freed. */
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index 307f7c2..14c493a 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -393,6 +393,8 @@ ldbm_back_modify( Slapi_PBlock *pb )
int fixup_tombstone = 0;
int ec_locked = 0;
int result_sent = 0;
+ int32_t parent_op = 0;
+ struct timespec parent_time;
slapi_pblock_get( pb, SLAPI_BACKEND, &be);
slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
@@ -405,6 +407,12 @@ ldbm_back_modify( Slapi_PBlock *pb )
fixup_tombstone = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_FIXUP);
dblayer_txn_init(li,&txn); /* must do this before first goto error_return */
+
+ if (txn.back_txn_txn == NULL) {
+ /* This is the parent operation, get the time */
+ parent_op = 1;
+ parent_time = slapi_current_rel_time_hr();
+ }
/* the calls to perform searches require the parent txn if any
so set txn to the parent_txn until we begin the child transaction */
if (parent_txn) {
@@ -863,6 +871,10 @@ ldbm_back_modify( Slapi_PBlock *pb )
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
if ( postentry != NULL )
{
slapi_entry_free( postentry );
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index 40d2415..c5d7a12 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -97,6 +97,8 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
int op_id;
int result_sent = 0;
Connection *pb_conn = NULL;
+ int32_t parent_op = 0;
+ struct timespec parent_time;
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
conn_id = 0; /* connection is NULL */
@@ -134,6 +136,13 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
/* dblayer_txn_init needs to be called before "goto error_return" */
dblayer_txn_init(li,&txn);
+
+ if (txn.back_txn_txn == NULL) {
+ /* This is the parent operation, get the time */
+ parent_op = 1;
+ parent_time = slapi_current_rel_time_hr();
+ }
+
/* the calls to perform searches require the parent txn if any
so set txn to the parent_txn until we begin the child transaction */
if (parent_txn) {
@@ -1326,6 +1335,10 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
goto common_return;
error_return:
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
/* result already sent above - just free stuff */
if (postentry) {
slapi_entry_free( postentry );
@@ -1410,6 +1423,10 @@ error_return:
slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ?
&ldap_result_code : &retval );
}
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
+ /* Revert the caches if this is the parent operation */
+ if (parent_op) {
+ revert_cache(inst, &parent_time);
+ }
}
/* Release SERIAL LOCK */
@@ -1469,13 +1486,8 @@ common_return:
CACHE_RETURN(&inst->inst_dncache, &bdn);
}
- /* remove the new entry from the cache if the op failed -
- otherwise, leave it in */
if (ec && inst) {
- if (retval && cache_is_in_cache(&inst->inst_cache, ec)) {
- CACHE_REMOVE( &inst->inst_cache, ec );
- }
- CACHE_RETURN( &inst->inst_cache, &ec );
+ CACHE_RETURN(&inst->inst_cache, &ec);
}
ec = NULL;
}
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 86ef5cb..09c1226 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -61,6 +61,7 @@ void cache_unlock_entry(struct cache *cache, struct backentry *e);
int cache_replace(struct cache *cache, void *oldptr, void *newptr);
int cache_has_otherref(struct cache *cache, void *bep);
int cache_is_in_cache(struct cache *cache, void *ptr);
+void revert_cache(ldbm_instance *inst, struct timespec *start_time);
#ifdef CACHE_DEBUG
void check_entry_cache(struct cache *cache, struct backentry *e);
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index d37bc63..08e6a81 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -6779,6 +6779,12 @@ int slapi_reslimit_get_integer_limit( Slapi_Connection *conn, int
handle,
*/
time_t slapi_current_time( void );
+/**
+ * Returns the current system time as a hr clock
+ *
+ * \return timespec of the current monotonic time.
+ */
+struct timespec slapi_current_rel_time_hr(void);
/*
* Plugin and parameter block related macros (remainder of this file).
@@ -8086,6 +8092,15 @@ uint64_t slapi_atomic_incr_64(uint64_t *ptr, int memorder);
*/
uint64_t slapi_atomic_decr_64(uint64_t *ptr, int memorder);
+/**
+ * Diffs two timespects a - b into *diff. This is useful with
+ * clock_monotonic to find time taken to perform operations.
+ *
+ * \param struct timespec a the "end" time.
+ * \param struct timespec b the "start" time.
+ * \param struct timespec c the difference.
+ */
+void slapi_timespec_diff(struct timespec *a, struct timespec *b, struct timespec *diff);
#ifdef __cplusplus
}
diff --git a/ldap/servers/slapd/time.c b/ldap/servers/slapd/time.c
index 16467af..69ae303 100644
--- a/ldap/servers/slapd/time.c
+++ b/ldap/servers/slapd/time.c
@@ -144,6 +144,32 @@ slapi_current_time( void )
return current_time();
}
+struct timespec
+slapi_current_rel_time_hr(void)
+{
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ return now;
+}
+
+void
+slapi_timespec_diff(struct timespec *a, struct timespec *b, struct timespec *diff)
+{
+ /* Now diff the two */
+ time_t sec = a->tv_sec - b->tv_sec;
+ int32_t nsec = a->tv_nsec - b->tv_nsec;
+
+ if (nsec < 0) {
+ /* It's negative so take one second */
+ sec -= 1;
+ /* And set nsec to to a whole value */
+ nsec = 1000000000 - nsec;
+ }
+
+ diff->tv_sec = sec;
+ diff->tv_nsec = nsec;
+}
+
time_t
time_plus_sec (time_t l, long r)
/* return the point in time 'r' seconds after 'l'. */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.