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