Blame SOURCES/0002-Ticket-51082-abort-when-a-empty-valueset-is-freed.patch

d69b2b
From 1426f086623404ab2eacb04de7e6414177c0993a Mon Sep 17 00:00:00 2001
d69b2b
From: Thierry Bordaz <tbordaz@redhat.com>
d69b2b
Date: Mon, 11 May 2020 17:11:49 +0200
d69b2b
Subject: [PATCH 02/12] Ticket 51082 - abort when a empty valueset is freed
d69b2b
d69b2b
Bug Description:
d69b2b
	A large valueset (more than 10 values) manages a sorted array of values.
d69b2b
        replication purges old values from a valueset (valueset_array_purge). If it purges all the values
d69b2b
        the valueset is freed (slapi_valueset_done).
d69b2b
        A problem is that the counter of values, in the valueset, is still reflecting the initial number
d69b2b
        of values (before the purge). When the valueset is freed (because empty) a safety checking
d69b2b
        detects incoherent values based on the wrong counter.
d69b2b
d69b2b
Fix Description:
d69b2b
	When all the values have been purge reset the counter before freeing the valueset
d69b2b
d69b2b
https://pagure.io/389-ds-base/issue/51082
d69b2b
d69b2b
Reviewed by: Mark Reynolds
d69b2b
d69b2b
Platforms tested: F30
d69b2b
d69b2b
Flag Day: no
d69b2b
d69b2b
Doc impact: no
d69b2b
---
d69b2b
 .../suites/replication/acceptance_test.py     | 57 +++++++++++++++++++
d69b2b
 ldap/servers/slapd/valueset.c                 |  4 ++
d69b2b
 2 files changed, 61 insertions(+)
d69b2b
d69b2b
diff --git a/dirsrvtests/tests/suites/replication/acceptance_test.py b/dirsrvtests/tests/suites/replication/acceptance_test.py
d69b2b
index c8e0a4c93..5009f4e7c 100644
d69b2b
--- a/dirsrvtests/tests/suites/replication/acceptance_test.py
d69b2b
+++ b/dirsrvtests/tests/suites/replication/acceptance_test.py
d69b2b
@@ -500,6 +500,63 @@ def test_warining_for_invalid_replica(topo_m4):
d69b2b
     assert topo_m4.ms["master1"].ds_error_log.match('.*nsds5ReplicaBackoffMax.*10.*invalid.*')
d69b2b
 
d69b2b
 
d69b2b
+@pytest.mark.ds51082
d69b2b
+def test_csnpurge_large_valueset(topo_m2):
d69b2b
+    """Test csn generator test
d69b2b
+
d69b2b
+    :id: 63e2bdb2-0a8f-4660-9465-7b80a9f72a74
d69b2b
+    :setup: MMR with 2 masters
d69b2b
+    :steps:
d69b2b
+        1. Create a test_user
d69b2b
+        2. add a large set of values (more than 10)
d69b2b
+        3. delete all the values (more than 10)
d69b2b
+        4. configure the replica to purge those values (purgedelay=5s)
d69b2b
+        5. Waiting for 6 second
d69b2b
+        6. do a series of update
d69b2b
+    :expectedresults:
d69b2b
+        1. Should succeeds
d69b2b
+        2. Should succeeds
d69b2b
+        3. Should succeeds
d69b2b
+        4. Should succeeds
d69b2b
+        5. Should succeeds
d69b2b
+        6. Should not crash
d69b2b
+    """
d69b2b
+    m1 = topo_m2.ms["master2"]
d69b2b
+
d69b2b
+    test_user = UserAccount(m1, TEST_ENTRY_DN)
d69b2b
+    if test_user.exists():
d69b2b
+        log.info('Deleting entry {}'.format(TEST_ENTRY_DN))
d69b2b
+        test_user.delete()
d69b2b
+    test_user.create(properties={
d69b2b
+        'uid': TEST_ENTRY_NAME,
d69b2b
+        'cn': TEST_ENTRY_NAME,
d69b2b
+        'sn': TEST_ENTRY_NAME,
d69b2b
+        'userPassword': TEST_ENTRY_NAME,
d69b2b
+        'uidNumber' : '1000',
d69b2b
+        'gidNumber' : '2000',
d69b2b
+        'homeDirectory' : '/home/mmrepl_test',
d69b2b
+    })
d69b2b
+
d69b2b
+    # create a large value set so that it is sorted
d69b2b
+    for i in range(1,20):
d69b2b
+        test_user.add('description', 'value {}'.format(str(i)))
d69b2b
+
d69b2b
+    # delete all values of the valueset
d69b2b
+    for i in range(1,20):
d69b2b
+        test_user.remove('description', 'value {}'.format(str(i)))
d69b2b
+
d69b2b
+    # set purging delay to 5 second and wait more that 5second
d69b2b
+    replicas = Replicas(m1)
d69b2b
+    replica = replicas.list()[0]
d69b2b
+    log.info('nsds5ReplicaPurgeDelay to 5')
d69b2b
+    replica.set('nsds5ReplicaPurgeDelay', '5')
d69b2b
+    time.sleep(6)
d69b2b
+
d69b2b
+    # add some new values to the valueset containing entries that should be purged
d69b2b
+    for i in range(21,25):
d69b2b
+        test_user.add('description', 'value {}'.format(str(i)))
d69b2b
+
d69b2b
+
d69b2b
 if __name__ == '__main__':
d69b2b
     # Run isolated
d69b2b
     # -s for DEBUG mode
d69b2b
diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c
d69b2b
index 2af3ee18d..12027ecb8 100644
d69b2b
--- a/ldap/servers/slapd/valueset.c
d69b2b
+++ b/ldap/servers/slapd/valueset.c
d69b2b
@@ -801,6 +801,10 @@ valueset_array_purge(const Slapi_Attr *a, Slapi_ValueSet *vs, const CSN *csn)
d69b2b
             }
d69b2b
         }
d69b2b
     } else {
d69b2b
+        /* empty valueset - reset the vs->num so that further
d69b2b
+         * checking will not abort
d69b2b
+         */
d69b2b
+        vs->num = 0;
d69b2b
         slapi_valueset_done(vs);
d69b2b
     }
d69b2b
 
d69b2b
-- 
d69b2b
2.26.2
d69b2b