2 commits - ldap/servers
by Noriko Hosoi
ldap/servers/plugins/uiduniq/uid.c | 10 ++--------
ldap/servers/slapd/task.c | 10 ++++++----
2 files changed, 8 insertions(+), 12 deletions(-)
New commits:
commit 03f85ec06f6011e1573980e87319af2043e03948
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Jul 14 10:43:21 2014 -0700
Ticket #47859 - Coverity: 12692 & 12717
12717 - Resource leak - servers/plugins/uiduniq/uid.c
Description: In uniqueness_entry_to_config, the return value of
slapi_ch_calloc was checked if it was NULL or not. If NULL, the
function returned without releasing values. This patch remove the
NULL check and error return since the 2 arguments (i + 1, sizeof
(Slapi_DN *)) never be 0 or negative, thus slapi_ch_calloc has no
chance to return NULL. If allocation fails, it exits there.
Note: introduced by commit c66b5e9f83a81d75d8137e86b5e7631507592099
(ticket #47823)
https://fedorahosted.org/389/ticket/47859
Reviewed by rmeggins(a)redhat.com (Thank you, Rich!!)
diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c
index f4a9a8d..d1a1700 100644
--- a/ldap/servers/plugins/uiduniq/uid.c
+++ b/ldap/servers/plugins/uiduniq/uid.c
@@ -223,15 +223,9 @@ uniqueness_entry_to_config(Slapi_PBlock *pb, Slapi_Entry *config_entry)
/* Subtrees where uniqueness is tested */
values = slapi_entry_attr_get_charray(config_entry, ATTR_UNIQUENESS_SUBTREES);
if (values) {
-
-
for (i = 0; values && values[i]; i++);
- if ((tmp_config->subtrees = (Slapi_DN **) slapi_ch_calloc(i + 1, sizeof (Slapi_DN *))) == NULL) {
- slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Config info: Fail to allocate subtree array \n");
- rc = SLAPI_PLUGIN_FAILURE;
- goto done;
- }
-
+ /* slapi_ch_calloc never returns NULL unless the 2 args are 0 or negative. */
+ tmp_config->subtrees = (Slapi_DN **) slapi_ch_calloc(i + 1, sizeof (Slapi_DN *)));
/* copy the valid subtree DN into the config */
for (i = 0, nb_subtrees = 0; values && values[i]; i++) {
if (slapi_dn_syntax_check(pb, values[i], 1)) { /* syntax check failed */
commit 1e0dc9e20d794e803063f98f964e711d56898891
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Mon Jul 14 10:11:28 2014 -0700
Revert "Revert "Ticket #47835 - Coverity: 12687..12692""
This reverts commit 8247976f25c22799a31be08074cc150e07f5dcce.
Note: It turned out this patch is necessary even if Coverity filter is enhanced.
12692 - Use of untrusted string value
Description: lines read from the sysconfig reload task's attribute
sysconfigfile (e.g., /etc/sysconfig/dirsrv-localhost) could be tainted.
Check the end of the line more rigorously, and eliminate a chance to
overflow env_var and env_value by copying the characters from read
line.
Reviewed by rmeggins(a)redhat.com (Thanks, Rich!)
https://fedorahosted.org/389/ticket/47835
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 489266f..1089353 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -1954,6 +1954,8 @@ task_sysconfig_reload_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
if ( file != NULL ){
char line[4096];
char *s = NULL;
+ /* fgets() reads in at most one less than size characters */
+ char *end_of_line = line + sizeof(line) - 1;
if(logchanges){
LDAPDebug(LDAP_DEBUG_ANY, "sysconfig reload task: processing file (%s)\n",
@@ -1965,8 +1967,8 @@ task_sysconfig_reload_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
/* skip comments */
continue;
} else {
- char env_value[4096];
- char env_var[4096];
+ char env_value[sizeof(line)];
+ char env_var[sizeof(line)];
int using_setenv = 0;
int value_index = 0;
int start_value = 0;
@@ -2002,7 +2004,7 @@ task_sysconfig_reload_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
using_setenv = 1;
}
if(strncmp(s, "export ", 7) == 0){
- /* strip off "export " */
+ /* strip off "export " */
s = s + 7;
} else if(strncmp(s, "set ", 4) == 0){
/* strip off "set " */
@@ -2026,7 +2028,7 @@ task_sysconfig_reload_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
/*
* Start parsing the names and values
*/
- for (; s && *s; s++){
+ for (; s && (s < end_of_line) && *s; s++){
/*
* If using "setenv", allow the first space/tab only, and start on the env value
*/
9 years, 8 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Mark Reynolds
ldap/servers/slapd/back-ldbm/ldbm_search.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 7dc69db08c6949ec43a55058e2318158d023770c
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jul 14 10:47:52 2014 -0400
Ticket 47858 - Internal searches using OP_FLAG_REVERSE_CANDIDATE_ORDER can crash the server
Bug Description: If an internal search uses OP_FLAG_REVERSE_CANDIDATE_ORDER, and
the search fails tro find any candidates the server will crash.
Fix Description: Make sure we do not dereference a NULL sr_candidates pointer in
ldbm_search().
https://fedorahosted.org/389/ticket/47858
Reviewed by: rmeggins(Thanks!)
(cherry picked from commit e6cee31aa2beb6496df86490776f1f93d3a8348b)
(cherry picked from commit da318fa5f147e229069b13c0479fdf81ccc28213)
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index 46f7413..7d23580 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -1440,7 +1440,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
* search can enter this function multiple times, we need to keep track
* of our state, and only initialize sr_current once.
*/
- if(!op->o_reverse_search_state){
+ if(!op->o_reverse_search_state && sr->sr_candidates){
sr->sr_current = sr->sr_candidates->b_nids;
op->o_reverse_search_state = REV_STARTED;
}
9 years, 8 months
Branch '389-ds-base-1.3.1' - ldap/servers
by Mark Reynolds
ldap/servers/slapd/back-ldbm/ldbm_search.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 722117e12de543a3a66695e795e32f55435779ec
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jul 14 10:47:52 2014 -0400
Ticket 47858 - Internal searches using OP_FLAG_REVERSE_CANDIDATE_ORDER can crash the server
Bug Description: If an internal search uses OP_FLAG_REVERSE_CANDIDATE_ORDER, and
the search fails tro find any candidates the server will crash.
Fix Description: Make sure we do not dereference a NULL sr_candidates pointer in
ldbm_search().
https://fedorahosted.org/389/ticket/47858
Reviewed by: rmeggins(Thanks!)
(cherry picked from commit e6cee31aa2beb6496df86490776f1f93d3a8348b)
(cherry picked from commit da318fa5f147e229069b13c0479fdf81ccc28213)
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index 6dff1f5..f1375a5 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -1450,7 +1450,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
* search can enter this function multiple times, we need to keep track
* of our state, and only initialize sr_current once.
*/
- if(!op->o_reverse_search_state){
+ if(!op->o_reverse_search_state && sr->sr_candidates){
sr->sr_current = sr->sr_candidates->b_nids;
op->o_reverse_search_state = REV_STARTED;
}
9 years, 8 months
Branch '389-ds-base-1.3.2' - ldap/servers
by Mark Reynolds
ldap/servers/slapd/back-ldbm/ldbm_search.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit da318fa5f147e229069b13c0479fdf81ccc28213
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jul 14 10:47:52 2014 -0400
Ticket 47858 - Internal searches using OP_FLAG_REVERSE_CANDIDATE_ORDER can crash the server
Bug Description: If an internal search uses OP_FLAG_REVERSE_CANDIDATE_ORDER, and
the search fails tro find any candidates the server will crash.
Fix Description: Make sure we do not dereference a NULL sr_candidates pointer in
ldbm_search().
https://fedorahosted.org/389/ticket/47858
Reviewed by: rmeggins(Thanks!)
(cherry picked from commit e6cee31aa2beb6496df86490776f1f93d3a8348b)
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index 6dff1f5..f1375a5 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -1450,7 +1450,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
* search can enter this function multiple times, we need to keep track
* of our state, and only initialize sr_current once.
*/
- if(!op->o_reverse_search_state){
+ if(!op->o_reverse_search_state && sr->sr_candidates){
sr->sr_current = sr->sr_candidates->b_nids;
op->o_reverse_search_state = REV_STARTED;
}
9 years, 8 months
dirsrvtests/tickets
by Mark Reynolds
dirsrvtests/tickets/ticket47313_test.py | 3 +++
dirsrvtests/tickets/ticket47490_test.py | 5 ++++-
dirsrvtests/tickets/ticket47553_single_aci_test.py | 3 +++
dirsrvtests/tickets/ticket47560_test.py | 5 ++++-
dirsrvtests/tickets/ticket47573_test.py | 5 ++++-
dirsrvtests/tickets/ticket47619_test.py | 5 ++++-
dirsrvtests/tickets/ticket47653MMR_test.py | 5 ++++-
dirsrvtests/tickets/ticket47653_test.py | 5 ++++-
dirsrvtests/tickets/ticket47676_test.py | 5 ++++-
dirsrvtests/tickets/ticket47721_test.py | 5 ++++-
dirsrvtests/tickets/ticket47781_test.py | 3 +++
dirsrvtests/tickets/ticket47787_test.py | 5 ++++-
dirsrvtests/tickets/ticket47808_test.py | 5 ++++-
dirsrvtests/tickets/ticket47815_test.py | 3 +++
dirsrvtests/tickets/ticket47819_test.py | 3 +++
dirsrvtests/tickets/ticket47823_test.py | 3 +++
dirsrvtests/tickets/ticket47829_test.py | 5 ++++-
17 files changed, 62 insertions(+), 11 deletions(-)
New commits:
commit 84477daf5b7b2b7614d8b798cd2184dada4d379d
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jul 14 12:37:11 2014 -0400
Ticket 47855 - clear tmp directory at the start of each test
Description: Clear out the tmp directory before starting each test.
https://fedorahosted.org/389/ticket/47855
Reviewed by: nhosoi(Thanks!)
diff --git a/dirsrvtests/tickets/ticket47313_test.py b/dirsrvtests/tickets/ticket47313_test.py
index 370dfc6..a946f08 100644
--- a/dirsrvtests/tickets/ticket47313_test.py
+++ b/dirsrvtests/tickets/ticket47313_test.py
@@ -109,6 +109,9 @@ def topology(request):
standalone.stop(timeout=10)
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
#
# Here we have standalone instance up and running
diff --git a/dirsrvtests/tickets/ticket47490_test.py b/dirsrvtests/tickets/ticket47490_test.py
index eee4cca..51511b9 100644
--- a/dirsrvtests/tickets/ticket47490_test.py
+++ b/dirsrvtests/tickets/ticket47490_test.py
@@ -272,7 +272,10 @@ def topology(request):
consumer.stop(timeout=10)
consumer.backupfile = consumer.backupFS()
consumer.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have two instances master and consumer
# with replication working. Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47553_single_aci_test.py b/dirsrvtests/tickets/ticket47553_single_aci_test.py
index cb62ee1..5911044 100644
--- a/dirsrvtests/tickets/ticket47553_single_aci_test.py
+++ b/dirsrvtests/tickets/ticket47553_single_aci_test.py
@@ -234,6 +234,9 @@ def topology(request):
master2.stop(timeout=10)
master2.backupfile = master2.backupFS()
master2.start(timeout=10)
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
#
# Here we have two instances master and consumer
diff --git a/dirsrvtests/tickets/ticket47560_test.py b/dirsrvtests/tickets/ticket47560_test.py
index 67d83e8..0b7e436 100644
--- a/dirsrvtests/tickets/ticket47560_test.py
+++ b/dirsrvtests/tickets/ticket47560_test.py
@@ -106,7 +106,10 @@ def topology(request):
standalone.stop(timeout=10)
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have standalone instance up and running
# Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47573_test.py b/dirsrvtests/tickets/ticket47573_test.py
index a85fc10..8922426 100644
--- a/dirsrvtests/tickets/ticket47573_test.py
+++ b/dirsrvtests/tickets/ticket47573_test.py
@@ -273,7 +273,10 @@ def topology(request):
consumer.stop(timeout=10)
consumer.backupfile = consumer.backupFS()
consumer.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have two instances master and consumer
# with replication working. Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47619_test.py b/dirsrvtests/tickets/ticket47619_test.py
index a8cacf3..945f68a 100644
--- a/dirsrvtests/tickets/ticket47619_test.py
+++ b/dirsrvtests/tickets/ticket47619_test.py
@@ -203,7 +203,10 @@ def topology(request):
consumer.stop(timeout=10)
consumer.backupfile = consumer.backupFS()
consumer.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have two instances master and consumer
# with replication working. Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47653MMR_test.py b/dirsrvtests/tickets/ticket47653MMR_test.py
index 5d86888..5a3f095 100644
--- a/dirsrvtests/tickets/ticket47653MMR_test.py
+++ b/dirsrvtests/tickets/ticket47653MMR_test.py
@@ -237,7 +237,10 @@ def topology(request):
master2.stop(timeout=10)
master2.backupfile = master2.backupFS()
master2.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have two instances master and consumer
# with replication working. Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47653_test.py b/dirsrvtests/tickets/ticket47653_test.py
index 9f4e757..e0dedbc 100644
--- a/dirsrvtests/tickets/ticket47653_test.py
+++ b/dirsrvtests/tickets/ticket47653_test.py
@@ -134,7 +134,10 @@ def topology(request):
standalone.stop(timeout=10)
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have standalone instance up and running
# Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47676_test.py b/dirsrvtests/tickets/ticket47676_test.py
index 1d7f0b1..be7e626 100644
--- a/dirsrvtests/tickets/ticket47676_test.py
+++ b/dirsrvtests/tickets/ticket47676_test.py
@@ -249,7 +249,10 @@ def topology(request):
master2.stop(timeout=10)
master2.backupfile = master2.backupFS()
master2.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have two instances master and consumer
# with replication working. Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47721_test.py b/dirsrvtests/tickets/ticket47721_test.py
index 0d6cd8b..955d4bc 100644
--- a/dirsrvtests/tickets/ticket47721_test.py
+++ b/dirsrvtests/tickets/ticket47721_test.py
@@ -255,7 +255,10 @@ def topology(request):
master2.stop(timeout=10)
master2.backupfile = master2.backupFS()
master2.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have two instances master and consumer
# with replication working. Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47781_test.py b/dirsrvtests/tickets/ticket47781_test.py
index 8eb68ba..9b58ef3 100644
--- a/dirsrvtests/tickets/ticket47781_test.py
+++ b/dirsrvtests/tickets/ticket47781_test.py
@@ -107,6 +107,9 @@ def topology(request):
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have standalone instance up and running
# Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47787_test.py b/dirsrvtests/tickets/ticket47787_test.py
index d9d3ca9..ecb008c 100644
--- a/dirsrvtests/tickets/ticket47787_test.py
+++ b/dirsrvtests/tickets/ticket47787_test.py
@@ -237,7 +237,10 @@ def topology(request):
master2.stop(timeout=10)
master2.backupfile = master2.backupFS()
master2.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have two instances master and consumer
# with replication working. Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47808_test.py b/dirsrvtests/tickets/ticket47808_test.py
index d87dafc..5a16a1f 100644
--- a/dirsrvtests/tickets/ticket47808_test.py
+++ b/dirsrvtests/tickets/ticket47808_test.py
@@ -110,7 +110,10 @@ def topology(request):
standalone.stop(timeout=10)
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have standalone instance up and running
# Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47815_test.py b/dirsrvtests/tickets/ticket47815_test.py
index 7c8f275..9d09240 100644
--- a/dirsrvtests/tickets/ticket47815_test.py
+++ b/dirsrvtests/tickets/ticket47815_test.py
@@ -106,6 +106,9 @@ def topology(request):
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have standalone instance up and running
# Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47819_test.py b/dirsrvtests/tickets/ticket47819_test.py
index 9611f07..7b6f2d5 100644
--- a/dirsrvtests/tickets/ticket47819_test.py
+++ b/dirsrvtests/tickets/ticket47819_test.py
@@ -107,6 +107,9 @@ def topology(request):
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=60)
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
# Here we have standalone instance up and running
# Either coming from a backup recovery
# or from a fresh (re)init
diff --git a/dirsrvtests/tickets/ticket47823_test.py b/dirsrvtests/tickets/ticket47823_test.py
index 2322e71..f4d3695 100644
--- a/dirsrvtests/tickets/ticket47823_test.py
+++ b/dirsrvtests/tickets/ticket47823_test.py
@@ -140,6 +140,9 @@ def topology(request):
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have standalone instance up and running
# Either coming from a backup recovery
diff --git a/dirsrvtests/tickets/ticket47829_test.py b/dirsrvtests/tickets/ticket47829_test.py
index 8cbfd32..ab8be77 100644
--- a/dirsrvtests/tickets/ticket47829_test.py
+++ b/dirsrvtests/tickets/ticket47829_test.py
@@ -151,7 +151,10 @@ def topology(request):
standalone.stop(timeout=10)
standalone.backupfile = standalone.backupFS()
standalone.start(timeout=10)
-
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
#
# Here we have standalone instance up and running
# Either coming from a backup recovery
9 years, 8 months
aclocal.m4 config.guess config.sub dirsrvtests/data dirsrvtests/tickets dirsrvtests/tmp ldap/admin ldap/ldif ldap/schema ldap/servers Makefile.am Makefile.in
by Mark Reynolds
Makefile.am | 1
Makefile.in | 1
aclocal.m4 | 15
config.guess | 151 ++----
config.sub | 30 -
dirsrvtests/data/README | 11
dirsrvtests/tickets/ticket47819_test.py | 345 +++++++++++++++
dirsrvtests/tmp/README | 10
ldap/admin/src/scripts/50nstombstonecsn.ldif | 7
ldap/ldif/template-dse.ldif.in | 7
ldap/schema/01core389.ldif | 6
ldap/servers/plugins/replication/repl5.h | 4
ldap/servers/plugins/replication/repl5_replica.c | 67 ++-
ldap/servers/plugins/replication/repl5_replica_config.c | 60 ++
ldap/servers/plugins/replication/repl_globals.c | 1
ldap/servers/plugins/replication/urp_tombstone.c | 2
ldap/servers/slapd/back-ldbm/import-threads.c | 39 +
ldap/servers/slapd/back-ldbm/index.c | 13
ldap/servers/slapd/back-ldbm/ldbm_add.c | 59 ++
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 79 +++
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 15
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 1
ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 63 ++
ldap/servers/slapd/entrywsi.c | 23 +
ldap/servers/slapd/mapping_tree.c | 11
ldap/servers/slapd/slapi-plugin.h | 2
ldap/servers/slapd/slapi-private.h | 4
ldap/servers/slapd/task.c | 352 +++++++++++++++-
28 files changed, 1215 insertions(+), 164 deletions(-)
New commits:
commit 0dfe006eef6c2634af89dfc3e5606c590e3fc663
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jul 14 12:04:26 2014 -0400
Ticket 47819 - Improve tombstone purging performance
Precise Tombstone Purging
A new attribute was added to the nsTombstone objectclass: nsTombstoneCSN,
and a new system equality index was created for nsTombstoneCSN. When
enabled the tombstone purging thread will use a range search to retrieve
all the tombstones that need to be purged. Previously we just searched
on "objectclass=nsTombstone", which can be very inefficient if there are
thousands of tombstones, but only a few tombstones that actually need to
be purged.
Migration and Mixed Environments:
Whether or not precise tombstone purging is enabled, the new index is maintained.
The only thing that needs to be done prior to enabling precise purging is
to re-import the database, or run the fixup task. During replication any
replicated tombstone that is missing the nsTombstoneCSN attribute will have
it added. During an import, any tombstone missing nsTombstoneCSN will also
have it added to the entry.
Fixup Task:
Specific backend names or suffix DN's can be specified. If no backend or
suffix is specified then all backends are processed.
dn: cn=fixem,cn=fixup tombstones,cn=tasks,cn=config
objectclass: top
objectclass: extensibleObject
cn: fixem
backend: userRoot
suffix: dc=redhat,dc=com
suffix: o=test.com
stripcsn: yes --> hidden option used for verifying the fixup tasks
works(this is used by lib389)
Upgrade:
Added 50nstombstonecsn.ldif which adds nsTombstoneCSN to the system indexes
during an upgrade
Tombstone Purging:
New configuration setting in replica entry:
dn: cn=replica,cn=dc\3Dexample\2Cdc\3Dcom,cn=mapping tree,cn=config
nsds5ReplicaPreciseTombstonePurging: on
When enabled, a range search is used to find the exact entries that need to
be removed:
"(&(nsTombstoneCSN<=PURGE_CSN)(objectclass=nsTombstone))"
https://fedorahosted.org/389/ticket/47819
Jenkins: passed
Reviewed by: rmeggins(Thanks!)
diff --git a/Makefile.am b/Makefile.am
index a2a1fa1..9c75c3a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -542,6 +542,7 @@ update_DATA = ldap/admin/src/scripts/exampleupdate.pl \
ldap/admin/src/scripts/50acctusabilityplugin.ldif \
ldap/admin/src/scripts/50automemberplugin.ldif \
ldap/admin/src/scripts/50memberofindex.ldif \
+ ldap/admin/src/scripts/50nstombstonecsn.ldif \
ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif \
ldap/admin/src/scripts/50managedentriesplugin.ldif \
ldap/admin/src/scripts/50memberofplugin.ldif \
diff --git a/Makefile.in b/Makefile.in
index 3c4f99e..b2a97e4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1950,6 +1950,7 @@ update_DATA = ldap/admin/src/scripts/exampleupdate.pl \
ldap/admin/src/scripts/50acctusabilityplugin.ldif \
ldap/admin/src/scripts/50automemberplugin.ldif \
ldap/admin/src/scripts/50memberofindex.ldif \
+ ldap/admin/src/scripts/50nstombstonecsn.ldif \
ldap/admin/src/scripts/50bitstringsyntaxplugin.ldif \
ldap/admin/src/scripts/50managedentriesplugin.ldif \
ldap/admin/src/scripts/50memberofplugin.ldif \
diff --git a/aclocal.m4 b/aclocal.m4
index 8136dd1..7afd01a 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -220,6 +220,21 @@ m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_NOARCH_INSTALLDIR
+
+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])# PKG_CHECK_VAR
+
# Copyright (C) 2002-2013 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
diff --git a/config.guess b/config.guess
index b79252d..1804e9f 100755
--- a/config.guess
+++ b/config.guess
@@ -1,8 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-# Copyright 1992-2013 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012, 2013 Free Software Foundation, Inc.
-timestamp='2013-06-10'
+timestamp='2012-12-29'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -24,7 +26,7 @@ timestamp='2013-06-10'
# program. This Exception is an additional permission under section 7
# of the GNU General Public License, version 3 ("GPLv3").
#
-# Originally written by Per Bothner.
+# Originally written by Per Bothner.
#
# You can get the latest version of this script from:
# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.gu...
@@ -50,7 +52,9 @@ version="\
GNU config.guess ($timestamp)
Originally written by Per Bothner.
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+2012, 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -132,27 +136,6 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-case "${UNAME_SYSTEM}" in
-Linux|GNU|GNU/*)
- # If the system lacks a compiler, then just pick glibc.
- # We could probably try harder.
- LIBC=gnu
-
- eval $set_cc_for_build
- cat <<-EOF > $dummy.c
- #include <features.h>
- #if defined(__UCLIBC__)
- LIBC=uclibc
- #elif defined(__dietlibc__)
- LIBC=dietlibc
- #else
- LIBC=gnu
- #endif
- EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
- ;;
-esac
-
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
@@ -874,21 +857,21 @@ EOF
exit ;;
*:GNU:*:*)
# the GNU system
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
exit ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit ;;
aarch64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
aarch64_be:Linux:*:*)
UNAME_MACHINE=aarch64_be
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -901,54 +884,59 @@ EOF
EV68*) UNAME_MACHINE=alphaev68 ;;
esac
objdump --private-headers /bin/sh | grep -q ld.so.1
- if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- arc:Linux:*:* | arceb:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
exit ;;
arm*:Linux:*:*)
eval $set_cc_for_build
if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_EABI__
then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
else
if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
| grep -q __ARM_PCS_VFP
then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
else
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
fi
fi
exit ;;
avr32*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
cris:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
crisv32:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ echo ${UNAME_MACHINE}-axis-linux-gnu
exit ;;
frv:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
hexagon:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
i*86:Linux:*:*)
- echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
exit ;;
ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
m32r*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
mips:Linux:*:* | mips64:Linux:*:*)
eval $set_cc_for_build
@@ -967,63 +955,54 @@ EOF
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
;;
- or1k:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
or32:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
padre:Linux:*:*)
- echo sparc-unknown-linux-${LIBC}
+ echo sparc-unknown-linux-gnu
exit ;;
parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-${LIBC}
+ echo hppa64-unknown-linux-gnu
exit ;;
parisc:Linux:*:* | hppa:Linux:*:*)
# Look for CPU level
case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
- PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
- *) echo hppa-unknown-linux-${LIBC} ;;
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
esac
exit ;;
ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-${LIBC}
+ echo powerpc64-unknown-linux-gnu
exit ;;
ppc:Linux:*:*)
- echo powerpc-unknown-linux-${LIBC}
- exit ;;
- ppc64le:Linux:*:*)
- echo powerpc64le-unknown-linux-${LIBC}
- exit ;;
- ppcle:Linux:*:*)
- echo powerpcle-unknown-linux-${LIBC}
+ echo powerpc-unknown-linux-gnu
exit ;;
s390:Linux:*:* | s390x:Linux:*:*)
- echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ echo ${UNAME_MACHINE}-ibm-linux
exit ;;
sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
tile*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ echo ${UNAME_MACHINE}-dec-linux-gnu
exit ;;
x86_64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
xtensa*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
exit ;;
i*86:DYNIX/ptx:4*:*)
# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
@@ -1256,21 +1235,19 @@ EOF
exit ;;
*:Darwin:*:*)
UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- eval $set_cc_for_build
- if test "$UNAME_PROCESSOR" = unknown ; then
- UNAME_PROCESSOR=powerpc
- fi
- if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
- then
- case $UNAME_PROCESSOR in
- i386) UNAME_PROCESSOR=x86_64 ;;
- powerpc) UNAME_PROCESSOR=powerpc64 ;;
- esac
- fi
- fi
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
exit ;;
*:procnto*:*:* | *:QNX:[0123456789]*:*)
diff --git a/config.sub b/config.sub
index c765b34..52f04bc 100755
--- a/config.sub
+++ b/config.sub
@@ -1,8 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
-# Copyright 1992-2013 Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+# 2011, 2012, 2013 Free Software Foundation, Inc.
-timestamp='2013-04-24'
+timestamp='2012-12-29'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -68,7 +70,9 @@ Report bugs and patches to <config-patches(a)gnu.org>."
version="\
GNU config.sub ($timestamp)
-Copyright 1992-2013 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+2012, 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -252,7 +256,7 @@ case $basic_machine in
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
- | arc | arceb \
+ | arc \
| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
| avr | avr32 \
| be32 | be64 \
@@ -286,17 +290,16 @@ case $basic_machine in
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| moxie \
| mt \
| msp430 \
| nds32 | nds32le | nds32be \
- | nios | nios2 | nios2eb | nios2el \
+ | nios | nios2 \
| ns16k | ns32k \
| open8 \
- | or1k | or32 \
+ | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle \
| pyramid \
@@ -366,7 +369,7 @@ case $basic_machine in
| aarch64-* | aarch64_be-* \
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
| avr-* | avr32-* \
| be32-* | be64-* \
@@ -404,13 +407,12 @@ case $basic_machine in
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipsr5900-* | mipsr5900el-* \
| mipstx39-* | mipstx39el-* \
| mmix-* \
| mt-* \
| msp430-* \
| nds32-* | nds32le-* | nds32be-* \
- | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | nios-* | nios2-* \
| none-* | np1-* | ns16k-* | ns32k-* \
| open8-* \
| orion-* \
@@ -1352,7 +1354,7 @@ case $os in
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
| -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
- | -sym* | -kopensolaris* | -plan9* \
+ | -sym* | -kopensolaris* \
| -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
| -aos* | -aros* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
@@ -1498,6 +1500,9 @@ case $os in
-aros*)
os=-aros
;;
+ -kaos*)
+ os=-kaos
+ ;;
-zvmoe)
os=-zvmoe
;;
@@ -1589,9 +1594,6 @@ case $basic_machine in
mips*-*)
os=-elf
;;
- or1k-*)
- os=-elf
- ;;
or32-*)
os=-coff
;;
diff --git a/dirsrvtests/data/README b/dirsrvtests/data/README
new file mode 100644
index 0000000..4261f92
--- /dev/null
+++ b/dirsrvtests/data/README
@@ -0,0 +1,11 @@
+DATA DIRECTORY README
+
+This directory is used for storing LDIF files used by the dirsrvtests scripts.
+This directory can be retrieved via getDir() from the DirSrv class.
+
+Example:
+
+ data_dir_path = topology.standalone.getDir(__file__, DATA_DIR)
+
+ ldif_file = data_dir_path + "ticket44444/1000entries.ldif"
+
diff --git a/dirsrvtests/tickets/ticket47819_test.py b/dirsrvtests/tickets/ticket47819_test.py
new file mode 100644
index 0000000..9611f07
--- /dev/null
+++ b/dirsrvtests/tickets/ticket47819_test.py
@@ -0,0 +1,345 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import socket
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from constants import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ At the beginning, It may exists a standalone instance.
+ It may also exists a backup for the standalone instance.
+
+ Principle:
+ If standalone instance exists:
+ restart it
+ If backup of standalone exists:
+ create/rebind to standalone
+
+ restore standalone instance from backup
+ else:
+ Cleanup everything
+ remove instance
+ remove backup
+ Create instance
+ Create backup
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the backups
+ backup_standalone = standalone.checkBackupFS()
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+ if instance_standalone:
+ # assuming the instance is already stopped, just wait 5 sec max
+ standalone.stop(timeout=5)
+ standalone.start(timeout=60)
+
+ if backup_standalone:
+ # The backup exist, assuming it is correct
+ # we just re-init the instance with it
+ if not instance_standalone:
+ standalone.create()
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # restore standalone instance from backup
+ standalone.stop(timeout=10)
+ standalone.restoreFS(backup_standalone)
+ standalone.start(timeout=60)
+
+ else:
+ # We should be here only in two conditions
+ # - This is the first time a test involve standalone instance
+ # - Something weird happened (instance/backup destroyed)
+ # so we discard everything and recreate all
+
+ # Remove the backup. So even if we have a specific backup file
+ # (e.g backup_standalone) we clear backup that an instance may have created
+ if backup_standalone:
+ standalone.clearBackupFS()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # Time to create the backups
+ standalone.stop(timeout=10)
+ standalone.backupfile = standalone.backupFS()
+ standalone.start(timeout=60)
+
+ # Here we have standalone instance up and running
+ # Either coming from a backup recovery
+ # or from a fresh (re)init
+ # Time to return the topology
+ return TopologyStandalone(standalone)
+
+
+def test_ticket47819(topology):
+ """
+ Testing precise tombstone purging:
+ [1] Make sure "nsTombstoneCSN" is added to new tombstones
+ [2] Make sure an import of a replication ldif adds "nsTombstoneCSN"
+ to old tombstones
+ [4] Test fixup task
+ [3] Make sure tombstone purging works
+ """
+
+ log.info('Testing Ticket 47819 - Test precise tombstone purging')
+
+ #
+ # Setup Replication
+ #
+ log.info('Setting up replication...')
+ topology.standalone.replica.enableReplication(suffix=DEFAULT_SUFFIX, role=REPLICAROLE_MASTER,
+ replicaId=REPLICAID_MASTER_1)
+
+ #
+ # Part 1 create a tombstone entry and make sure nsTombstoneCSN is added
+ #
+ log.info('Part 1: Add and then delete an entry to create a tombstone...')
+
+ try:
+ topology.standalone.add_s(Entry(('cn=entry1,dc=example,dc=com', {
+ 'objectclass': 'top person'.split(),
+ 'sn': 'user',
+ 'cn': 'entry1'})))
+ except ldap.LDAPError, e:
+ log.error('Failed to add entry: ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.delete_s('cn=entry1,dc=example,dc=com')
+ except ldap.LDAPError, e:
+ log.error('Failed to delete entry: ' + e.message['desc'])
+ assert False
+
+ log.info('Search for tombstone entries...')
+ try:
+ entries = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+ '(&(nsTombstoneCSN=*)(objectclass=nsTombstone))')
+ if not entries:
+ log.fatal('Search failed to the new tombstone(nsTombstoneCSN is probably missing).')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Search failed: ' + e.message['desc'])
+ assert False
+
+ log.info('Part 1 - passed')
+
+ #
+ # Part 2 - import ldif with tombstones missing 'nsTombstoneCSN'
+ #
+ # First, export the replication ldif, edit the file(remove nstombstonecsn),
+ # and reimport it.
+ #
+ log.info('Part 2: Exporting replication ldif...')
+
+ # Get the the full path and name for our LDIF we will be exporting
+ ldif_file = topology.standalone.getDir(__file__, TMP_DIR) + "export.ldif"
+
+ args = {EXPORT_REPL_INFO: True,
+ TASK_WAIT: True}
+ exportTask = Tasks(topology.standalone)
+ try:
+ exportTask.exportLDIF(DEFAULT_SUFFIX, None, ldif_file, args)
+ except ValueError:
+ assert False
+
+ # open the ldif file, get the lines, then rewrite the file
+ ldif = open(ldif_file, "r")
+ lines = ldif.readlines()
+ ldif.close()
+
+ ldif = open(ldif_file, "w")
+ for line in lines:
+ if not line.lower().startswith('nstombstonecsn'):
+ ldif.write(line)
+ ldif.close()
+
+ # import the new ldif file
+ log.info('Import replication LDIF file...')
+ importTask = Tasks(topology.standalone)
+ args = {TASK_WAIT: True}
+ try:
+ importTask.importLDIF(DEFAULT_SUFFIX, None, ldif_file, args)
+ os.remove(ldif_file)
+ except ValueError:
+ os.remove(ldif_file)
+ assert False
+
+ # Search for the tombstone again
+ log.info('Search for tombstone entries...')
+ try:
+ entries = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+ '(&(nsTombstoneCSN=*)(objectclass=nsTombstone))')
+ if not entries:
+ log.fatal('Search failed to fine the new tombstone(nsTombstoneCSN is probably missing).')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Search failed: ' + e.message['desc'])
+ assert False
+
+ log.info('Part 2 - passed')
+
+ #
+ # Part 3 - test fixup task
+ #
+ log.info('Part 4: test the fixup task')
+
+ # Run fixup task using the strip option. This removes nsTombstoneCSN
+ # so we can test if the fixup task works.
+ args = {TASK_WAIT: True,
+ TASK_TOMB_STRIP: True}
+ fixupTombTask = Tasks(topology.standalone)
+ try:
+ fixupTombTask.fixupTombstones(DEFAULT_BENAME, args)
+ except:
+ assert False
+
+ # Search for tombstones with nsTombstoneCSN - better not find any
+ log.info('Search for tombstone entries...')
+ try:
+ entries = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+ '(&(nsTombstoneCSN=*)(objectclass=nsTombstone))')
+ if entries:
+ log.fatal('Search found tombstones with nsTombstoneCSN')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Search failed: ' + e.message['desc'])
+ assert False
+
+ # Now run the fixup task
+ args = {TASK_WAIT: True}
+ fixupTombTask = Tasks(topology.standalone)
+ try:
+ fixupTombTask.fixupTombstones(DEFAULT_BENAME, args)
+ except:
+ assert False
+
+ # Search for tombstones with nsTombstoneCSN - better find some
+ log.info('Search for tombstone entries...')
+ try:
+ entries = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+ '(&(nsTombstoneCSN=*)(objectclass=nsTombstone))')
+ if not entries:
+ log.fatal('Search did not find any fixed-up tombstones')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Search failed: ' + e.message['desc'])
+ assert False
+
+ log.info('Part 3 - passed')
+
+ #
+ # Part 4 - Test tombstone purging
+ #
+ log.info('Part 4: test tombstone purging...')
+
+ args = {REPLICA_PRECISE_PURGING: 'on',
+ REPLICA_PURGE_DELAY: '5',
+ REPLICA_PURGE_INTERVAL: '5'}
+ try:
+ topology.standalone.replica.setProperties(DEFAULT_SUFFIX, None, None, args)
+ except:
+ log.fatal('Failed to configure replica')
+ assert False
+
+ # Wait for the interval to pass
+ log.info('Wait for tombstone purge interval to pass...')
+ time.sleep(6)
+
+ # Add an entry to trigger replication
+ log.info('Perform an update to help trigger tombstone purging...')
+ try:
+ topology.standalone.add_s(Entry(('cn=test_entry,dc=example,dc=com', {
+ 'objectclass': 'top person'.split(),
+ 'sn': 'user',
+ 'cn': 'entry1'})))
+ except ldap.LDAPError, e:
+ log.error('Failed to add entry: ' + e.message['desc'])
+ assert False
+
+ # Wait for the interval to pass again
+ log.info('Wait for tombstone purge interval to pass again...')
+ time.sleep(10)
+
+ # search for tombstones, there should be none
+ log.info('Search for tombstone entries...')
+ try:
+ entries = topology.standalone.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
+ '(&(nsTombstoneCSN=*)(objectclass=nsTombstone))')
+ if entries:
+ log.fatal('Search unexpectedly found tombstones')
+ assert False
+ except ldap.LDAPError, e:
+ log.fatal('Search failed: ' + e.message['desc'])
+ assert False
+
+ log.info('Part 4 - passed')
+
+ #
+ # If we got here we passed!
+ #
+ log.info('Ticket47819 Test - Passed')
+
+
+def test_ticket47819_final(topology):
+ topology.standalone.stop(timeout=10)
+
+
+def run_isolated():
+ '''
+ run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
+ To run isolated without py.test, you need to
+ - edit this file and comment '@pytest.fixture' line before 'topology' function.
+ - set the installation prefix
+ - run this program
+ '''
+ global installation_prefix
+ installation_prefix = None
+
+ topo = topology(True)
+ test_ticket47819(topo)
+
+if __name__ == '__main__':
+ run_isolated()
\ No newline at end of file
diff --git a/dirsrvtests/tmp/README b/dirsrvtests/tmp/README
new file mode 100644
index 0000000..0e8f416
--- /dev/null
+++ b/dirsrvtests/tmp/README
@@ -0,0 +1,10 @@
+TMP DIRECTORY README
+
+This directory is used to store files(LDIFs, etc) that are created during the ticket script runtime. The script is also responsible for removing any files it places in this directory. This directory can be retrieved via getDir() from the DirSrv class.
+
+Example:
+
+ tmp_dir_path = topology.standalone.getDir(__file__, TMP_DIR)
+
+ new_ldif = tmp_dir_path + "export.ldif"
+
diff --git a/ldap/admin/src/scripts/50nstombstonecsn.ldif b/ldap/admin/src/scripts/50nstombstonecsn.ldif
new file mode 100644
index 0000000..871124b
--- /dev/null
+++ b/ldap/admin/src/scripts/50nstombstonecsn.ldif
@@ -0,0 +1,7 @@
+dn: cn=nsTombstoneCSN,cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config
+changetype: add
+objectclass: top
+objectclass: nsIndex
+cn: nsTombstoneCSN
+nssystemindex: true
+nsindextype: eq
\ No newline at end of file
diff --git a/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in
index c613c23..9f6a45c 100644
--- a/ldap/ldif/template-dse.ldif.in
+++ b/ldap/ldif/template-dse.ldif.in
@@ -967,6 +967,13 @@ cn: uniquemember
nssystemindex: false
nsindextype: eq
+dn: cn=nsTombstoneCSN,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config
+objectclass: top
+objectclass: nsIndex
+cn: nsTombstoneCSN
+nssystemindex: true
+nsindextype: eq
+
dn: cn=monitor, cn=ldbm database, cn=plugins, cn=config
objectclass: top
objectclass: extensibleObject
diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
index 6199277..0e0e75f 100644
--- a/ldap/schema/01core389.ldif
+++ b/ldap/schema/01core389.ldif
@@ -299,6 +299,8 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2304 NAME 'nsslapd-dynamic-plugins' DESC
attributeTypes: ( 2.16.840.1.113730.3.1.2305 NAME 'nsslapd-moddn-aci' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2306 NAME 'nsslapd-return-default-opattr' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2307 NAME 'nsslapd-allow-hashed-passwords' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2308 NAME 'nstombstonecsn' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2309 NAME 'nsds5ReplicaPreciseTombstonePurging' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
#
# objectclasses
#
@@ -308,8 +310,8 @@ objectClasses: ( 2.16.840.1.113730.3.2.44 NAME 'nsIndex' DESC 'Netscape defined
objectClasses: ( 2.16.840.1.113730.3.2.109 NAME 'nsBackendInstance' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.104 NAME 'nsContainer' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top MUST ( nsDS5ReplicaRoot $ nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaBackoffMin $ nsds5ReplicaBackoffMax ) X-ORIGIN 'Netscape Directory Server' )
-objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top MUST ( nsDS5ReplicaRoot $ nsDS5ReplicaId ) MAY (cn $ nsds5ReplicaPreciseTombstonePurging $ nsds5ReplicaCleanRUV $ nsds5ReplicaAbortCleanRUV $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer $ nsds5ReplicaProtocolTimeout $ nsds5ReplicaBackoffMin $ nsds5ReplicaBackoffMax ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nstombstonecsn $ nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsds5ReplicaCleanRUVNotified $ nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicatedAttributeListTotal $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5ReplicaEnabled $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5ReplicaStripAttrs $ nsds5replicaSessionPauseTime $ nsds5ReplicaProtocolTimeout ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) MAY ( nsSaslMapPriority ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index a66e7a0..86c77ce 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -173,6 +173,7 @@ extern const char *type_nsds5ReplicaStripAttrs;
extern const char *type_replicaProtocolTimeout;
extern const char *type_replicaBackoffMin;
extern const char *type_replicaBackoffMax;
+extern const char *type_replicaPrecisePurge;
/* Attribute names for windows replication agreements */
extern const char *type_nsds7WindowsReplicaArea;
@@ -595,7 +596,6 @@ void replica_destroy_dn_hash ();
int replica_add_by_dn (const char *dn);
int replica_delete_by_dn (const char *dn);
int replica_is_being_configured (const char *dn);
-const CSN * _get_deletion_csn(Slapi_Entry *e);
int legacy_consumer_init_referrals (Replica *r);
void consumer5_set_mapping_tree_state_for_replica(const Replica *r, RUV *supplierRuv);
Object *replica_get_for_backend (const char *be_name);
@@ -619,6 +619,8 @@ void replica_set_backoff_max(Replica *r, PRUint64 max);
int replica_get_agmt_count(Replica *r);
void replica_incr_agmt_count(Replica *r);
void replica_decr_agmt_count(Replica *r);
+PRUint64 replica_get_precise_purging(Replica *r);
+void replica_set_precise_purging(Replica *r, PRUint64 on_off);
/* The functions below handles the state flag */
/* Current internal state flags */
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index 45122ef..b6e7be0 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -95,6 +95,7 @@ struct replica {
Slapi_Counter *protocol_timeout;/* protocol shutdown timeout */
Slapi_Counter *backoff_min; /* backoff retry minimum */
Slapi_Counter *backoff_max; /* backoff retry maximum */
+ Slapi_Counter *precise_purging; /* Enable precise tombstone purging */
PRUint64 agmt_count; /* Number of agmts */
};
@@ -1086,7 +1087,7 @@ char *replica_get_generation (const Replica *r)
if (r && r->repl_ruv)
{
replica_lock(r->repl_lock);
-
+
if (rc == 0)
gen = ruv_get_replica_generation ((RUV*)object_get_data (r->repl_ruv));
@@ -1789,6 +1790,7 @@ _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
Slapi_Attr *a = NULL;
Slapi_Attr *attr;
CSNGen *gen;
+ char *precise_purging = NULL;
char buf [SLAPI_DSE_RETURNTEXT_SIZE];
char *errormsg = errortext? errortext : buf;
char *val;
@@ -1874,6 +1876,25 @@ _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
slapi_counter_set_value(r->protocol_timeout, ptimeout);
}
+ /* check for precise tombstone purging */
+ precise_purging = slapi_entry_attr_get_charptr(e, type_replicaPrecisePurge);
+ if(precise_purging){
+ if (strcasecmp(precise_purging, "on") == 0){
+ slapi_counter_set_value(r->precise_purging, 1);
+ } else if (strcasecmp(precise_purging, "off") == 0){
+ slapi_counter_set_value(r->precise_purging, 0);
+ } else{
+ /* Invalid value */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Invalid value for %s: %s Using default value (off)\n",
+ type_replicaPrecisePurge, precise_purging);
+ slapi_counter_set_value(r->precise_purging, 0);
+ }
+ slapi_ch_free_string(&precise_purging);
+ } else {
+ slapi_counter_set_value(r->precise_purging, 0);
+ }
+
/* get replica flags */
r->repl_flags = slapi_entry_attr_get_ulong(e, attr_flags);
@@ -2862,7 +2883,7 @@ replica_ruv_smods_for_op( Slapi_PBlock *pb, char **uniqueid, Slapi_Mods **smods
const CSN *
-_get_deletion_csn(Slapi_Entry *e)
+entry_get_deletion_csn(Slapi_Entry *e)
{
const CSN *deletion_csn = NULL;
@@ -2950,7 +2971,7 @@ process_reap_entry (Slapi_Entry *entry, void *cb_data)
objectclass attribute values - if we need more attributes returned by the
search in the future, see _replica_reap_tombstones below and add more to the
attrs array */
- deletion_csn = _get_deletion_csn(entry);
+ deletion_csn = entry_get_deletion_csn(entry);
if ((NULL == deletion_csn || csn_compare(deletion_csn, purge_csn) < 0) &&
(!is_ruv_tombstone_entry(entry))) {
@@ -3043,9 +3064,26 @@ _replica_reap_tombstones(void *arg)
if (NULL != purge_csn)
{
LDAPControl **ctrls;
- int oprc;
reap_callback_data cb_data;
+ char deletion_csn_str[CSN_STRSIZE];
+ char tombstone_filter[128];
char **attrs = NULL;
+ int oprc;
+
+ if (replica_get_precise_purging(replica)){
+ /*
+ * Using precise tombstone purging. Create filter to lookup the exact
+ * entries that need to be purged by using a range search on the new
+ * tombstone csn index.
+ */
+ csn_as_string(purge_csn, PR_FALSE, deletion_csn_str);
+ PR_snprintf(tombstone_filter, 128,
+ "(&(%s<=%s)(objectclass=nsTombstone))", SLAPI_ATTR_TOMBSTONE_CSN,
+ csn_as_string(purge_csn, PR_FALSE, deletion_csn_str));
+ } else {
+ /* Use the old inefficient filter */
+ PR_snprintf(tombstone_filter, 128, "(objectclass=nsTombstone)");
+ }
/* we just need the objectclass - for the deletion csn
and the dn and nsuniqueid - for possible deletion
@@ -3055,6 +3093,7 @@ _replica_reap_tombstones(void *arg)
charray_add(&attrs, slapi_ch_strdup("objectclass"));
charray_add(&attrs, slapi_ch_strdup("nsuniqueid"));
charray_add(&attrs, slapi_ch_strdup("tombstonenumsubordinates"));
+ charray_add(&attrs, slapi_ch_strdup(SLAPI_ATTR_TOMBSTONE_CSN));
ctrls = (LDAPControl **)slapi_ch_calloc (3, sizeof (LDAPControl *));
ctrls[0] = create_managedsait_control();
@@ -3062,7 +3101,7 @@ _replica_reap_tombstones(void *arg)
ctrls[2] = NULL;
pb = slapi_pblock_new();
slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(replica->repl_root),
- LDAP_SCOPE_SUBTREE, "(objectclass=nstombstone)",
+ LDAP_SCOPE_SUBTREE, tombstone_filter,
attrs, 0, ctrls, NULL,
repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
OP_FLAG_REVERSE_CANDIDATE_ORDER);
@@ -4067,6 +4106,24 @@ replica_set_backoff_max(Replica *r, PRUint64 max)
}
}
+void
+replica_set_precise_purging(Replica *r, PRUint64 on_off)
+{
+ if(r){
+ slapi_counter_set_value(r->precise_purging, on_off);
+ }
+}
+
+PRUint64
+replica_get_precise_purging(Replica *r)
+{
+ if(r){
+ return slapi_counter_get_value(r->precise_purging);
+ } else {
+ return 0;
+ }
+}
+
int
replica_get_agmt_count(Replica *r)
{
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index f433fc9..2810b11 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -381,24 +381,24 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
*/
if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
{
- *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
+ *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
}
else if (strcasecmp (config_attr, attr_replicaBindDnGroup) == 0)
{
- *returncode = replica_config_change_updatedngroup (r, mods[i], errortext, apply_mods);
+ *returncode = replica_config_change_updatedngroup (r, mods[i], errortext, apply_mods);
}
else if (strcasecmp (config_attr, attr_replicaBindDnGroupCheckInterval) == 0)
{
- replica_set_groupdn_checkinterval (r, -1);
- }
+ replica_set_groupdn_checkinterval (r, -1);
+ }
else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
{
if (apply_mods) {
- replica_set_referrals(r, NULL);
- if (!replica_is_legacy_consumer (r)) {
- consumer5_set_mapping_tree_state_for_replica(r, NULL);
- }
- }
+ replica_set_referrals(r, NULL);
+ if (!replica_is_legacy_consumer (r)) {
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+ }
+ }
}
else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
{
@@ -428,6 +428,11 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
if (apply_mods)
replica_set_backoff_max(r, PROTOCOL_BACKOFF_MAXIMUM);
}
+ else if (strcasecmp (config_attr, type_replicaPrecisePurge) == 0 )
+ {
+ if (apply_mods)
+ replica_set_precise_purging(r, 0);
+ }
else
{
*returncode = LDAP_UNWILLING_TO_PERFORM;
@@ -448,16 +453,16 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
}
if (strcasecmp (config_attr, attr_replicaBindDn) == 0) {
- *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
+ *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
}
else if (strcasecmp (config_attr, attr_replicaBindDnGroup) == 0)
{
- *returncode = replica_config_change_updatedngroup (r, mods[i], errortext, apply_mods);
+ *returncode = replica_config_change_updatedngroup (r, mods[i], errortext, apply_mods);
}
else if (strcasecmp (config_attr, attr_replicaBindDnGroupCheckInterval) == 0)
{
- int interval = atoi(config_attr_value);
- replica_set_groupdn_checkinterval (r, interval);
+ int interval = atoi(config_attr_value);
+ replica_set_groupdn_checkinterval (r, interval);
}
else if (strcasecmp (config_attr, attr_replicaType) == 0)
{
@@ -586,6 +591,35 @@ replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry*
replica_set_backoff_max(r, val);
}
}
+ else if (strcasecmp (config_attr, type_replicaPrecisePurge) == 0 )
+ {
+ if (apply_mods)
+ {
+ if (apply_mods && config_attr_value[0])
+ {
+ PRUint64 on_off = 0;
+
+ if (strcasecmp(config_attr_value, "on") == 0){
+ on_off = 1;
+ } else if (strcasecmp(config_attr_value, "off") == 0){
+ on_off = 0;
+ } else{
+ /* Invalid value */
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ PR_snprintf (errortext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Invalid value for %s: %s Value should be \"on\" or \"off\"\n",
+ type_replicaPrecisePurge, config_attr_value);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Invalid value for %s: %s Value should be \"on\" or \"off\")\n",
+ type_replicaPrecisePurge, config_attr_value);
+ break;
+ }
+ replica_set_precise_purging(r, on_off);
+ } else if (apply_mods) {
+ replica_set_precise_purging(r, 0);
+ }
+ }
+ }
else
{
*returncode = LDAP_UNWILLING_TO_PERFORM;
diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c
index db48178..5609def 100644
--- a/ldap/servers/plugins/replication/repl_globals.c
+++ b/ldap/servers/plugins/replication/repl_globals.c
@@ -118,6 +118,7 @@ const char *type_replicaAbortCleanRUV = "nsds5ReplicaAbortCleanRUV";
const char *type_replicaProtocolTimeout = "nsds5ReplicaProtocolTimeout";
const char *type_replicaBackoffMin = "nsds5ReplicaBackoffMin";
const char *type_replicaBackoffMax = "nsds5ReplicaBackoffMax";
+const char *type_replicaPrecisePurge = "nsds5ReplicaPreciseTombstonePurging";
/* Attribute names for replication agreement attributes */
const char *type_nsds5ReplicaHost = "nsds5ReplicaHost";
diff --git a/ldap/servers/plugins/replication/urp_tombstone.c b/ldap/servers/plugins/replication/urp_tombstone.c
index db7fa00..c1d0c55 100644
--- a/ldap/servers/plugins/replication/urp_tombstone.c
+++ b/ldap/servers/plugins/replication/urp_tombstone.c
@@ -75,7 +75,7 @@ get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn)
PRBool ists = PR_FALSE;
if (is_tombstone_entry(entry)) {
ists = PR_TRUE;
- *delcsn = _get_deletion_csn((Slapi_Entry *)entry); /* cast away const */
+ *delcsn = entry_get_deletion_csn((Slapi_Entry *)entry); /* cast away const */
}
return ists;
diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c
index 8344cfd..1d25f95 100644
--- a/ldap/servers/slapd/back-ldbm/import-threads.c
+++ b/ldap/servers/slapd/back-ldbm/import-threads.c
@@ -110,6 +110,26 @@ static int import_generate_uniqueid(ImportJob *job, Slapi_Entry *e)
return( rc );
}
+/*
+ * Check if the tombstonecsn is missing, if so add it.
+ */
+static void
+import_generate_tombstone_csn(Slapi_Entry *e)
+{
+ if(e->e_flags & SLAPI_ENTRY_FLAG_TOMBSTONE) {
+ if (attrlist_find( e->e_attrs, SLAPI_ATTR_TOMBSTONE_CSN ) == NULL){
+ const CSN *tombstone_csn = NULL;
+ char tombstone_csnstr[CSN_STRSIZE];
+
+ /* Add the tombstone csn str */
+ if((tombstone_csn = entry_get_deletion_csn(e))){
+ csn_as_string(tombstone_csn, PR_FALSE, tombstone_csnstr);
+ slapi_entry_add_string(e, SLAPI_ATTR_TOMBSTONE_CSN, tombstone_csnstr);
+ }
+ }
+ }
+}
+
/********** BETTER LDIF PARSER **********/
@@ -642,6 +662,8 @@ import_producer(void *param)
if (g_get_global_lastmod()) {
import_add_created_attrs(e);
}
+ /* Add nsTombstoneCSN to tombstone entries unless it's already present */
+ import_generate_tombstone_csn(e);
ep = import_make_backentry(e, id);
if ((ep == NULL) || (ep->ep_entry == NULL)) {
@@ -2795,6 +2817,7 @@ import_worker(void *param)
int is_objectclass_attribute;
int is_nsuniqueid_attribute;
int is_nscpentrydn_attribute;
+ int is_nstombstonecsn_attribute;
void *attrlist_cursor;
PR_ASSERT(NULL != info);
@@ -2822,6 +2845,8 @@ import_worker(void *param)
(strcasecmp(info->index_info->name, SLAPI_ATTR_UNIQUEID) == 0);
is_nscpentrydn_attribute =
(strcasecmp(info->index_info->name, SLAPI_ATTR_NSCP_ENTRYDN) == 0);
+ is_nstombstonecsn_attribute =
+ (strcasecmp(info->index_info->name, SLAPI_ATTR_TOMBSTONE_CSN) == 0);
if (1 != idl_get_idl_new()) {
/* Is there substring indexing going on here ? */
@@ -3012,6 +3037,20 @@ import_worker(void *param)
}
}
}
+ if(is_nstombstonecsn_attribute){
+ const CSN *tomb_csn = entry_get_deletion_csn(ep->ep_entry);
+ char tomb_csnstr[CSN_STRSIZE];
+
+ if(tomb_csn){
+ csn_as_string(tomb_csn, PR_FALSE, tomb_csnstr);
+ ret = index_addordel_string(be, SLAPI_ATTR_TOMBSTONE_CSN,
+ tomb_csnstr, ep->ep_id, BE_INDEX_ADD, NULL);
+ if (0 != ret) {
+ /* Something went wrong, eg disk filled up */
+ goto error;
+ }
+ }
+ }
}
import_decref_entry(ep);
info->last_ID_processed = id;
diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c
index ffeedef..0d9ac33 100644
--- a/ldap/servers/slapd/back-ldbm/index.c
+++ b/ldap/servers/slapd/back-ldbm/index.c
@@ -393,8 +393,11 @@ index_addordel_entry(
/* if we are adding a tombstone entry (see ldbm_add.c) */
if ((flags & BE_INDEX_TOMBSTONE) && (flags & BE_INDEX_ADD))
{
+ const CSN *tombstone_csn = NULL;
+ char deletion_csn_str[CSN_STRSIZE];
Slapi_DN parent;
Slapi_DN *sdn = slapi_entry_get_sdn(e->ep_entry);
+
slapi_sdn_init(&parent);
slapi_sdn_get_parent(sdn, &parent);
/*
@@ -417,6 +420,16 @@ index_addordel_entry(
ldbm_nasty(errmsg, 1021, result);
return( result );
}
+
+ if((tombstone_csn = entry_get_deletion_csn(e->ep_entry))){
+ csn_as_string(tombstone_csn, PR_FALSE, deletion_csn_str);
+ result = index_addordel_string(be, SLAPI_ATTR_TOMBSTONE_CSN, deletion_csn_str, e->ep_id, flags, txn);
+ if ( result != 0 ) {
+ ldbm_nasty(errmsg, 1021, result);
+ return( result );
+ }
+ }
+
slapi_sdn_done(&parent);
if (entryrdn_get_switch()) { /* subtree-rename: on */
Slapi_Attr* attr;
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
index 598cd8e..eb11440 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -562,6 +562,7 @@ ldbm_back_add( Slapi_PBlock *pb )
addingentry->ep_id = slapi_entry_attr_get_ulong(addingentry->ep_entry,"entryid");
slapi_entry_attr_delete(addingentry->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
slapi_entry_delete_string(addingentry->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
+ slapi_entry_attr_delete(addingentry->ep_entry, SLAPI_ATTR_TOMBSTONE_CSN);
/* Now also remove the nscpEntryDN */
if (slapi_entry_attr_delete(addingentry->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN) != 0){
LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Couldn't remove %s\n", dn, SLAPI_ATTR_NSCP_ENTRYDN, 0);
@@ -697,6 +698,26 @@ ldbm_back_add( Slapi_PBlock *pb )
slapi_entry_set_flag(addingentry->ep_entry,
SLAPI_ENTRY_FLAG_TOMBSTONE);
}
+ if (!slapi_entry_attr_hasvalue(addingentry->ep_entry,
+ SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE))
+ {
+ slapi_entry_add_string(addingentry->ep_entry,
+ SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
+ slapi_entry_set_flag(addingentry->ep_entry,
+ SLAPI_ENTRY_FLAG_TOMBSTONE);
+ }
+ if (attrlist_find( addingentry->ep_entry->e_attrs, SLAPI_ATTR_TOMBSTONE_CSN ) == NULL){
+ const CSN *tombstone_csn = NULL;
+ char tombstone_csnstr[CSN_STRSIZE];
+
+ /* Add the missing nsTombstoneCSN attribute to the tombstone */
+ if((tombstone_csn = entry_get_deletion_csn(addingentry->ep_entry))){
+ csn_as_string(tombstone_csn, PR_FALSE, tombstone_csnstr);
+ slapi_entry_add_string(addingentry->ep_entry, SLAPI_ATTR_TOMBSTONE_CSN,
+ tombstone_csnstr);
+ }
+ }
+
if (NULL != operation->o_params.p.p_add.parentuniqueid)
{
slapi_entry_add_string(addingentry->ep_entry,
@@ -744,7 +765,7 @@ ldbm_back_add( Slapi_PBlock *pb )
}
pid = parententry->ep_id;
- /* We may need to adjust the DN since parent could be a resrected conflict entry... */
+ /* We may need to adjust the DN since parent could be a resurrected conflict entry... */
if (!slapi_sdn_isparent(slapi_entry_get_sdn_const(parententry->ep_entry),
slapi_entry_get_sdn_const(addingentry->ep_entry))) {
Slapi_DN adjustedsdn = {0};
@@ -790,7 +811,7 @@ ldbm_back_add( Slapi_PBlock *pb )
/* Tentatively add the entry to the cache. We do this after adding any
* operational attributes to ensure that the cache is sized correctly. */
- if ( cache_add_tentative( &inst->inst_cache, addingentry, NULL )!= 0 )
+ if ( cache_add_tentative( &inst->inst_cache, addingentry, NULL ) != 0 )
{
LDAPDebug1Arg(LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected: %s\n",
slapi_entry_get_dn_const(addingentry->ep_entry));
@@ -886,7 +907,11 @@ ldbm_back_add( Slapi_PBlock *pb )
goto error_return;
}
if (is_resurect_operation) {
- retval = index_addordel_string(be,SLAPI_ATTR_OBJECTCLASS,SLAPI_ATTR_VALUE_TOMBSTONE,addingentry->ep_id,BE_INDEX_DEL|BE_INDEX_EQUALITY,&txn);
+ const CSN *tombstone_csn = NULL;
+ char deletion_csn_str[CSN_STRSIZE];
+
+ retval = index_addordel_string(be,SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE,
+ addingentry->ep_id, BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
if (DB_LOCK_DEADLOCK == retval) {
LDAPDebug( LDAP_DEBUG_ARGS, "add 2 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
/* Retry txn */
@@ -903,9 +928,33 @@ ldbm_back_add( Slapi_PBlock *pb )
}
goto error_return;
}
+
+ /* Need to update the nsTombstoneCSN index */
+ if((tombstone_csn = entry_get_deletion_csn(tombstoneentry->ep_entry))){
+ csn_as_string(tombstone_csn, PR_FALSE, deletion_csn_str);
+ retval = index_addordel_string(be, SLAPI_ATTR_TOMBSTONE_CSN, deletion_csn_str,
+ tombstoneentry->ep_id, BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 3 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "index_addordel_string TOMBSTONE csn(%s), err=%d %s\n",
+ slapi_entry_get_dn_const(tombstoneentry->ep_entry),
+ retval, (msg = dblayer_strerror( retval )) ? msg : "");
+ ADD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ goto diskfull_return;
+ }
+ goto error_return;
+ }
+ }
+
retval = index_addordel_string(be,SLAPI_ATTR_UNIQUEID,slapi_entry_get_uniqueid(addingentry->ep_entry),addingentry->ep_id,BE_INDEX_DEL|BE_INDEX_EQUALITY,&txn);
if (DB_LOCK_DEADLOCK == retval) {
- LDAPDebug( LDAP_DEBUG_ARGS, "add 3 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 4 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
/* Retry txn */
continue;
}
@@ -926,7 +975,7 @@ ldbm_back_add( Slapi_PBlock *pb )
addingentry->ep_id,
BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
if (DB_LOCK_DEADLOCK == retval) {
- LDAPDebug( LDAP_DEBUG_ARGS, "add 4 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 5 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
/* Retry txn */
continue;
}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
index 97c21eb..a00989e 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -102,12 +102,14 @@ ldbm_back_delete( Slapi_PBlock *pb )
int parent_switched = 0;
int myrc = 0;
PRUint64 conn_id;
+ const CSN *tombstone_csn = NULL;
+ char deletion_csn_str[CSN_STRSIZE];
int op_id;
+
if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) {
conn_id = 0; /* connection is NULL */
}
- slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id);
-
+ slapi_pblock_get( pb, SLAPI_OPERATION_ID, &op_id);
slapi_pblock_get( pb, SLAPI_BACKEND, &be);
slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
slapi_pblock_get( pb, SLAPI_DELETE_TARGET_SDN, &sdnp );
@@ -629,10 +631,13 @@ ldbm_back_delete( Slapi_PBlock *pb )
/* The suffix entry has no parent */
slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID, parentuniqueid);
}
+ if(opcsn){
+ csn_as_string(opcsn, PR_FALSE, deletion_csn_str);
+ slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_TOMBSTONE_CSN, deletion_csn_str);
+ }
slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN, slapi_sdn_get_ndn(&nscpEntrySDN));
tomb_value = slapi_value_new_string(SLAPI_ATTR_VALUE_TOMBSTONE);
- value_update_csn(tomb_value, CSN_TYPE_VALUE_UPDATED,
- operation_get_csn(operation));
+ value_update_csn(tomb_value, CSN_TYPE_VALUE_UPDATED, operation_get_csn(operation));
slapi_entry_add_value(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, tomb_value);
slapi_value_free(&tomb_value);
/* XXXggood above used to be: slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE); */
@@ -846,6 +851,8 @@ ldbm_back_delete( Slapi_PBlock *pb )
* above, but we want it to remain in the nsUniqueID and nscpEntryDN indexes
* and for objectclass=tombstone.
*/
+
+
retval = index_addordel_string(be, SLAPI_ATTR_OBJECTCLASS,
SLAPI_ATTR_VALUE_TOMBSTONE,
tombstone->ep_id,BE_INDEX_ADD, &txn);
@@ -858,14 +865,42 @@ ldbm_back_delete( Slapi_PBlock *pb )
}
if (retval) {
LDAPDebug( LDAP_DEBUG_ANY,
- "delete (adding %s) failed, err=%d %s\n",
- SLAPI_ATTR_VALUE_TOMBSTONE, retval,
- (msg = dblayer_strerror( retval )) ? msg : "" );
+ "delete (adding %s) failed, err=%d %s\n",
+ SLAPI_ATTR_VALUE_TOMBSTONE, retval,
+ (msg = dblayer_strerror( retval )) ? msg : "" );
if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
DEL_SET_ERROR(ldap_result_code,
LDAP_OPERATIONS_ERROR, retry_count);
goto error_return;
}
+
+ /* Need to update the nsTombstoneCSN index */
+ if((tombstone_csn = entry_get_deletion_csn(tombstone->ep_entry))){
+ csn_as_string(tombstone_csn, PR_FALSE, deletion_csn_str);
+ retval = index_addordel_string(be, SLAPI_ATTR_TOMBSTONE_CSN,
+ deletion_csn_str, tombstone->ep_id,
+ BE_INDEX_ADD, &txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_BACKLDBM,
+ "delete tombstone csn(adding %s) DB_LOCK_DEADLOCK\n",
+ deletion_csn_str, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "delete tombsone csn(adding %s) failed, err=%d %s\n",
+ deletion_csn_str,
+ retval,
+ (msg = dblayer_strerror( retval )) ? msg : "" );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)){
+ disk_full = 1;
+ }
+ DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
+ goto error_return;
+ }
+ }
+
retval = index_addordel_string(be, SLAPI_ATTR_UNIQUEID,
slapi_entry_get_uniqueid(tombstone->ep_entry),
tombstone->ep_id,BE_INDEX_ADD,&txn);
@@ -1002,7 +1037,7 @@ ldbm_back_delete( Slapi_PBlock *pb )
{
/*
* We need to remove the Tombstone entry from the remaining indexes:
- * objectclass=nsTombstone, nsUniqueID, nscpEntryDN
+ * objectclass=nsTombstone, nsUniqueID, nscpEntryDN, nsTombstoneCSN
*/
char *nscpedn = NULL;
@@ -1026,6 +1061,34 @@ ldbm_back_delete( Slapi_PBlock *pb )
LDAP_OPERATIONS_ERROR, retry_count);
goto error_return;
}
+
+ /* Need to update the nsTombstoneCSN index */
+ if((tombstone_csn = entry_get_deletion_csn(e->ep_entry))){
+ csn_as_string(tombstone_csn, PR_FALSE, deletion_csn_str);
+ retval = index_addordel_string(be, SLAPI_ATTR_TOMBSTONE_CSN,
+ deletion_csn_str, e->ep_id,
+ BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_BACKLDBM,
+ "delete tombstone csn(deleting %s) DB_LOCK_DEADLOCK\n",
+ deletion_csn_str, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "delete tombsone csn(deleting %s) failed, err=%d %s\n",
+ deletion_csn_str,
+ retval,
+ (msg = dblayer_strerror( retval )) ? msg : "" );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)){
+ disk_full = 1;
+ }
+ DEL_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count);
+ goto error_return;
+ }
+ }
+
retval = index_addordel_string(be, SLAPI_ATTR_UNIQUEID,
slapi_entry_get_uniqueid(e->ep_entry),
e->ep_id, BE_INDEX_DEL|BE_INDEX_EQUALITY, &txn);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
index 6f2da15..3dba6f3 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -418,15 +418,18 @@ ldbm_back_modify( Slapi_PBlock *pb )
int opreturn = 0;
int mod_count = 0;
int not_an_error = 0;
+ int fixup_tombstone = 0;
slapi_pblock_get( pb, SLAPI_BACKEND, &be);
slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr );
slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
slapi_pblock_get( pb, SLAPI_TXN, (void**)&parent_txn );
- slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
-
+ slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
+
+ fixup_tombstone = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_FIXUP);
+
dblayer_txn_init(li,&txn); /* must do this before first goto error_return */
/* the calls to perform searches require the parent txn if any
so set txn to the parent_txn until we begin the child transaction */
@@ -566,13 +569,15 @@ ldbm_back_modify( Slapi_PBlock *pb )
}
}
- if ( !is_fixup_operation )
+ if ( !is_fixup_operation && !fixup_tombstone)
{
- if (!repl_op && slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE) ) {
+ if (!repl_op && slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE))
+ {
ldap_result_code = LDAP_UNWILLING_TO_PERFORM;
ldap_result_message = "Operation not allowed on tombstone entry.";
slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_modify",
- "Attempt to modify a tombstone entry %s\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const( e->ep_entry )));
+ "Attempt to modify a tombstone entry %s\n",
+ slapi_sdn_get_dn(slapi_entry_get_sdn_const( e->ep_entry )));
goto error_return;
}
opcsn = operation_get_csn (operation);
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
index 622ad7a..3368284 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -732,6 +732,7 @@ ldbm_back_modrdn( Slapi_PBlock *pb )
slapi_log_error(SLAPI_LOG_REPL, "ldbm_back_modrdn",
"Resurrecting an entry %s\n", slapi_entry_get_dn(ec->ep_entry));
slapi_entry_attr_delete(ec->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
+ slapi_entry_attr_delete(ec->ep_entry, SLAPI_ATTR_TOMBSTONE_CSN);
slapi_entry_delete_string(ec->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
/* Now also remove the nscpEntryDN */
if (slapi_entry_attr_delete(ec->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN) != 0){
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index 1d1b2dc..ab3a4a5 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -2179,6 +2179,69 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
}
/*
+ * If this entry is a tombstone, update the 'nstombstonecsn' index
+ */
+ if(ep->ep_entry->e_flags & SLAPI_ENTRY_FLAG_TOMBSTONE){
+ const CSN *tombstone_csn = NULL;
+ char deletion_csn_str[CSN_STRSIZE];
+
+ if((tombstone_csn = entry_get_deletion_csn(ep->ep_entry))){
+ if (!run_from_cmdline) {
+ rc = dblayer_txn_begin(be, NULL, &txn);
+ if (0 != rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_ldbm2index",
+ "%s: ERROR: failed to begin txn for update index '%s' (err %d: %s)\n",
+ inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task, "%s: ERROR: failed to begin txn for "
+ "update index '%s' (err %d: %s)",
+ inst->inst_name, indexAttrs[j], rc,
+ dblayer_strerror(rc));
+ }
+ return_value = -2;
+ goto err_out;
+ }
+ }
+
+ csn_as_string(tombstone_csn, PR_FALSE, deletion_csn_str);
+ rc = index_addordel_string(be, SLAPI_ATTR_TOMBSTONE_CSN, deletion_csn_str,
+ ep->ep_id, BE_INDEX_ADD, &txn);
+ if (rc != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_ldbm2index",
+ "%s: ERROR: failed to update index '%s' (err %d: %s)\n",
+ inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task, "%s: ERROR: failed to update index '%s' "
+ "(err %d: %s)", inst->inst_name,
+ SLAPI_ATTR_TOMBSTONE_CSN, rc,
+ dblayer_strerror(rc));
+ }
+ if (!run_from_cmdline) {
+ dblayer_txn_abort(be, &txn);
+ }
+ return_value = -2;
+ goto err_out;
+ }
+ if (!run_from_cmdline) {
+ rc = dblayer_txn_commit(be, &txn);
+ if (0 != rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_ldbm2index",
+ "%s: ERROR: failed to commit txn for update index '%s' (err %d: %s)\n",
+ inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task,"%s: ERROR: failed to commit txn for "
+ "update index '%s' (err %d: %s)",
+ inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN,
+ rc, dblayer_strerror(rc));
+ }
+ return_value = -2;
+ goto err_out;
+ }
+ }
+ }
+ }
+
+ /*
* Update the attribute indexes
*/
if (indexAttrs != NULL) {
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
index 5512b5b..23bb797 100644
--- a/ldap/servers/slapd/entrywsi.c
+++ b/ldap/servers/slapd/entrywsi.c
@@ -1527,3 +1527,26 @@ resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribu
}
}
+const CSN *
+entry_get_deletion_csn(Slapi_Entry *e)
+{
+ const CSN *deletion_csn = NULL;
+
+ PR_ASSERT(NULL != e);
+ if (NULL != e)
+ {
+ Slapi_Attr *oc_attr = NULL;
+ if (entry_attr_find_wsi(e, SLAPI_ATTR_OBJECTCLASS, &oc_attr) == ATTRIBUTE_PRESENT)
+ {
+ Slapi_Value *tombstone_value = NULL;
+ struct berval v;
+ v.bv_val = SLAPI_ATTR_VALUE_TOMBSTONE;
+ v.bv_len = strlen(SLAPI_ATTR_VALUE_TOMBSTONE);
+ if (attr_value_find_wsi(oc_attr, &v, &tombstone_value) == VALUE_PRESENT)
+ {
+ deletion_csn = value_get_csn(tombstone_value, CSN_TYPE_VALUE_UPDATED);
+ }
+ }
+ }
+ return deletion_csn;
+}
diff --git a/ldap/servers/slapd/mapping_tree.c b/ldap/servers/slapd/mapping_tree.c
index 338fffe..4267750 100644
--- a/ldap/servers/slapd/mapping_tree.c
+++ b/ldap/servers/slapd/mapping_tree.c
@@ -2174,6 +2174,7 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry
int ret;
int scope=LDAP_SCOPE_BASE;
int op_type;
+ int fixup = 0;
if(mapping_tree_freed){
@@ -2192,6 +2193,7 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry
/* Get the target for this op */
target_sdn = operation_get_target_spec (op);
+ fixup = operation_is_flag_set(op, OP_FLAG_TOMBSTONE_FIXUP);
if(!mapping_tree_inited) {
mapping_tree_init();
@@ -2240,14 +2242,17 @@ int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry
* or if the whole server is readonly AND backend is public (!private)
*/
if ((ret == LDAP_SUCCESS) && *be && !be_isdeleted(*be) &&
- ((*be)->be_readonly ||
- (slapi_config_get_readonly() && !slapi_be_private(*be)))) {
+ (((*be)->be_readonly && !fixup) ||
+ ((slapi_config_get_readonly() && !fixup) &&
+ !slapi_be_private(*be))) )
+ {
unsigned long op_type = operation_get_type(op);
if ((op_type != SLAPI_OPERATION_SEARCH) &&
(op_type != SLAPI_OPERATION_COMPARE) &&
(op_type != SLAPI_OPERATION_BIND) &&
- (op_type != SLAPI_OPERATION_UNBIND)) {
+ (op_type != SLAPI_OPERATION_UNBIND))
+ {
ret = LDAP_UNWILLING_TO_PERFORM;
PL_strncpyz(errorbuf, slapi_config_get_readonly() ?
"Server is read-only" :
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 9a84e6f..cd17907 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -498,6 +498,7 @@ NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...)
#define SLAPI_ATTR_UNIQUEID "nsuniqueid"
#define SLAPI_ATTR_OBJECTCLASS "objectclass"
#define SLAPI_ATTR_VALUE_TOMBSTONE "nsTombstone"
+#define SLAPI_ATTR_TOMBSTONE_CSN "nsTombstoneCSN"
#define SLAPI_ATTR_VALUE_PARENT_UNIQUEID "nsParentUniqueID"
#define SLAPI_ATTR_VALUE_SUBENTRY "ldapsubentry"
#define SLAPI_ATTR_NSCP_ENTRYDN "nscpEntryDN"
@@ -508,6 +509,7 @@ NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...)
#define SLAPI_ATTR_UNIQUEID_LENGTH 10
#define SLAPI_ATTR_OBJECTCLASS_LENGTH 11
#define SLAPI_ATTR_VALUE_TOMBSTONE_LENGTH 11
+#define SLAPI_ATTR_TOMBSTONE_CSN_LENGTH 14
#define SLAPI_ATTR_VALUE_PARENT_UNIQUEID_LENGTH 16
#define SLAPI_ATTR_VALUE_SUBENTRY_LENGTH 12
#define SLAPI_ATTR_NSCP_ENTRYDN_LENGTH 11
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index 2347119..a8d7738 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -352,6 +352,7 @@ void entry_add_rdn_csn(Slapi_Entry *e, const CSN *csn);
/* this adds a csn to the entry's e_dncsnset but makes sure the set is in increasing csn order */
#define ENTRY_DNCSN_INCREASING 0x1 /* for flags below */
int entry_add_dncsn_ext(Slapi_Entry *entry, const CSN *csn, PRUint32 flags);
+const CSN *entry_get_deletion_csn(Slapi_Entry *entry);
/* attr.c */
Slapi_Attr *slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_lock);
@@ -442,7 +443,8 @@ char *slapi_filter_to_string_internal( const struct slapi_filter *f, char *buf,
#define OP_FLAG_PAGED_RESULTS 0x040000 /* simple paged results */
#define OP_FLAG_SERVER_SIDE_SORTING 0x080000 /* server side sorting */
#define OP_FLAG_REVERSE_CANDIDATE_ORDER 0x100000 /* reverse the search candidate list */
-#define OP_FLAG_NEVER_CACHE 0x200000 /* never keep the entry in cache */
+#define OP_FLAG_NEVER_CACHE 0x200000 /* never keep the entry in cache */
+#define OP_FLAG_TOMBSTONE_FIXUP 0x400000 /* operation is tombstone fixup op */
/* reverse search states */
#define REV_STARTED 1
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 6340db8..489266f 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -67,6 +67,7 @@ static int shutting_down = 0;
#define TASK_RESTORE_DN "cn=restore,cn=tasks,cn=config"
#define TASK_INDEX_DN "cn=index,cn=tasks,cn=config"
#define TASK_UPGRADEDB_DN "cn=upgradedb,cn=tasks,cn=config"
+#define TASK_TOMBSTONE_FIXUP_DN "cn=fixup tombstones,cn=tasks,cn=config"
#define TASK_LOG_NAME "nsTaskLog"
#define TASK_STATUS_NAME "nsTaskStatus"
@@ -77,6 +78,10 @@ static int shutting_down = 0;
#define DEFAULT_TTL "120" /* seconds */
#define TASK_SYSCONFIG_FILE_ATTR "sysconfigfile" /* sysconfig reload task file attr */
#define TASK_SYSCONFIG_LOGCHANGES_ATTR "logchanges"
+#define TASK_TOMBSTONE_FIXUP "fixup tombstones task"
+#define TASK_TOMBSTONE_FIXUP_BACKEND "backend"
+#define TASK_TOMBSTONE_FIXUP_SUFFIX "suffix"
+#define TASK_TOMBSTONE_FIXUP_STRIPCSN "stripcsn"
#define LOG_BUFFER 256
/* if the cumul. log gets larger than this, it's truncated: */
@@ -224,29 +229,12 @@ void slapi_task_log_status(Slapi_Task *task, char *format, ...)
slapi_task_status_changed(task);
}
-void slapi_task_log_status_ext(Slapi_Task *task, char *format, va_list ap)
-{
- if (! task->task_status)
- task->task_status = (char *)slapi_ch_malloc(10 * LOG_BUFFER);
- if (! task->task_status)
- return; /* out of memory? */
-
- PR_vsnprintf(task->task_status, (10 * LOG_BUFFER), format, ap);
- slapi_task_status_changed(task);
-}
-
-/* this adds a line to the 'nsTaskLog' value, which is cumulative (anything
- * logged here is added to the end)
- */
-void slapi_task_log_notice(Slapi_Task *task, char *format, ...)
+void slapi_task_log_notice_ext(Slapi_Task *task, char *format, va_list ap)
{
- va_list ap;
char buffer[LOG_BUFFER];
size_t len;
- va_start(ap, format);
PR_vsnprintf(buffer, LOG_BUFFER, format, ap);
- va_end(ap);
if (task->task_log_lock) {
PR_Lock(task->task_log_lock);
@@ -286,12 +274,29 @@ void slapi_task_log_notice(Slapi_Task *task, char *format, ...)
slapi_task_status_changed(task);
}
-void slapi_task_log_notice_ext(Slapi_Task *task, char *format, va_list ap)
+void slapi_task_log_status_ext(Slapi_Task *task, char *format, va_list ap)
+{
+ if (! task->task_status)
+ task->task_status = (char *)slapi_ch_malloc(10 * LOG_BUFFER);
+ if (! task->task_status)
+ return; /* out of memory? */
+
+ PR_vsnprintf(task->task_status, (10 * LOG_BUFFER), format, ap);
+ slapi_task_status_changed(task);
+}
+
+/* this adds a line to the 'nsTaskLog' value, which is cumulative (anything
+ * logged here is added to the end)
+ */
+void slapi_task_log_notice(Slapi_Task *task, char *format, ...)
{
+ va_list ap;
char buffer[LOG_BUFFER];
size_t len;
+ va_start(ap, format);
PR_vsnprintf(buffer, LOG_BUFFER, format, ap);
+ va_end(ap);
if (task->task_log_lock) {
PR_Lock(task->task_log_lock);
@@ -2090,6 +2095,314 @@ done:
return rc;
}
+/*
+ * Add the nsTombstoneCSN attribute/value to the entry.
+ */
+static int
+fixup_tombstone(Slapi_PBlock *pb, char *suffix, Slapi_Entry *e, int *fixup_count)
+{
+ LDAPMod mod;
+ LDAPMod *mods[2];
+ const CSN *tombstone_csn = NULL;
+ char deletion_csn_str[CSN_STRSIZE];
+ char *val[2];
+ int rc = LDAP_SUCCESS;
+
+ if((tombstone_csn = entry_get_deletion_csn(e))){
+ slapi_log_error(SLAPI_LOG_REPL, TASK_TOMBSTONE_FIXUP,
+ "Fixing tombstone (%s)\n", slapi_entry_get_dn(e));
+
+ /* We have an entry tombstone that needs fixing */
+ slapi_pblock_init(pb);
+ csn_as_string(tombstone_csn, PR_FALSE, deletion_csn_str);
+ mods[0] = &mod;
+ mods[1] = 0;
+
+ val[0] = deletion_csn_str;
+ val[1] = 0;
+
+ mod.mod_op = LDAP_MOD_ADD;
+ mod.mod_type = SLAPI_ATTR_TOMBSTONE_CSN;
+ mod.mod_values = val;
+
+ slapi_modify_internal_set_pb_ext( pb, slapi_entry_get_sdn(e),
+ mods, 0, 0, (void *)plugin_get_default_component_id(),
+ OP_FLAG_TOMBSTONE_ENTRY | OP_FLAG_TOMBSTONE_FIXUP);
+ slapi_modify_internal_pb(pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ pblock_done(pb);
+ if(rc == LDAP_SUCCESS){
+ (*fixup_count)++;
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Strip out nsTombstoneCSN so the task can be run again to remove them. Used
+ * solely for testing the fixup task.
+ */
+static void
+strip_tombstone(Slapi_PBlock *pb, char *suffix, Slapi_Entry *e, int *strip_count)
+{
+ LDAPMod mod;
+ LDAPMod *mods[2];
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_REPL, TASK_TOMBSTONE_FIXUP,
+ "Stripping tombstone (%s)\n", slapi_entry_get_dn(e));
+
+ /* We have an entry tombstone that needs stripping */
+ slapi_pblock_init(pb);
+ mods[0] = &mod;
+ mods[1] = 0;
+
+ mod.mod_op = LDAP_MOD_DELETE;
+ mod.mod_type = SLAPI_ATTR_TOMBSTONE_CSN;
+ mod.mod_values = NULL;
+
+ slapi_modify_internal_set_pb_ext( pb, slapi_entry_get_sdn(e),
+ mods, 0, 0, (void *)plugin_get_default_component_id(),
+ OP_FLAG_TOMBSTONE_ENTRY | OP_FLAG_TOMBSTONE_FIXUP);
+ slapi_modify_internal_pb(pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ pblock_done(pb);
+
+ if(rc == LDAP_SUCCESS){
+ (*strip_count)++;
+ } else {
+ slapi_log_error(SLAPI_LOG_REPL, TASK_TOMBSTONE_FIXUP,
+ "Stripping tombstone (%s) failed, error %d\n", slapi_entry_get_dn(e), rc);
+ }
+}
+
+struct task_tombstone_data
+{
+ char **base;
+ int stripcsn;
+ Slapi_Task *task;
+};
+
+/*
+ * Fix tombstone thread - add missing nsTombstoneCSN
+ */
+static void
+task_fixup_tombstone_thread(void *arg)
+{
+ struct task_tombstone_data *task_data = arg;
+ Slapi_Entry **entries = NULL;
+ Slapi_Task *task = task_data->task;
+ char **base = task_data->base;
+ char *filter = NULL;
+ int fixup_count = 0;
+ int rc, i, j;
+
+ slapi_task_begin(task, 1);
+ slapi_task_log_notice(task, "Beginning tombstone fixup task...\n");
+ slapi_log_error(SLAPI_LOG_REPL, TASK_TOMBSTONE_FIXUP,
+ "Beginning tombstone fixup task...\n");
+
+ if(task_data->stripcsn){
+ /* find tombstones with nsTombstoneCSN */
+ filter = "(&(nstombstonecsn=*)(objectclass=nsTombstone))";
+ } else {
+ /* find tombstones missing nsTombstoneCSN */
+ filter = "(&(!(nstombstonecsn=*))(objectclass=nsTombstone))";
+ }
+
+ /* Okay check the specified backends only */
+ for(i = 0; base && base[i]; i++){
+ Slapi_PBlock *search_pb = slapi_pblock_new();
+
+ /* find entries that need fixing... */
+ slapi_search_internal_set_pb(search_pb, base[i], LDAP_SCOPE_SUBTREE,
+ filter, NULL, 0, NULL, NULL, plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(search_pb);
+
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS) {
+ slapi_task_log_notice(task,
+ "Failed to search backend for tombstones, error %d\n", rc);
+ slapi_log_error(SLAPI_LOG_REPL, TASK_TOMBSTONE_FIXUP,
+ "Failed to search backend for tombstones, error %d\n", rc);
+ slapi_pblock_destroy(search_pb);
+ slapi_task_finish(task, rc);
+ return;
+ }
+
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (entries) {
+ Slapi_PBlock *fixup_pb = slapi_pblock_new();
+
+ /* process all the tombstone entries */
+ for (j = 0; entries[j]; j++){
+ if(task_data->stripcsn){
+ /* strip nsTombstoneCSN - used to testing */
+ strip_tombstone(fixup_pb, base[i], entries[j], &fixup_count);
+ } else if((rc = fixup_tombstone(fixup_pb, base[i], entries[j], &fixup_count))){
+ /* Failed to update tombstone, log it and move on... */
+ slapi_task_log_notice(task,
+ "Failed to update tombstone entry (%s) error %d\n",
+ slapi_entry_get_dn(entries[j]), rc);
+ slapi_log_error(SLAPI_LOG_FATAL, TASK_TOMBSTONE_FIXUP,
+ "Failed to update tombstone entry (%s) error %d\n",
+ slapi_entry_get_dn(entries[j]), rc);
+ }
+ }
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(fixup_pb);
+ }
+ slapi_pblock_destroy(search_pb);
+ slapi_task_inc_progress(task);
+ }
+ slapi_task_log_notice(task, "%s %d tombstones.\n",
+ task_data->stripcsn ? "Stripped" : "Fixed", fixup_count);
+ slapi_log_error(SLAPI_LOG_REPL, TASK_TOMBSTONE_FIXUP, "%s %d tombstones.\n",
+ task_data->stripcsn ? "Stripped" : "Fixed", fixup_count);
+ slapi_task_inc_progress(task);
+ slapi_task_finish(task, rc);
+ slapi_ch_array_free(base);
+ slapi_ch_free((void **)&task_data);
+}
+
+
+/*
+ * task_fixup_tombstones_add
+ *
+ * Check all the existing tombstones and add nsTombstoneCSN if missing.
+ *
+ * dn: cn=fixem,cn=fixup tombstones,cn=tasks,cn=config
+ * objectclass: top
+ * objectclass: extensibleObject
+ * cn: fixem
+ * backend: userRoot
+ * suffix: dc=example,dc=com
+ * stripcsn: yes
+ *
+ * backend & suffix are optional. If skipped, all backends/suffixes are
+ * checked. Multiple suffixes can also be specified.
+ *
+ * Hidden option: "stripcsn" is strictly used to verify the fixup task: run
+ * the task using the strip option to strip tombstones of "nsTombstoneCSN",
+ * then run task, without the strip option, to add "nsTombstoneCSN" back.
+ */
+static int
+task_fixup_tombstones_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ Slapi_Backend *be = NULL;
+ Slapi_Task *task = NULL;
+ struct task_tombstone_data *task_data = NULL;
+ const Slapi_DN *base_sdn = NULL;
+ PRThread *thread = NULL;
+ char **backend = NULL;
+ char **suffix = NULL;
+ char **base = NULL;
+ char *stripcsn = NULL;
+ int i;
+
+ /*
+ * Get the task options. We will store all the "backends" in the suffix array.
+ */
+ if((suffix = slapi_entry_attr_get_charray(e, TASK_TOMBSTONE_FIXUP_SUFFIX))){
+ for (i = 0; suffix && suffix[i]; i++){
+ char *dn = slapi_create_dn_string("%s", suffix[i]);
+
+ if(dn){
+ if(slapi_dn_syntax_check(pb, dn, 1)){
+ /* invalid suffix name */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Invalid DN (%s) used for \"suffix\"\n", suffix[i]);
+ *returncode = LDAP_INVALID_DN_SYNTAX;
+ goto done;
+ } else {
+ slapi_ch_array_add(&base, dn);
+ }
+ }
+ }
+ }
+ if((backend = slapi_entry_attr_get_charray(e, TASK_TOMBSTONE_FIXUP_BACKEND))){
+ for (i = 0; backend && backend[i]; i++){
+ if((be = slapi_be_select_by_instance_name(backend[i]))){
+ if((base_sdn = slapi_be_getsuffix(be, 0))){
+ slapi_ch_array_add(&base, slapi_ch_strdup(slapi_sdn_get_ndn(base_sdn)));
+ } else {
+ /* failed to get a suffix */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Failed to find a suffix for the backend(%s)\n", backend[i]);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ } else {
+ /* Failed to find a backend */
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Failed to find a backend using (%s)\n", backend[i]);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+ }
+ }
+
+ /*
+ * If suffix is NULL, we check all the backends
+ */
+ if(base == NULL){
+ char *cookie = NULL;
+
+ /* Gather all the backends */
+ be = slapi_get_first_backend(&cookie);
+ while(be){
+ if((base_sdn = slapi_be_getsuffix(be, 0)) && !be->be_private){
+ const char *suf = slapi_sdn_get_ndn(base_sdn);
+ /* Need to skip the retro changelog */
+ if(strcmp(suf, "cn=changelog"))
+ {
+ slapi_ch_array_add(&base, slapi_ch_strdup(suf));
+ }
+ }
+ be = slapi_get_next_backend(cookie);
+ }
+ }
+
+ task = slapi_new_task(slapi_entry_get_ndn(e));
+ task_data = (struct task_tombstone_data *)slapi_ch_calloc(1, sizeof(struct task_tombstone_data));
+ task_data->base = base;
+ task_data->task = task;
+ if((stripcsn = slapi_entry_attr_get_charptr(e, TASK_TOMBSTONE_FIXUP_STRIPCSN))){
+ if(strcasecmp(stripcsn, "yes") == 0 || strcasecmp(stripcsn, "on") == 0){
+ task_data->stripcsn = 1;
+ }
+ slapi_ch_free_string(&stripcsn);
+ }
+
+ /* start the db2index as a separate thread */
+ thread = PR_CreateThread(PR_USER_THREAD, task_fixup_tombstone_thread,
+ (void *)task_data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "task_fixup_tombstones_add: unable to create index thread!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ slapi_task_finish(task, *returncode);
+ slapi_ch_array_free(base);
+ slapi_ch_free((void **)&task_data);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+done:
+ slapi_ch_array_free(suffix);
+ slapi_ch_array_free(backend);
+
+ if (*returncode != LDAP_SUCCESS){
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
/* cleanup old tasks that may still be in the DSE from a previous session
* (this can happen if the server crashes [no matter how unlikely we like
* to think that is].)
@@ -2170,6 +2483,7 @@ void task_init(void)
slapi_task_register_handler("index", task_index_add);
slapi_task_register_handler("upgradedb", task_upgradedb_add);
slapi_task_register_handler("sysconfig reload", task_sysconfig_reload_add);
+ slapi_task_register_handler("fixup tombstones", task_fixup_tombstones_add);
}
/* called when the server is shutting down -- abort all existing tasks */
9 years, 8 months
ldap/servers
by Mark Reynolds
ldap/servers/slapd/back-ldbm/ldbm_search.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit e6cee31aa2beb6496df86490776f1f93d3a8348b
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Jul 14 10:47:52 2014 -0400
Ticket 47858 - Internal searches using OP_FLAG_REVERSE_CANDIDATE_ORDER can crash the server
Bug Description: If an internal search uses OP_FLAG_REVERSE_CANDIDATE_ORDER, and
the search fails tro find any candidates the server will crash.
Fix Description: Make sure we do not dereference a NULL sr_candidates pointer in
ldbm_search().
https://fedorahosted.org/389/ticket/47858
Reviewed by: rmeggins(Thanks!)
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index 6dff1f5..f1375a5 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -1450,7 +1450,7 @@ ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
* search can enter this function multiple times, we need to keep track
* of our state, and only initialize sr_current once.
*/
- if(!op->o_reverse_search_state){
+ if(!op->o_reverse_search_state && sr->sr_candidates){
sr->sr_current = sr->sr_candidates->b_nids;
op->o_reverse_search_state = REV_STARTED;
}
9 years, 8 months
Branch '389-ds-base-1.3.2' - ldap/servers
by Noriko Hosoi
ldap/servers/slapd/add.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 88aa59f7d1cf3d99c017134c4f4c30f1825f2c3e
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Fri Jul 11 10:29:12 2014 -0700
Ticket #47834 - Tombstone_to_glue: if parents are also converted to glue, the target entry's DN must be adjusted.
Description: commit 708a56b8d524131362e2d71b7fbc2eb257075e14 breaks
the CI testcase 47808. Undo the change made in op_shared_add (add.c).
https://fedorahosted.org/389/ticket/47834#comment:9
(cherry picked from commit 6d38125d0e848e43788d2b7e4f5b85613b60448c)
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
index 170e28b..875ad22 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -732,9 +732,9 @@ static void op_shared_add (Slapi_PBlock *pb)
if (be->be_add != NULL)
{
+ rc = (*be->be_add)(pb);
/* backend may change this if errors and not consumed */
slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &save_e);
- rc = (*be->be_add)(pb);
slapi_pblock_set(pb, SLAPI_ADD_ENTRY, ec);
if (rc == 0)
{
9 years, 8 months
ldap/servers
by Noriko Hosoi
ldap/servers/slapd/add.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit 6d38125d0e848e43788d2b7e4f5b85613b60448c
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Fri Jul 11 10:29:12 2014 -0700
Ticket #47834 - Tombstone_to_glue: if parents are also converted to glue, the target entry's DN must be adjusted.
Description: commit 708a56b8d524131362e2d71b7fbc2eb257075e14 breaks
the CI testcase 47808. Undo the change made in op_shared_add (add.c).
https://fedorahosted.org/389/ticket/47834#comment:9
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
index 170e28b..875ad22 100644
--- a/ldap/servers/slapd/add.c
+++ b/ldap/servers/slapd/add.c
@@ -732,9 +732,9 @@ static void op_shared_add (Slapi_PBlock *pb)
if (be->be_add != NULL)
{
+ rc = (*be->be_add)(pb);
/* backend may change this if errors and not consumed */
slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &save_e);
- rc = (*be->be_add)(pb);
slapi_pblock_set(pb, SLAPI_ADD_ENTRY, ec);
if (rc == 0)
{
9 years, 8 months
Branch '389-ds-base-1.3.2' - ldap/servers
by thierry bordaz
ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 38 +++++++++++++--------------
1 file changed, 19 insertions(+), 19 deletions(-)
New commits:
commit 107722f4216207659f15043b7c4a330ead4f3572
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Fri Jul 11 15:24:53 2014 +0200
Ticket 47797 - fix the indentation
Bug Description:
Indentation of some parts of the fix was 8 spaces rather than 4
Fix Description:
https://fedorahosted.org/389/ticket/47797
Reviewed by: Mark Reynolds
Platforms tested: f17
Flag Day: no
Doc impact: no
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
index 2937d1b..253136c 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
@@ -1799,15 +1799,15 @@ retry_get:
*elem = (rdn_elem *)data->data;
if (rc) {
if (DB_LOCK_DEADLOCK == rc) {
- if (db_txn) {
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_get_elem: cursor get deadlock while under txn -> failure\n");
- } else {
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_get_elem: cursor get deadlock\n");
- /* try again */
- goto retry_get;
- }
+ if (db_txn) {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_elem: cursor get deadlock while under txn -> failure\n");
+ } else {
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_get_elem: cursor get deadlock\n");
+ /* try again */
+ goto retry_get;
+ }
} else if (DB_BUFFER_SMALL == rc) {
/* try again */
data->flags = DB_DBT_MALLOC;
@@ -2582,10 +2582,10 @@ _entryrdn_insert_key(backend *be,
int isexception = 0;
if ((rc == DB_LOCK_DEADLOCK) && db_txn) {
- slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
- "_entryrdn_insert_key: Suffix \"%s\" cursor get fails: "
- "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
- goto bail;
+ slapi_log_error(ENTRYRDN_LOGLEVEL(rc), ENTRYRDN_TAG,
+ "_entryrdn_insert_key: Suffix \"%s\" cursor get fails: "
+ "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
+ goto bail;
}
/* Check the RDN is in the exception list */
for (ep = rdn_exceptions; ep && *ep; ep++) {
@@ -3238,11 +3238,11 @@ _entryrdn_index_read(backend *be,
if (rc || NULL == *elem) {
slapi_ch_free((void **)elem);
if ((rc == DB_LOCK_DEADLOCK) && db_txn) {
- slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
- "_entryrdn_index_read: Suffix \"%s\" cursor get fails: "
- "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
- slapi_rdn_free(&tmpsrdn);
- goto bail;
+ slapi_log_error(SLAPI_LOG_BACKLDBM, ENTRYRDN_TAG,
+ "_entryrdn_index_read: Suffix \"%s\" cursor get fails: "
+ "%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
+ slapi_rdn_free(&tmpsrdn);
+ goto bail;
}
if (flags & TOMBSTONE_INCLUDED) {
/* Node might be a tombstone. */
@@ -3336,7 +3336,7 @@ _entryrdn_index_read(backend *be,
"_entryrdn_index_read: Suffix \"%s\" cursor get fails: "
"%s(%d)\n", nrdn, dblayer_strerror(rc), rc);
if (tmpsrdn != srdn) {
- slapi_rdn_free(&tmpsrdn);
+ slapi_rdn_free(&tmpsrdn);
}
goto bail;
}
9 years, 8 months