andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
Blob Blame History Raw
From 096c95690a27c942d47b20a85fa3d7fe15ffe624 Mon Sep 17 00:00:00 2001
From: Mark Reynolds <mreynolds@redhat.com>
Date: Wed, 8 Sep 2021 10:31:19 -0400
Subject: [PATCH] Issue 4910 - db reindex corrupts RUV tombstone nsuiqueid
 index

Bug Description:  During a reindex task we skip the RUV tombstone entry,
                  which corrupts the nsuniqueid index.

Fix Description:  Make sure we still index nsuniqueid index for
                  the RUV tombstone entry.

relates: https://github.com/389ds/389-ds-base/issues/4910

Reviewed by: firstyear & progier389 (Thanks!!)
---
 .../tests/suites/replication/ruvstore_test.py | 35 +++++++++++++++++++
 .../slapd/back-ldbm/db-bdb/bdb_ldif2db.c      | 12 +++++--
 2 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/dirsrvtests/tests/suites/replication/ruvstore_test.py b/dirsrvtests/tests/suites/replication/ruvstore_test.py
index c04fd079e..4e5326227 100644
--- a/dirsrvtests/tests/suites/replication/ruvstore_test.py
+++ b/dirsrvtests/tests/suites/replication/ruvstore_test.py
@@ -12,6 +12,8 @@ import ldap
 import pytest
 from ldif import LDIFParser
 from lib389.replica import Replicas
+from lib389.backend import Backends
+from lib389.idm.domain import Domain
 from lib389.idm.user import UserAccounts
 from lib389.topologies import topology_m2 as topo
 from lib389._constants import *
@@ -156,6 +158,39 @@ def test_memoryruv_sync_with_databaseruv(topo):
     _compare_memoryruv_and_databaseruv(topo, 'delete')
 
 
+def test_ruv_after_reindex(topo):
+    """Test that the tombstone RUV entry is not corrupted after a reindex task
+
+    :id: 988c0fab-1905-4dc5-a45d-fbf195843a33
+    :setup: 2 suppliers
+    :steps:
+        1. Reindex database
+        2. Perform some updates
+        3. Check error log does not have "_entryrdn_insert_key" errors
+    :expectedresults:
+        1. Success
+        2. Success
+        3. Success
+    """
+
+    inst = topo.ms['supplier1']
+    suffix = Domain(inst, "ou=people," + DEFAULT_SUFFIX)
+    backends = Backends(inst)
+    backend = backends.get(DEFAULT_BENAME)
+
+    # Reindex nsuniqueid
+    backend.reindex(attrs=['nsuniqueid'], wait=True)
+
+    # Do some updates
+    for idx in range(0, 5):
+        suffix.replace('description', str(idx))
+
+    # Check error log for RUV entryrdn errors.  Stopping instance forces RUV
+    # to be written and quickly exposes the error
+    inst.stop()
+    assert not inst.searchErrorsLog("entryrdn_insert_key")
+
+
 if __name__ == '__main__':
     # Run isolated
     # -s for DEBUG mode
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c
index 506c285a3..6100dbf77 100644
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c
@@ -25,6 +25,7 @@
 #define DB2INDEX_ENTRYRDN 0x2     /* index entryrdn */
 #define DB2LDIF_ENTRYRDN 0x4      /* export entryrdn */
 #define DB2INDEX_OBJECTCLASS 0x10 /* for reindexing "objectclass: nstombstone" */
+#define DB2INDEX_NSUNIQUEID 0x20  /* for reindexing RUV tombstone */
 
 #define LDIF2LDBM_EXTBITS(x) ((x)&0xf)
 
@@ -1543,6 +1544,9 @@ bdb_db2index(Slapi_PBlock *pb)
                     if (strcasecmp(attrs[i] + 1, SLAPI_ATTR_OBJECTCLASS) == 0) {
                         index_ext |= DB2INDEX_OBJECTCLASS;
                     }
+                    if (strcasecmp(attrs[i] + 1, SLAPI_ATTR_UNIQUEID) == 0) {
+                        index_ext |= DB2INDEX_NSUNIQUEID;
+                    }
                     charray_add(&indexAttrs, attrs[i] + 1);
                     ai->ai_indexmask |= INDEX_OFFLINE;
                     slapi_task_log_notice(task, "%s: Indexing attribute: %s",
@@ -1895,7 +1899,7 @@ bdb_db2index(Slapi_PBlock *pb)
          * Update the attribute indexes
          */
         if (indexAttrs) {
-            if (istombstone && !(index_ext & (DB2INDEX_ENTRYRDN | DB2INDEX_OBJECTCLASS))) {
+            if (istombstone && !(index_ext & (DB2INDEX_ENTRYRDN | DB2INDEX_OBJECTCLASS | DB2INDEX_NSUNIQUEID))) {
                 /* if it is a tombstone entry, just entryrdn or "objectclass: nstombstone"
                  * need to be reindexed.  the to-be-indexed list does not contain them. */
                 backentry_free(&ep);
@@ -1915,8 +1919,10 @@ bdb_db2index(Slapi_PBlock *pb)
                         if (istombstone) {
                             if (!slapi_attr_type_cmp(indexAttrs[j], SLAPI_ATTR_OBJECTCLASS, SLAPI_TYPE_CMP_SUBTYPE)) {
                                 is_tombstone_obj = 1; /* is tombstone && is objectclass. need to index "nstombstone"*/
-                            } else if (slapi_attr_type_cmp(indexAttrs[j], LDBM_ENTRYRDN_STR, SLAPI_TYPE_CMP_SUBTYPE)) {
-                                /* Entry is a tombstone && this index is not an entryrdn. */
+                            } else if (slapi_attr_type_cmp(indexAttrs[j], LDBM_ENTRYRDN_STR, SLAPI_TYPE_CMP_SUBTYPE) &&
+                                       slapi_attr_type_cmp(indexAttrs[j], SLAPI_ATTR_UNIQUEID, SLAPI_TYPE_CMP_SUBTYPE))
+                            {
+                                /* Entry is a tombstone && this index is not entryrdn or nsuniqueid */
                                 continue;
                             }
                         }
-- 
2.31.1