|
|
d0a457 |
From 17aada4feb87407e004a890225700e730778d692 Mon Sep 17 00:00:00 2001
|
|
|
d0a457 |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
d0a457 |
Date: Thu, 20 Jun 2019 15:50:08 -0400
|
|
|
d0a457 |
Subject: [PATCH 1/2] BZ1518320 - entry cache crash fix
|
|
|
d0a457 |
|
|
|
d0a457 |
Description: THis patch is combination of all the entry cache fixes.
|
|
|
d0a457 |
|
|
|
d0a457 |
If these fixes are not enough, there is an experimental
|
|
|
d0a457 |
"fix" that should prevent the crash. A message will be
|
|
|
d0a457 |
logged that reports the crash was averted:
|
|
|
d0a457 |
|
|
|
d0a457 |
"(avoided crash, but cache was corrupted)"
|
|
|
d0a457 |
|
|
|
d0a457 |
The customer should monitor the errors log for this text,
|
|
|
d0a457 |
and let GSS know if they see it.
|
|
|
d0a457 |
---
|
|
|
d0a457 |
configure.ac | 3 -
|
|
|
d0a457 |
dirsrvtests/tests/suites/betxns/betxn_test.py | 57 ++++++
|
|
|
d0a457 |
ldap/servers/slapd/back-ldbm/back-ldbm.h | 68 ++++----
|
|
|
d0a457 |
ldap/servers/slapd/back-ldbm/backentry.c | 2 +-
|
|
|
d0a457 |
ldap/servers/slapd/back-ldbm/cache.c | 163 ++++++++++++++++--
|
|
|
d0a457 |
ldap/servers/slapd/back-ldbm/ldbm_add.c | 13 ++
|
|
|
d0a457 |
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 12 ++
|
|
|
d0a457 |
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 12 ++
|
|
|
d0a457 |
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 22 ++-
|
|
|
d0a457 |
.../servers/slapd/back-ldbm/proto-back-ldbm.h | 1 +
|
|
|
d0a457 |
ldap/servers/slapd/slapi-plugin.h | 15 ++
|
|
|
d0a457 |
ldap/servers/slapd/time.c | 26 +++
|
|
|
d0a457 |
12 files changed, 341 insertions(+), 53 deletions(-)
|
|
|
d0a457 |
|
|
|
d0a457 |
diff --git a/configure.ac b/configure.ac
|
|
|
d0a457 |
index 91d6d398b..ea528ff2b 100644
|
|
|
d0a457 |
--- a/configure.ac
|
|
|
d0a457 |
+++ b/configure.ac
|
|
|
d0a457 |
@@ -72,9 +72,6 @@ AC_FUNC_STRFTIME
|
|
|
d0a457 |
AC_FUNC_VPRINTF
|
|
|
d0a457 |
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])
|
|
|
d0a457 |
|
|
|
d0a457 |
-# These functions are *required* without option.
|
|
|
d0a457 |
-AC_CHECK_FUNCS([clock_gettime], [], AC_MSG_ERROR([unable to locate required symbol clock_gettime]))
|
|
|
d0a457 |
-
|
|
|
d0a457 |
# This will detect if we need to add the LIBADD_DL value for us.
|
|
|
d0a457 |
LT_LIB_DLLOAD
|
|
|
d0a457 |
|
|
|
d0a457 |
diff --git a/dirsrvtests/tests/suites/betxns/betxn_test.py b/dirsrvtests/tests/suites/betxns/betxn_test.py
|
|
|
d0a457 |
index 175496495..48181a9ea 100644
|
|
|
d0a457 |
--- a/dirsrvtests/tests/suites/betxns/betxn_test.py
|
|
|
d0a457 |
+++ b/dirsrvtests/tests/suites/betxns/betxn_test.py
|
|
|
d0a457 |
@@ -8,6 +8,7 @@
|
|
|
d0a457 |
#
|
|
|
d0a457 |
import pytest
|
|
|
d0a457 |
import six
|
|
|
d0a457 |
+import ldap
|
|
|
d0a457 |
from lib389.tasks import *
|
|
|
d0a457 |
from lib389.utils import *
|
|
|
d0a457 |
from lib389.topologies import topology_st
|
|
|
d0a457 |
@@ -248,6 +249,62 @@ def test_betxn_memberof(topology_st, dynamic_plugins):
|
|
|
d0a457 |
log.info('test_betxn_memberof: PASSED')
|
|
|
d0a457 |
|
|
|
d0a457 |
|
|
|
d0a457 |
+def test_betxn_modrdn_memberof(topology_st):
|
|
|
d0a457 |
+ """Test modrdn operartions and memberOf
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ :id: 70d0b96e-b693-4bf7-bbf5-102a66ac5994
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ :setup: Standalone instance
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ :steps: 1. Enable and configure memberOf plugin
|
|
|
d0a457 |
+ 2. Set memberofgroupattr="member" and memberofAutoAddOC="nsContainer"
|
|
|
d0a457 |
+ 3. Create group and user outside of memberOf plugin scope
|
|
|
d0a457 |
+ 4. Do modrdn to move group into scope
|
|
|
d0a457 |
+ 5. Do modrdn to move group into scope (again)
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ :expectedresults:
|
|
|
d0a457 |
+ 1. memberOf plugin plugin should be ON
|
|
|
d0a457 |
+ 2. Set memberofgroupattr="member" and memberofAutoAddOC="nsContainer" should PASS
|
|
|
d0a457 |
+ 3. Creating group and user should PASS
|
|
|
d0a457 |
+ 4. Modrdn should fail with objectclass violation
|
|
|
d0a457 |
+ 5. Second modrdn should also fail with objectclass violation
|
|
|
d0a457 |
+ """
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ peoplebase = 'ou=people,%s' % DEFAULT_SUFFIX
|
|
|
d0a457 |
+ memberof = MemberOfPlugin(topology_st.standalone)
|
|
|
d0a457 |
+ memberof.enable()
|
|
|
d0a457 |
+ memberof.set_autoaddoc('nsContainer') # Bad OC
|
|
|
d0a457 |
+ memberof.set('memberOfEntryScope', peoplebase)
|
|
|
d0a457 |
+ memberof.set('memberOfAllBackends', 'on')
|
|
|
d0a457 |
+ topology_st.standalone.restart()
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ groups = Groups(topology_st.standalone, DEFAULT_SUFFIX)
|
|
|
d0a457 |
+ group = groups.create(properties={
|
|
|
d0a457 |
+ 'cn': 'group',
|
|
|
d0a457 |
+ })
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ # Create user and add it to group
|
|
|
d0a457 |
+ users = UserAccounts(topology_st.standalone, basedn=DEFAULT_SUFFIX)
|
|
|
d0a457 |
+ user = users.create(properties=TEST_USER_PROPERTIES)
|
|
|
d0a457 |
+ if not ds_is_older('1.3.7'):
|
|
|
d0a457 |
+ user.remove('objectClass', 'nsMemberOf')
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ group.add_member(user.dn)
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ # Attempt modrdn that should fail, but the original entry should stay in the cache
|
|
|
d0a457 |
+ with pytest.raises(ldap.OBJECTCLASS_VIOLATION):
|
|
|
d0a457 |
+ group.rename('cn=group_to_people', newsuperior=peoplebase)
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ # Should fail, but not with NO_SUCH_OBJECT as the original entry should still be in the cache
|
|
|
d0a457 |
+ with pytest.raises(ldap.OBJECTCLASS_VIOLATION):
|
|
|
d0a457 |
+ group.rename('cn=group_to_people', newsuperior=peoplebase)
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ #
|
|
|
d0a457 |
+ # Done
|
|
|
d0a457 |
+ #
|
|
|
d0a457 |
+ log.info('test_betxn_modrdn_memberof: PASSED')
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+
|
|
|
d0a457 |
if __name__ == '__main__':
|
|
|
d0a457 |
# Run isolated
|
|
|
d0a457 |
# -s for DEBUG mode
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
|
|
d0a457 |
index 4727961a9..399508561 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
|
|
d0a457 |
@@ -310,36 +310,37 @@ typedef struct
|
|
|
d0a457 |
#define CACHE_TYPE_ENTRY 0
|
|
|
d0a457 |
#define CACHE_TYPE_DN 1
|
|
|
d0a457 |
|
|
|
d0a457 |
-struct backcommon
|
|
|
d0a457 |
-{
|
|
|
d0a457 |
- int ep_type; /* to distinguish backdn from backentry */
|
|
|
d0a457 |
- struct backcommon *ep_lrunext; /* for the cache */
|
|
|
d0a457 |
- struct backcommon *ep_lruprev; /* for the cache */
|
|
|
d0a457 |
- ID ep_id; /* entry id */
|
|
|
d0a457 |
- char ep_state; /* state in the cache */
|
|
|
d0a457 |
-#define ENTRY_STATE_DELETED 0x1 /* entry is marked as deleted */
|
|
|
d0a457 |
-#define ENTRY_STATE_CREATING 0x2 /* entry is being created; don't touch it */
|
|
|
d0a457 |
-#define ENTRY_STATE_NOTINCACHE 0x4 /* cache_add failed; not in the cache */
|
|
|
d0a457 |
- int ep_refcnt; /* entry reference cnt */
|
|
|
d0a457 |
- size_t ep_size; /* for cache tracking */
|
|
|
d0a457 |
+struct backcommon {
|
|
|
d0a457 |
+ int ep_type; /* to distinguish backdn from backentry */
|
|
|
d0a457 |
+ struct backcommon *ep_lrunext; /* for the cache */
|
|
|
d0a457 |
+ struct backcommon *ep_lruprev; /* for the cache */
|
|
|
d0a457 |
+ ID ep_id; /* entry id */
|
|
|
d0a457 |
+ char ep_state; /* state in the cache */
|
|
|
d0a457 |
+#define ENTRY_STATE_DELETED 0x1 /* entry is marked as deleted */
|
|
|
d0a457 |
+#define ENTRY_STATE_CREATING 0x2 /* entry is being created; don't touch it */
|
|
|
d0a457 |
+#define ENTRY_STATE_NOTINCACHE 0x4 /* cache_add failed; not in the cache */
|
|
|
d0a457 |
+#define ENTRY_STATE_INVALID 0x8 /* cache entry is invalid and needs to be removed */
|
|
|
d0a457 |
+ int ep_refcnt; /* entry reference cnt */
|
|
|
d0a457 |
+ size_t ep_size; /* for cache tracking */
|
|
|
d0a457 |
+ struct timespec ep_create_time; /* the time the entry was added to the cache */
|
|
|
d0a457 |
};
|
|
|
d0a457 |
|
|
|
d0a457 |
/* From ep_type through ep_size MUST be identical to backcommon */
|
|
|
d0a457 |
-struct backentry
|
|
|
d0a457 |
-{
|
|
|
d0a457 |
- int ep_type; /* to distinguish backdn from backentry */
|
|
|
d0a457 |
- struct backcommon *ep_lrunext; /* for the cache */
|
|
|
d0a457 |
- struct backcommon *ep_lruprev; /* for the cache */
|
|
|
d0a457 |
- ID ep_id; /* entry id */
|
|
|
d0a457 |
- char ep_state; /* state in the cache */
|
|
|
d0a457 |
- int ep_refcnt; /* entry reference cnt */
|
|
|
d0a457 |
- size_t ep_size; /* for cache tracking */
|
|
|
d0a457 |
- Slapi_Entry *ep_entry; /* real entry */
|
|
|
d0a457 |
- Slapi_Entry *ep_vlventry;
|
|
|
d0a457 |
- void *ep_dn_link; /* linkage for the 3 hash */
|
|
|
d0a457 |
- void *ep_id_link; /* tables used for */
|
|
|
d0a457 |
- void *ep_uuid_link; /* looking up entries */
|
|
|
d0a457 |
- PRMonitor *ep_mutexp; /* protection for mods; make it reentrant */
|
|
|
d0a457 |
+struct backentry {
|
|
|
d0a457 |
+ int ep_type; /* to distinguish backdn from backentry */
|
|
|
d0a457 |
+ struct backcommon *ep_lrunext; /* for the cache */
|
|
|
d0a457 |
+ struct backcommon *ep_lruprev; /* for the cache */
|
|
|
d0a457 |
+ ID ep_id; /* entry id */
|
|
|
d0a457 |
+ char ep_state; /* state in the cache */
|
|
|
d0a457 |
+ int ep_refcnt; /* entry reference cnt */
|
|
|
d0a457 |
+ size_t ep_size; /* for cache tracking */
|
|
|
d0a457 |
+ struct timespec ep_create_time; /* the time the entry was added to the cache */
|
|
|
d0a457 |
+ Slapi_Entry *ep_entry; /* real entry */
|
|
|
d0a457 |
+ Slapi_Entry *ep_vlventry;
|
|
|
d0a457 |
+ void * ep_dn_link; /* linkage for the 3 hash */
|
|
|
d0a457 |
+ void * ep_id_link; /* tables used for */
|
|
|
d0a457 |
+ void * ep_uuid_link; /* looking up entries */
|
|
|
d0a457 |
+ PRMonitor *ep_mutexp; /* protection for mods; make it reentrant */
|
|
|
d0a457 |
};
|
|
|
d0a457 |
|
|
|
d0a457 |
/* From ep_type through ep_size MUST be identical to backcommon */
|
|
|
d0a457 |
@@ -348,12 +349,13 @@ struct backdn
|
|
|
d0a457 |
int ep_type; /* to distinguish backdn from backentry */
|
|
|
d0a457 |
struct backcommon *ep_lrunext; /* for the cache */
|
|
|
d0a457 |
struct backcommon *ep_lruprev; /* for the cache */
|
|
|
d0a457 |
- ID ep_id; /* entry id */
|
|
|
d0a457 |
- char ep_state; /* state in the cache; share ENTRY_STATE_* */
|
|
|
d0a457 |
- int ep_refcnt; /* entry reference cnt */
|
|
|
d0a457 |
- size_t ep_size; /* for cache tracking */
|
|
|
d0a457 |
- Slapi_DN *dn_sdn;
|
|
|
d0a457 |
- void *dn_id_link; /* for hash table */
|
|
|
d0a457 |
+ ID ep_id; /* entry id */
|
|
|
d0a457 |
+ char ep_state; /* state in the cache; share ENTRY_STATE_* */
|
|
|
d0a457 |
+ int ep_refcnt; /* entry reference cnt */
|
|
|
d0a457 |
+ size_t ep_size; /* for cache tracking */
|
|
|
d0a457 |
+ struct timespec ep_create_time; /* the time the entry was added to the cache */
|
|
|
d0a457 |
+ Slapi_DN *dn_sdn;
|
|
|
d0a457 |
+ void *dn_id_link; /* for hash table */
|
|
|
d0a457 |
};
|
|
|
d0a457 |
|
|
|
d0a457 |
/* for the in-core cache of entries */
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/backentry.c b/ldap/servers/slapd/back-ldbm/backentry.c
|
|
|
d0a457 |
index f2fe780db..a1f3ca1bb 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/backentry.c
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/backentry.c
|
|
|
d0a457 |
@@ -23,7 +23,7 @@ backentry_free(struct backentry **bep)
|
|
|
d0a457 |
return;
|
|
|
d0a457 |
}
|
|
|
d0a457 |
ep = *bep;
|
|
|
d0a457 |
- PR_ASSERT(ep->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_NOTINCACHE));
|
|
|
d0a457 |
+ PR_ASSERT(ep->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_NOTINCACHE | ENTRY_STATE_INVALID));
|
|
|
d0a457 |
if (ep->ep_entry != NULL) {
|
|
|
d0a457 |
slapi_entry_free(ep->ep_entry);
|
|
|
d0a457 |
}
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
|
|
|
d0a457 |
index 86e1f7b39..054766df2 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/cache.c
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/cache.c
|
|
|
d0a457 |
@@ -56,6 +56,11 @@
|
|
|
d0a457 |
#define LOG(...)
|
|
|
d0a457 |
#endif
|
|
|
d0a457 |
|
|
|
d0a457 |
+typedef enum {
|
|
|
d0a457 |
+ ENTRY_CACHE,
|
|
|
d0a457 |
+ DN_CACHE,
|
|
|
d0a457 |
+} CacheType;
|
|
|
d0a457 |
+
|
|
|
d0a457 |
#define LRU_DETACH(cache, e) lru_detach((cache), (void *)(e))
|
|
|
d0a457 |
|
|
|
d0a457 |
#define CACHE_LRU_HEAD(cache, type) ((type)((cache)->c_lruhead))
|
|
|
d0a457 |
@@ -185,6 +190,7 @@ new_hash(u_long size, u_long offset, HashFn hfn, HashTestFn tfn)
|
|
|
d0a457 |
int
|
|
|
d0a457 |
add_hash(Hashtable *ht, void *key, uint32_t keylen, void *entry, void **alt)
|
|
|
d0a457 |
{
|
|
|
d0a457 |
+ struct backcommon *back_entry = (struct backcommon *)entry;
|
|
|
d0a457 |
u_long val, slot;
|
|
|
d0a457 |
void *e;
|
|
|
d0a457 |
|
|
|
d0a457 |
@@ -202,6 +208,7 @@ add_hash(Hashtable *ht, void *key, uint32_t keylen, void *entry, void **alt)
|
|
|
d0a457 |
e = HASH_NEXT(ht, e);
|
|
|
d0a457 |
}
|
|
|
d0a457 |
/* ok, it's not already there, so add it */
|
|
|
d0a457 |
+ back_entry->ep_create_time = slapi_current_rel_time_hr();
|
|
|
d0a457 |
HASH_NEXT(ht, entry) = ht->slot[slot];
|
|
|
d0a457 |
ht->slot[slot] = entry;
|
|
|
d0a457 |
return 1;
|
|
|
d0a457 |
@@ -492,6 +499,126 @@ cache_make_hashes(struct cache *cache, int type)
|
|
|
d0a457 |
}
|
|
|
d0a457 |
}
|
|
|
d0a457 |
|
|
|
d0a457 |
+/*
|
|
|
d0a457 |
+ * Helper function for flush_hash() to calculate if the entry should be
|
|
|
d0a457 |
+ * removed from the cache.
|
|
|
d0a457 |
+ */
|
|
|
d0a457 |
+static int32_t
|
|
|
d0a457 |
+flush_remove_entry(struct timespec *entry_time, struct timespec *start_time)
|
|
|
d0a457 |
+{
|
|
|
d0a457 |
+ struct timespec diff;
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ slapi_timespec_diff(entry_time, start_time, &diff);
|
|
|
d0a457 |
+ if (diff.tv_sec >= 0) {
|
|
|
d0a457 |
+ return 1;
|
|
|
d0a457 |
+ } else {
|
|
|
d0a457 |
+ return 0;
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+}
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+/*
|
|
|
d0a457 |
+ * Flush all the cache entries that were added after the "start time"
|
|
|
d0a457 |
+ * This is called when a backend transaction plugin fails, and we need
|
|
|
d0a457 |
+ * to remove all the possible invalid entries in the cache.
|
|
|
d0a457 |
+ *
|
|
|
d0a457 |
+ * If the ref count is 0, we can straight up remove it from the cache, but
|
|
|
d0a457 |
+ * if the ref count is greater than 1, then the entry is currently in use.
|
|
|
d0a457 |
+ * In the later case we set the entry state to ENTRY_STATE_INVALID, and
|
|
|
d0a457 |
+ * when the owning thread cache_returns() the cache entry is automatically
|
|
|
d0a457 |
+ * removed so another thread can not use/lock the invalid cache entry.
|
|
|
d0a457 |
+ */
|
|
|
d0a457 |
+static void
|
|
|
d0a457 |
+flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
|
|
|
d0a457 |
+{
|
|
|
d0a457 |
+ Hashtable *ht = cache->c_idtable; /* start with the ID table as it's in both ENTRY and DN caches */
|
|
|
d0a457 |
+ void *e, *laste = NULL;
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ cache_lock(cache);
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ for (size_t i = 0; i < ht->size; i++) {
|
|
|
d0a457 |
+ e = ht->slot[i];
|
|
|
d0a457 |
+ while (e) {
|
|
|
d0a457 |
+ struct backcommon *entry = (struct backcommon *)e;
|
|
|
d0a457 |
+ uint64_t remove_it = 0;
|
|
|
d0a457 |
+ if (flush_remove_entry(&entry->ep_create_time, start_time)) {
|
|
|
d0a457 |
+ /* Mark the entry to be removed */
|
|
|
d0a457 |
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash", "[%s] Removing entry id (%d)\n",
|
|
|
d0a457 |
+ type ? "DN CACHE" : "ENTRY CACHE", entry->ep_id);
|
|
|
d0a457 |
+ remove_it = 1;
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ laste = e;
|
|
|
d0a457 |
+ e = HASH_NEXT(ht, e);
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (remove_it) {
|
|
|
d0a457 |
+ /* since we have the cache lock we know we can trust refcnt */
|
|
|
d0a457 |
+ entry->ep_state |= ENTRY_STATE_INVALID;
|
|
|
d0a457 |
+ if (entry->ep_refcnt == 0) {
|
|
|
d0a457 |
+ entry->ep_refcnt++;
|
|
|
d0a457 |
+ lru_delete(cache, laste);
|
|
|
d0a457 |
+ if (type == ENTRY_CACHE) {
|
|
|
d0a457 |
+ entrycache_remove_int(cache, laste);
|
|
|
d0a457 |
+ entrycache_return(cache, (struct backentry **)&laste);
|
|
|
d0a457 |
+ } else {
|
|
|
d0a457 |
+ dncache_remove_int(cache, laste);
|
|
|
d0a457 |
+ dncache_return(cache, (struct backdn **)&laste);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ } else {
|
|
|
d0a457 |
+ /* Entry flagged for removal */
|
|
|
d0a457 |
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash",
|
|
|
d0a457 |
+ "[%s] Flagging entry to be removed later: id (%d) refcnt: %d\n",
|
|
|
d0a457 |
+ type ? "DN CACHE" : "ENTRY CACHE", entry->ep_id, entry->ep_refcnt);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (type == ENTRY_CACHE) {
|
|
|
d0a457 |
+ /* Also check the DN hashtable */
|
|
|
d0a457 |
+ ht = cache->c_dntable;
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ for (size_t i = 0; i < ht->size; i++) {
|
|
|
d0a457 |
+ e = ht->slot[i];
|
|
|
d0a457 |
+ while (e) {
|
|
|
d0a457 |
+ struct backcommon *entry = (struct backcommon *)e;
|
|
|
d0a457 |
+ uint64_t remove_it = 0;
|
|
|
d0a457 |
+ if (flush_remove_entry(&entry->ep_create_time, start_time)) {
|
|
|
d0a457 |
+ /* Mark the entry to be removed */
|
|
|
d0a457 |
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash", "[ENTRY CACHE] Removing entry id (%d)\n",
|
|
|
d0a457 |
+ entry->ep_id);
|
|
|
d0a457 |
+ remove_it = 1;
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ laste = e;
|
|
|
d0a457 |
+ e = HASH_NEXT(ht, e);
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (remove_it) {
|
|
|
d0a457 |
+ /* since we have the cache lock we know we can trust refcnt */
|
|
|
d0a457 |
+ entry->ep_state |= ENTRY_STATE_INVALID;
|
|
|
d0a457 |
+ if (entry->ep_refcnt == 0) {
|
|
|
d0a457 |
+ entry->ep_refcnt++;
|
|
|
d0a457 |
+ lru_delete(cache, laste);
|
|
|
d0a457 |
+ entrycache_remove_int(cache, laste);
|
|
|
d0a457 |
+ entrycache_return(cache, (struct backentry **)&laste);
|
|
|
d0a457 |
+ } else {
|
|
|
d0a457 |
+ /* Entry flagged for removal */
|
|
|
d0a457 |
+ slapi_log_err(SLAPI_LOG_CACHE, "flush_hash",
|
|
|
d0a457 |
+ "[ENTRY CACHE] Flagging entry to be removed later: id (%d) refcnt: %d\n",
|
|
|
d0a457 |
+ entry->ep_id, entry->ep_refcnt);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ cache_unlock(cache);
|
|
|
d0a457 |
+}
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+void
|
|
|
d0a457 |
+revert_cache(ldbm_instance *inst, struct timespec *start_time)
|
|
|
d0a457 |
+{
|
|
|
d0a457 |
+ flush_hash(&inst->inst_cache, start_time, ENTRY_CACHE);
|
|
|
d0a457 |
+ flush_hash(&inst->inst_dncache, start_time, DN_CACHE);
|
|
|
d0a457 |
+}
|
|
|
d0a457 |
+
|
|
|
d0a457 |
/* initialize the cache */
|
|
|
d0a457 |
int
|
|
|
d0a457 |
cache_init(struct cache *cache, uint64_t maxsize, long maxentries, int type)
|
|
|
d0a457 |
@@ -1141,10 +1268,10 @@ entrycache_return(struct cache *cache, struct backentry **bep)
|
|
|
d0a457 |
backentry_free(bep);
|
|
|
d0a457 |
} else {
|
|
|
d0a457 |
ASSERT(e->ep_refcnt > 0);
|
|
|
d0a457 |
- if (!--e->ep_refcnt) {
|
|
|
d0a457 |
- if (e->ep_state & ENTRY_STATE_DELETED) {
|
|
|
d0a457 |
- const char *ndn = slapi_sdn_get_ndn(backentry_get_sdn(e));
|
|
|
d0a457 |
- if (ndn) {
|
|
|
d0a457 |
+ if (! --e->ep_refcnt) {
|
|
|
d0a457 |
+ if (e->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_INVALID)) {
|
|
|
d0a457 |
+ const char* ndn = slapi_sdn_get_ndn(backentry_get_sdn(e));
|
|
|
d0a457 |
+ if (ndn){
|
|
|
d0a457 |
/*
|
|
|
d0a457 |
* State is "deleted" and there are no more references,
|
|
|
d0a457 |
* so we need to remove the entry from the DN cache because
|
|
|
d0a457 |
@@ -1154,6 +1281,13 @@ entrycache_return(struct cache *cache, struct backentry **bep)
|
|
|
d0a457 |
LOG("entrycache_return -Failed to remove %s from dn table\n", ndn);
|
|
|
d0a457 |
}
|
|
|
d0a457 |
}
|
|
|
d0a457 |
+ if (e->ep_state & ENTRY_STATE_INVALID) {
|
|
|
d0a457 |
+ /* Remove it from the hash table before we free the back entry */
|
|
|
d0a457 |
+ slapi_log_err(SLAPI_LOG_CACHE, "entrycache_return",
|
|
|
d0a457 |
+ "Finally flushing invalid entry: %d (%s)\n",
|
|
|
d0a457 |
+ e->ep_id, backentry_get_ndn(e));
|
|
|
d0a457 |
+ entrycache_remove_int(cache, e);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
backentry_free(bep);
|
|
|
d0a457 |
} else {
|
|
|
d0a457 |
lru_add(cache, e);
|
|
|
d0a457 |
@@ -1535,11 +1669,11 @@ cache_lock_entry(struct cache *cache, struct backentry *e)
|
|
|
d0a457 |
|
|
|
d0a457 |
/* make sure entry hasn't been deleted now */
|
|
|
d0a457 |
cache_lock(cache);
|
|
|
d0a457 |
- if (e->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_NOTINCACHE)) {
|
|
|
d0a457 |
- cache_unlock(cache);
|
|
|
d0a457 |
- PR_ExitMonitor(e->ep_mutexp);
|
|
|
d0a457 |
- LOG("<= cache_lock_entry (DELETED)\n");
|
|
|
d0a457 |
- return RETRY_CACHE_LOCK;
|
|
|
d0a457 |
+ if (e->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_NOTINCACHE | ENTRY_STATE_INVALID)) {
|
|
|
d0a457 |
+ cache_unlock(cache);
|
|
|
d0a457 |
+ PR_ExitMonitor(e->ep_mutexp);
|
|
|
d0a457 |
+ LOG("<= cache_lock_entry (DELETED)\n");
|
|
|
d0a457 |
+ return RETRY_CACHE_LOCK;
|
|
|
d0a457 |
}
|
|
|
d0a457 |
cache_unlock(cache);
|
|
|
d0a457 |
|
|
|
d0a457 |
@@ -1695,8 +1829,15 @@ dncache_return(struct cache *cache, struct backdn **bdn)
|
|
|
d0a457 |
backdn_free(bdn);
|
|
|
d0a457 |
} else {
|
|
|
d0a457 |
ASSERT((*bdn)->ep_refcnt > 0);
|
|
|
d0a457 |
- if (!--(*bdn)->ep_refcnt) {
|
|
|
d0a457 |
- if ((*bdn)->ep_state & ENTRY_STATE_DELETED) {
|
|
|
d0a457 |
+ if (! --(*bdn)->ep_refcnt) {
|
|
|
d0a457 |
+ if ((*bdn)->ep_state & (ENTRY_STATE_DELETED | ENTRY_STATE_INVALID)) {
|
|
|
d0a457 |
+ if ((*bdn)->ep_state & ENTRY_STATE_INVALID) {
|
|
|
d0a457 |
+ /* Remove it from the hash table before we free the back dn */
|
|
|
d0a457 |
+ slapi_log_err(SLAPI_LOG_CACHE, "dncache_return",
|
|
|
d0a457 |
+ "Finally flushing invalid entry: %d (%s)\n",
|
|
|
d0a457 |
+ (*bdn)->ep_id, slapi_sdn_get_dn((*bdn)->dn_sdn));
|
|
|
d0a457 |
+ dncache_remove_int(cache, (*bdn));
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
backdn_free(bdn);
|
|
|
d0a457 |
} else {
|
|
|
d0a457 |
lru_add(cache, (void *)*bdn);
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
|
|
d0a457 |
index 32c8e71ff..d3c8cdab2 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
|
|
d0a457 |
@@ -97,6 +97,8 @@ ldbm_back_add(Slapi_PBlock *pb)
|
|
|
d0a457 |
PRUint64 conn_id;
|
|
|
d0a457 |
int op_id;
|
|
|
d0a457 |
int result_sent = 0;
|
|
|
d0a457 |
+ int32_t parent_op = 0;
|
|
|
d0a457 |
+ struct timespec parent_time;
|
|
|
d0a457 |
|
|
|
d0a457 |
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
|
|
|
d0a457 |
conn_id = 0; /* connection is NULL */
|
|
|
d0a457 |
@@ -147,6 +149,13 @@ ldbm_back_add(Slapi_PBlock *pb)
|
|
|
d0a457 |
slapi_entry_delete_values(e, numsubordinates, NULL);
|
|
|
d0a457 |
|
|
|
d0a457 |
dblayer_txn_init(li, &txn);
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (txn.back_txn_txn == NULL) {
|
|
|
d0a457 |
+ /* This is the parent operation, get the time */
|
|
|
d0a457 |
+ parent_op = 1;
|
|
|
d0a457 |
+ parent_time = slapi_current_rel_time_hr();
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
/* the calls to perform searches require the parent txn if any
|
|
|
d0a457 |
so set txn to the parent_txn until we begin the child transaction */
|
|
|
d0a457 |
if (parent_txn) {
|
|
|
d0a457 |
@@ -1239,6 +1248,10 @@ ldbm_back_add(Slapi_PBlock *pb)
|
|
|
d0a457 |
goto common_return;
|
|
|
d0a457 |
|
|
|
d0a457 |
error_return:
|
|
|
d0a457 |
+ if (parent_op) {
|
|
|
d0a457 |
+ revert_cache(inst, &parent_time);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
if (addingentry_id_assigned) {
|
|
|
d0a457 |
next_id_return(be, addingentry->ep_id);
|
|
|
d0a457 |
}
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
|
|
d0a457 |
index f5f6c1e3a..80c53a3e0 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
|
|
d0a457 |
@@ -79,6 +79,8 @@ ldbm_back_delete(Slapi_PBlock *pb)
|
|
|
d0a457 |
ID tomb_ep_id = 0;
|
|
|
d0a457 |
int result_sent = 0;
|
|
|
d0a457 |
Connection *pb_conn;
|
|
|
d0a457 |
+ int32_t parent_op = 0;
|
|
|
d0a457 |
+ struct timespec parent_time;
|
|
|
d0a457 |
|
|
|
d0a457 |
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
|
|
|
d0a457 |
conn_id = 0; /* connection is NULL */
|
|
|
d0a457 |
@@ -98,6 +100,13 @@ ldbm_back_delete(Slapi_PBlock *pb)
|
|
|
d0a457 |
|
|
|
d0a457 |
/* dblayer_txn_init needs to be called before "goto error_return" */
|
|
|
d0a457 |
dblayer_txn_init(li, &txn);
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (txn.back_txn_txn == NULL) {
|
|
|
d0a457 |
+ /* This is the parent operation, get the time */
|
|
|
d0a457 |
+ parent_op = 1;
|
|
|
d0a457 |
+ parent_time = slapi_current_rel_time_hr();
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
/* the calls to perform searches require the parent txn if any
|
|
|
d0a457 |
so set txn to the parent_txn until we begin the child transaction */
|
|
|
d0a457 |
if (parent_txn) {
|
|
|
d0a457 |
@@ -1356,6 +1365,9 @@ commit_return:
|
|
|
d0a457 |
goto common_return;
|
|
|
d0a457 |
|
|
|
d0a457 |
error_return:
|
|
|
d0a457 |
+ if (parent_op) {
|
|
|
d0a457 |
+ revert_cache(inst, &parent_time);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
if (tombstone) {
|
|
|
d0a457 |
if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
|
|
|
d0a457 |
tomb_ep_id = tombstone->ep_id; /* Otherwise, tombstone might have been freed. */
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
|
|
d0a457 |
index cc4319e5f..93ab0a9e8 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
|
|
d0a457 |
@@ -412,6 +412,8 @@ ldbm_back_modify(Slapi_PBlock *pb)
|
|
|
d0a457 |
int fixup_tombstone = 0;
|
|
|
d0a457 |
int ec_locked = 0;
|
|
|
d0a457 |
int result_sent = 0;
|
|
|
d0a457 |
+ int32_t parent_op = 0;
|
|
|
d0a457 |
+ struct timespec parent_time;
|
|
|
d0a457 |
|
|
|
d0a457 |
slapi_pblock_get(pb, SLAPI_BACKEND, &be);
|
|
|
d0a457 |
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li;;
|
|
|
d0a457 |
@@ -424,6 +426,13 @@ ldbm_back_modify(Slapi_PBlock *pb)
|
|
|
d0a457 |
fixup_tombstone = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_FIXUP);
|
|
|
d0a457 |
|
|
|
d0a457 |
dblayer_txn_init(li, &txn); /* must do this before first goto error_return */
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (txn.back_txn_txn == NULL) {
|
|
|
d0a457 |
+ /* This is the parent operation, get the time */
|
|
|
d0a457 |
+ parent_op = 1;
|
|
|
d0a457 |
+ parent_time = slapi_current_rel_time_hr();
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
/* the calls to perform searches require the parent txn if any
|
|
|
d0a457 |
so set txn to the parent_txn until we begin the child transaction */
|
|
|
d0a457 |
if (parent_txn) {
|
|
|
d0a457 |
@@ -887,6 +896,9 @@ ldbm_back_modify(Slapi_PBlock *pb)
|
|
|
d0a457 |
goto common_return;
|
|
|
d0a457 |
|
|
|
d0a457 |
error_return:
|
|
|
d0a457 |
+ if (parent_op) {
|
|
|
d0a457 |
+ revert_cache(inst, &parent_time);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
if (postentry != NULL) {
|
|
|
d0a457 |
slapi_entry_free(postentry);
|
|
|
d0a457 |
postentry = NULL;
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
|
|
d0a457 |
index e2e9d1b46..1ca1bdb28 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
|
|
d0a457 |
@@ -97,6 +97,8 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
|
|
|
d0a457 |
int op_id;
|
|
|
d0a457 |
int result_sent = 0;
|
|
|
d0a457 |
Connection *pb_conn = NULL;
|
|
|
d0a457 |
+ int32_t parent_op = 0;
|
|
|
d0a457 |
+ struct timespec parent_time;
|
|
|
d0a457 |
|
|
|
d0a457 |
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
|
|
|
d0a457 |
conn_id = 0; /* connection is NULL */
|
|
|
d0a457 |
@@ -134,6 +136,13 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
|
|
|
d0a457 |
|
|
|
d0a457 |
/* dblayer_txn_init needs to be called before "goto error_return" */
|
|
|
d0a457 |
dblayer_txn_init(li, &txn);
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (txn.back_txn_txn == NULL) {
|
|
|
d0a457 |
+ /* This is the parent operation, get the time */
|
|
|
d0a457 |
+ parent_op = 1;
|
|
|
d0a457 |
+ parent_time = slapi_current_rel_time_hr();
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
/* the calls to perform searches require the parent txn if any
|
|
|
d0a457 |
so set txn to the parent_txn until we begin the child transaction */
|
|
|
d0a457 |
if (parent_txn) {
|
|
|
d0a457 |
@@ -1276,6 +1285,10 @@ ldbm_back_modrdn(Slapi_PBlock *pb)
|
|
|
d0a457 |
goto common_return;
|
|
|
d0a457 |
|
|
|
d0a457 |
error_return:
|
|
|
d0a457 |
+ /* Revert the caches if this is the parent operation */
|
|
|
d0a457 |
+ if (parent_op) {
|
|
|
d0a457 |
+ revert_cache(inst, &parent_time);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
/* result already sent above - just free stuff */
|
|
|
d0a457 |
if (postentry) {
|
|
|
d0a457 |
slapi_entry_free(postentry);
|
|
|
d0a457 |
@@ -1353,6 +1366,10 @@ error_return:
|
|
|
d0a457 |
slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval);
|
|
|
d0a457 |
}
|
|
|
d0a457 |
slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
|
|
|
d0a457 |
+ /* Revert the caches if this is the parent operation */
|
|
|
d0a457 |
+ if (parent_op) {
|
|
|
d0a457 |
+ revert_cache(inst, &parent_time);
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
}
|
|
|
d0a457 |
retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN);
|
|
|
d0a457 |
|
|
|
d0a457 |
@@ -1413,12 +1430,7 @@ common_return:
|
|
|
d0a457 |
CACHE_RETURN(&inst->inst_dncache, &bdn;;
|
|
|
d0a457 |
}
|
|
|
d0a457 |
|
|
|
d0a457 |
- /* remove the new entry from the cache if the op failed -
|
|
|
d0a457 |
- otherwise, leave it in */
|
|
|
d0a457 |
if (ec && inst) {
|
|
|
d0a457 |
- if (retval && cache_is_in_cache(&inst->inst_cache, ec)) {
|
|
|
d0a457 |
- CACHE_REMOVE(&inst->inst_cache, ec);
|
|
|
d0a457 |
- }
|
|
|
d0a457 |
CACHE_RETURN(&inst->inst_cache, &ec);
|
|
|
d0a457 |
}
|
|
|
d0a457 |
ec = NULL;
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
|
|
d0a457 |
index 61c3313c5..510d38f57 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
|
|
d0a457 |
@@ -55,6 +55,7 @@ void cache_unlock_entry(struct cache *cache, struct backentry *e);
|
|
|
d0a457 |
int cache_replace(struct cache *cache, void *oldptr, void *newptr);
|
|
|
d0a457 |
int cache_has_otherref(struct cache *cache, void *bep);
|
|
|
d0a457 |
int cache_is_in_cache(struct cache *cache, void *ptr);
|
|
|
d0a457 |
+void revert_cache(ldbm_instance *inst, struct timespec *start_time);
|
|
|
d0a457 |
|
|
|
d0a457 |
#ifdef CACHE_DEBUG
|
|
|
d0a457 |
void check_entry_cache(struct cache *cache, struct backentry *e);
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
|
|
|
d0a457 |
index bdad4e59e..eefe88724 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/slapi-plugin.h
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/slapi-plugin.h
|
|
|
d0a457 |
@@ -6853,6 +6853,12 @@ void slapi_operation_time_expiry(Slapi_Operation *o, time_t timeout, struct time
|
|
|
d0a457 |
*/
|
|
|
d0a457 |
slapi_timer_result slapi_timespec_expire_check(struct timespec *expire);
|
|
|
d0a457 |
|
|
|
d0a457 |
+/**
|
|
|
d0a457 |
+ * Returns the current system time as a hr clock
|
|
|
d0a457 |
+ *
|
|
|
d0a457 |
+ * \return timespec of the current monotonic time.
|
|
|
d0a457 |
+ */
|
|
|
d0a457 |
+struct timespec slapi_current_rel_time_hr(void);
|
|
|
d0a457 |
|
|
|
d0a457 |
/*
|
|
|
d0a457 |
* Plugin and parameter block related macros (remainder of this file).
|
|
|
d0a457 |
@@ -8296,6 +8302,15 @@ uint64_t slapi_atomic_decr_64(uint64_t *ptr, int memorder);
|
|
|
d0a457 |
|
|
|
d0a457 |
/* helper function */
|
|
|
d0a457 |
const char * fetch_attr(Slapi_Entry *e, const char *attrname, char *default_val);
|
|
|
d0a457 |
+/**
|
|
|
d0a457 |
+ * Diffs two timespects a - b into *diff. This is useful with
|
|
|
d0a457 |
+ * clock_monotonic to find time taken to perform operations.
|
|
|
d0a457 |
+ *
|
|
|
d0a457 |
+ * \param struct timespec a the "end" time.
|
|
|
d0a457 |
+ * \param struct timespec b the "start" time.
|
|
|
d0a457 |
+ * \param struct timespec c the difference.
|
|
|
d0a457 |
+ */
|
|
|
d0a457 |
+void slapi_timespec_diff(struct timespec *a, struct timespec *b, struct timespec *diff);
|
|
|
d0a457 |
|
|
|
d0a457 |
#ifdef __cplusplus
|
|
|
d0a457 |
}
|
|
|
d0a457 |
diff --git a/ldap/servers/slapd/time.c b/ldap/servers/slapd/time.c
|
|
|
d0a457 |
index 584bd1e63..2a3865858 100644
|
|
|
d0a457 |
--- a/ldap/servers/slapd/time.c
|
|
|
d0a457 |
+++ b/ldap/servers/slapd/time.c
|
|
|
d0a457 |
@@ -96,6 +96,32 @@ slapi_current_utc_time_hr(void)
|
|
|
d0a457 |
return ltnow;
|
|
|
d0a457 |
}
|
|
|
d0a457 |
|
|
|
d0a457 |
+struct timespec
|
|
|
d0a457 |
+slapi_current_rel_time_hr(void)
|
|
|
d0a457 |
+{
|
|
|
d0a457 |
+ struct timespec now;
|
|
|
d0a457 |
+ clock_gettime(CLOCK_MONOTONIC, &now;;
|
|
|
d0a457 |
+ return now;
|
|
|
d0a457 |
+}
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+void
|
|
|
d0a457 |
+slapi_timespec_diff(struct timespec *a, struct timespec *b, struct timespec *diff)
|
|
|
d0a457 |
+{
|
|
|
d0a457 |
+ /* Now diff the two */
|
|
|
d0a457 |
+ time_t sec = a->tv_sec - b->tv_sec;
|
|
|
d0a457 |
+ int32_t nsec = a->tv_nsec - b->tv_nsec;
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ if (nsec < 0) {
|
|
|
d0a457 |
+ /* It's negative so take one second */
|
|
|
d0a457 |
+ sec -= 1;
|
|
|
d0a457 |
+ /* And set nsec to to a whole value */
|
|
|
d0a457 |
+ nsec = 1000000000 - nsec;
|
|
|
d0a457 |
+ }
|
|
|
d0a457 |
+
|
|
|
d0a457 |
+ diff->tv_sec = sec;
|
|
|
d0a457 |
+ diff->tv_nsec = nsec;
|
|
|
d0a457 |
+}
|
|
|
d0a457 |
+
|
|
|
d0a457 |
time_t
|
|
|
d0a457 |
slapi_current_utc_time(void)
|
|
|
d0a457 |
{
|
|
|
d0a457 |
--
|
|
|
d0a457 |
2.21.0
|
|
|
d0a457 |
|