mirror of
https://git.centos.org/rpms/389-ds-base.git
synced 2025-02-23 16:22:54 +00:00
import 389-ds-base-1.4.3.16-3.module+el8.4.0+8869+55706461
This commit is contained in:
parent
a628bce560
commit
47c2e97085
8 changed files with 1352 additions and 1 deletions
|
@ -0,0 +1,159 @@
|
||||||
|
From 81dcaf1c37c2de24c46672df8d4f968c2fb40a6e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mark Reynolds <mreynolds@redhat.com>
|
||||||
|
Date: Wed, 11 Nov 2020 08:59:18 -0500
|
||||||
|
Subject: [PATCH 1/3] Issue 4383 - Do not normalize escaped spaces in a DN
|
||||||
|
|
||||||
|
Bug Description: Adding an entry with an escaped leading space leads to many
|
||||||
|
problems. Mainly id2entry can get corrupted during an
|
||||||
|
import of such an entry, and the entryrdn index is not
|
||||||
|
updated correctly
|
||||||
|
|
||||||
|
Fix Description: In slapi_dn_normalize_ext() leave an escaped space intact.
|
||||||
|
|
||||||
|
Relates: https://github.com/389ds/389-ds-base/issues/4383
|
||||||
|
|
||||||
|
Reviewed by: firstyear, progier, and tbordaz (Thanks!!!)
|
||||||
|
---
|
||||||
|
.../tests/suites/syntax/acceptance_test.py | 75 ++++++++++++++++++-
|
||||||
|
ldap/servers/slapd/dn.c | 8 +-
|
||||||
|
2 files changed, 77 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dirsrvtests/tests/suites/syntax/acceptance_test.py b/dirsrvtests/tests/suites/syntax/acceptance_test.py
|
||||||
|
index 543718689..7939a99a7 100644
|
||||||
|
--- a/dirsrvtests/tests/suites/syntax/acceptance_test.py
|
||||||
|
+++ b/dirsrvtests/tests/suites/syntax/acceptance_test.py
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
# --- BEGIN COPYRIGHT BLOCK ---
|
||||||
|
-# Copyright (C) 2019 Red Hat, Inc.
|
||||||
|
+# Copyright (C) 2020 Red Hat, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# License: GPL (version 3 or any later version).
|
||||||
|
@@ -7,13 +7,12 @@
|
||||||
|
# --- END COPYRIGHT BLOCK ---
|
||||||
|
|
||||||
|
import ldap
|
||||||
|
-import logging
|
||||||
|
import pytest
|
||||||
|
import os
|
||||||
|
from lib389.schema import Schema
|
||||||
|
from lib389.config import Config
|
||||||
|
from lib389.idm.user import UserAccounts
|
||||||
|
-from lib389.idm.group import Groups
|
||||||
|
+from lib389.idm.group import Group, Groups
|
||||||
|
from lib389._constants import DEFAULT_SUFFIX
|
||||||
|
from lib389.topologies import log, topology_st as topo
|
||||||
|
|
||||||
|
@@ -127,7 +126,7 @@ def test_invalid_dn_syntax_crash(topo):
|
||||||
|
4. Success
|
||||||
|
"""
|
||||||
|
|
||||||
|
- # Create group
|
||||||
|
+ # Create group
|
||||||
|
groups = Groups(topo.standalone, DEFAULT_SUFFIX)
|
||||||
|
group = groups.create(properties={'cn': ' test'})
|
||||||
|
|
||||||
|
@@ -145,6 +144,74 @@ def test_invalid_dn_syntax_crash(topo):
|
||||||
|
groups.list()
|
||||||
|
|
||||||
|
|
||||||
|
+@pytest.mark.parametrize("props, rawdn", [
|
||||||
|
+ ({'cn': ' leadingSpace'}, "cn=\\20leadingSpace,ou=Groups,dc=example,dc=com"),
|
||||||
|
+ ({'cn': 'trailingSpace '}, "cn=trailingSpace\\20,ou=Groups,dc=example,dc=com")])
|
||||||
|
+def test_dn_syntax_spaces_delete(topo, props, rawdn):
|
||||||
|
+ """Test that an entry with a space as the first character in the DN can be
|
||||||
|
+ deleted without error. We also want to make sure the indexes are properly
|
||||||
|
+ updated by repeatedly adding and deleting the entry, and that the entry cache
|
||||||
|
+ is properly maintained.
|
||||||
|
+
|
||||||
|
+ :id: b993f37c-c2b0-4312-992c-a9048ff98965
|
||||||
|
+ :parametrized: yes
|
||||||
|
+ :setup: Standalone Instance
|
||||||
|
+ :steps:
|
||||||
|
+ 1. Create a group with a DN that has a space as the first/last
|
||||||
|
+ character.
|
||||||
|
+ 2. Delete group
|
||||||
|
+ 3. Add group
|
||||||
|
+ 4. Modify group
|
||||||
|
+ 5. Restart server and modify entry
|
||||||
|
+ 6. Delete group
|
||||||
|
+ 7. Add group back
|
||||||
|
+ 8. Delete group using specific DN
|
||||||
|
+ :expectedresults:
|
||||||
|
+ 1. Success
|
||||||
|
+ 2. Success
|
||||||
|
+ 3. Success
|
||||||
|
+ 4. Success
|
||||||
|
+ 5. Success
|
||||||
|
+ 6. Success
|
||||||
|
+ 7. Success
|
||||||
|
+ 8. Success
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ # Create group
|
||||||
|
+ groups = Groups(topo.standalone, DEFAULT_SUFFIX)
|
||||||
|
+ group = groups.create(properties=props.copy())
|
||||||
|
+
|
||||||
|
+ # Delete group (verifies DN/RDN parsing works and cache is correct)
|
||||||
|
+ group.delete()
|
||||||
|
+
|
||||||
|
+ # Add group again (verifies entryrdn index was properly updated)
|
||||||
|
+ groups = Groups(topo.standalone, DEFAULT_SUFFIX)
|
||||||
|
+ group = groups.create(properties=props.copy())
|
||||||
|
+
|
||||||
|
+ # Modify the group (verifies dn/rdn parsing is correct)
|
||||||
|
+ group.replace('description', 'escaped space group')
|
||||||
|
+
|
||||||
|
+ # Restart the server. This will pull the entry from the database and
|
||||||
|
+ # convert it into a cache entry, which is different than how a client
|
||||||
|
+ # first adds an entry and is put into the cache before being written to
|
||||||
|
+ # disk.
|
||||||
|
+ topo.standalone.restart()
|
||||||
|
+
|
||||||
|
+ # Make sure we can modify the entry (verifies cache entry was created
|
||||||
|
+ # correctly)
|
||||||
|
+ group.replace('description', 'escaped space group after restart')
|
||||||
|
+
|
||||||
|
+ # Make sure it can still be deleted (verifies cache again).
|
||||||
|
+ group.delete()
|
||||||
|
+
|
||||||
|
+ # Add it back so we can delete it using a specific DN (sanity test to verify
|
||||||
|
+ # another DN/RDN parsing variation).
|
||||||
|
+ groups = Groups(topo.standalone, DEFAULT_SUFFIX)
|
||||||
|
+ group = groups.create(properties=props.copy())
|
||||||
|
+ group = Group(topo.standalone, dn=rawdn)
|
||||||
|
+ group.delete()
|
||||||
|
+
|
||||||
|
+
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Run isolated
|
||||||
|
# -s for DEBUG mode
|
||||||
|
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
|
||||||
|
index 2af3f38fc..3980b897f 100644
|
||||||
|
--- a/ldap/servers/slapd/dn.c
|
||||||
|
+++ b/ldap/servers/slapd/dn.c
|
||||||
|
@@ -894,8 +894,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- } else if (s + 2 < ends &&
|
||||||
|
- isxdigit(*(s + 1)) && isxdigit(*(s + 2))) {
|
||||||
|
+ } else if (s + 2 < ends && isxdigit(*(s + 1)) && isxdigit(*(s + 2))) {
|
||||||
|
/* esc hexpair ==> real character */
|
||||||
|
int n = slapi_hexchar2int(*(s + 1));
|
||||||
|
int n2 = slapi_hexchar2int(*(s + 2));
|
||||||
|
@@ -903,6 +902,11 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
|
||||||
|
if (n == 0) { /* don't change \00 */
|
||||||
|
*d++ = *++s;
|
||||||
|
*d++ = *++s;
|
||||||
|
+ } else if (n == 32) { /* leave \20 (space) intact */
|
||||||
|
+ *d++ = *s;
|
||||||
|
+ *d++ = *++s;
|
||||||
|
+ *d++ = *++s;
|
||||||
|
+ s++;
|
||||||
|
} else {
|
||||||
|
*d++ = n;
|
||||||
|
s += 3;
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
From 29c9e1c3c760f0941b022d45d14c248e9ceb9738 Mon Sep 17 00:00:00 2001
|
||||||
|
From: progier389 <72748589+progier389@users.noreply.github.com>
|
||||||
|
Date: Tue, 3 Nov 2020 12:18:50 +0100
|
||||||
|
Subject: [PATCH 2/3] ticket 2058: Add keep alive entry after on-line
|
||||||
|
initialization - second version (#4399)
|
||||||
|
|
||||||
|
Bug description:
|
||||||
|
Keep alive entry is not created on target master after on line initialization,
|
||||||
|
and its RUVelement stays empty until a direct update is issued on that master
|
||||||
|
|
||||||
|
Fix description:
|
||||||
|
The patch allows a consumer (configured as a master) to create (if it did not
|
||||||
|
exist before) the consumer's keep alive entry. It creates it at the end of a
|
||||||
|
replication session at a time we are sure the changelog exists and will not
|
||||||
|
be reset. It allows a consumer to have RUVelement with csn in the RUV at the
|
||||||
|
first incoming replication session.
|
||||||
|
|
||||||
|
That is basically lkrispen's proposal with an associated pytest testcase
|
||||||
|
|
||||||
|
Second version changes:
|
||||||
|
- moved the testcase to suites/replication/regression_test.py
|
||||||
|
- set up the topology from a 2 master topology then
|
||||||
|
reinitialized the replicas from an ldif without replication metadata
|
||||||
|
rather than using the cli.
|
||||||
|
- search for keepalive entries using search_s instead of getEntry
|
||||||
|
- add a comment about keep alive entries purpose
|
||||||
|
|
||||||
|
last commit:
|
||||||
|
- wait that ruv are in sync before checking keep alive entries
|
||||||
|
|
||||||
|
Reviewed by: droideck, Firstyear
|
||||||
|
|
||||||
|
Platforms tested: F32
|
||||||
|
|
||||||
|
relates: #2058
|
||||||
|
---
|
||||||
|
.../suites/replication/regression_test.py | 130 ++++++++++++++++++
|
||||||
|
.../plugins/replication/repl5_replica.c | 14 ++
|
||||||
|
ldap/servers/plugins/replication/repl_extop.c | 4 +
|
||||||
|
3 files changed, 148 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/dirsrvtests/tests/suites/replication/regression_test.py b/dirsrvtests/tests/suites/replication/regression_test.py
|
||||||
|
index 844d762b9..14b9d6a44 100644
|
||||||
|
--- a/dirsrvtests/tests/suites/replication/regression_test.py
|
||||||
|
+++ b/dirsrvtests/tests/suites/replication/regression_test.py
|
||||||
|
@@ -98,6 +98,30 @@ def _move_ruv(ldif_file):
|
||||||
|
for dn, entry in ldif_list:
|
||||||
|
ldif_writer.unparse(dn, entry)
|
||||||
|
|
||||||
|
+def _remove_replication_data(ldif_file):
|
||||||
|
+ """ Remove the replication data from ldif file:
|
||||||
|
+ db2lif without -r includes some of the replica data like
|
||||||
|
+ - nsUniqueId
|
||||||
|
+ - keepalive entries
|
||||||
|
+ This function filters the ldif fil to remove these data
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ with open(ldif_file) as f:
|
||||||
|
+ parser = ldif.LDIFRecordList(f)
|
||||||
|
+ parser.parse()
|
||||||
|
+
|
||||||
|
+ ldif_list = parser.all_records
|
||||||
|
+ # Iterate on a copy of the ldif entry list
|
||||||
|
+ for dn, entry in ldif_list[:]:
|
||||||
|
+ if dn.startswith('cn=repl keep alive'):
|
||||||
|
+ ldif_list.remove((dn,entry))
|
||||||
|
+ else:
|
||||||
|
+ entry.pop('nsUniqueId')
|
||||||
|
+ with open(ldif_file, 'w') as f:
|
||||||
|
+ ldif_writer = ldif.LDIFWriter(f)
|
||||||
|
+ for dn, entry in ldif_list:
|
||||||
|
+ ldif_writer.unparse(dn, entry)
|
||||||
|
+
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def topo_with_sigkill(request):
|
||||||
|
@@ -897,6 +921,112 @@ def test_moving_entry_make_online_init_fail(topology_m2):
|
||||||
|
assert len(m1entries) == len(m2entries)
|
||||||
|
|
||||||
|
|
||||||
|
+def get_keepalive_entries(instance,replica):
|
||||||
|
+ # Returns the keep alive entries that exists with the suffix of the server instance
|
||||||
|
+ try:
|
||||||
|
+ entries = instance.search_s(replica.get_suffix(), ldap.SCOPE_ONELEVEL,
|
||||||
|
+ "(&(objectclass=ldapsubentry)(cn=repl keep alive*))",
|
||||||
|
+ ['cn', 'nsUniqueId', 'modifierTimestamp'])
|
||||||
|
+ except ldap.LDAPError as e:
|
||||||
|
+ log.fatal('Failed to retrieve keepalive entry (%s) on instance %s: error %s' % (dn, instance, str(e)))
|
||||||
|
+ assert False
|
||||||
|
+ # No error, so lets log the keepalive entries
|
||||||
|
+ if log.isEnabledFor(logging.DEBUG):
|
||||||
|
+ for ret in entries:
|
||||||
|
+ log.debug("Found keepalive entry:\n"+str(ret));
|
||||||
|
+ return entries
|
||||||
|
+
|
||||||
|
+def verify_keepalive_entries(topo, expected):
|
||||||
|
+ #Check that keep alive entries exists (or not exists) for every masters on every masters
|
||||||
|
+ #Note: The testing method is quite basic: counting that there is one keepalive entry per master.
|
||||||
|
+ # that is ok for simple test cases like test_online_init_should_create_keepalive_entries but
|
||||||
|
+ # not for the general case as keep alive associated with no more existing master may exists
|
||||||
|
+ # (for example after: db2ldif / demote a master / ldif2db / init other masters)
|
||||||
|
+ # ==> if the function is somehow pushed in lib389, a check better than simply counting the entries
|
||||||
|
+ # should be done.
|
||||||
|
+ for masterId in topo.ms:
|
||||||
|
+ master=topo.ms[masterId]
|
||||||
|
+ for replica in Replicas(master).list():
|
||||||
|
+ if (replica.get_role() != ReplicaRole.MASTER):
|
||||||
|
+ continue
|
||||||
|
+ replica_info = f'master: {masterId} RID: {replica.get_rid()} suffix: {replica.get_suffix()}'
|
||||||
|
+ log.debug(f'Checking keepAliveEntries on {replica_info}')
|
||||||
|
+ keepaliveEntries = get_keepalive_entries(master, replica);
|
||||||
|
+ expectedCount = len(topo.ms) if expected else 0
|
||||||
|
+ foundCount = len(keepaliveEntries)
|
||||||
|
+ if (foundCount == expectedCount):
|
||||||
|
+ log.debug(f'Found {foundCount} keepalive entries as expected on {replica_info}.')
|
||||||
|
+ else:
|
||||||
|
+ log.error(f'{foundCount} Keepalive entries are found '
|
||||||
|
+ f'while {expectedCount} were expected on {replica_info}.')
|
||||||
|
+ assert False
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def test_online_init_should_create_keepalive_entries(topo_m2):
|
||||||
|
+ """Check that keep alive entries are created when initializinf a master from another one
|
||||||
|
+
|
||||||
|
+ :id: d5940e71-d18a-4b71-aaf7-b9185361fffe
|
||||||
|
+ :setup: Two masters replication setup
|
||||||
|
+ :steps:
|
||||||
|
+ 1. Generate ldif without replication data
|
||||||
|
+ 2 Init both masters from that ldif
|
||||||
|
+ 3 Check that keep alive entries does not exists
|
||||||
|
+ 4 Perform on line init of master2 from master1
|
||||||
|
+ 5 Check that keep alive entries exists
|
||||||
|
+ :expectedresults:
|
||||||
|
+ 1. No error while generating ldif
|
||||||
|
+ 2. No error while importing the ldif file
|
||||||
|
+ 3. No keepalive entrie should exists on any masters
|
||||||
|
+ 4. No error while initializing master2
|
||||||
|
+ 5. All keepalive entries should exist on every masters
|
||||||
|
+
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||||
|
+ m1 = topo_m2.ms["master1"]
|
||||||
|
+ m2 = topo_m2.ms["master2"]
|
||||||
|
+ # Step 1: Generate ldif without replication data
|
||||||
|
+ m1.stop()
|
||||||
|
+ m2.stop()
|
||||||
|
+ ldif_file = '%s/norepl.ldif' % m1.get_ldif_dir()
|
||||||
|
+ m1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX],
|
||||||
|
+ excludeSuffixes=None, repl_data=False,
|
||||||
|
+ outputfile=ldif_file, encrypt=False)
|
||||||
|
+ # Remove replication metadata that are still in the ldif
|
||||||
|
+ _remove_replication_data(ldif_file)
|
||||||
|
+
|
||||||
|
+ # Step 2: Init both masters from that ldif
|
||||||
|
+ m1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file)
|
||||||
|
+ m2.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file)
|
||||||
|
+ m1.start()
|
||||||
|
+ m2.start()
|
||||||
|
+
|
||||||
|
+ """ Replica state is now as if CLI setup has been done using:
|
||||||
|
+ dsconf master1 replication enable --suffix "${SUFFIX}" --role master
|
||||||
|
+ dsconf master2 replication enable --suffix "${SUFFIX}" --role master
|
||||||
|
+ dsconf master1 replication create-manager --name "${REPLICATION_MANAGER_NAME}" --passwd "${REPLICATION_MANAGER_PASSWORD}"
|
||||||
|
+ dsconf master2 replication create-manager --name "${REPLICATION_MANAGER_NAME}" --passwd "${REPLICATION_MANAGER_PASSWORD}"
|
||||||
|
+ dsconf master1 repl-agmt create --suffix "${SUFFIX}"
|
||||||
|
+ dsconf master2 repl-agmt create --suffix "${SUFFIX}"
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ # Step 3: No keepalive entrie should exists on any masters
|
||||||
|
+ verify_keepalive_entries(topo_m2, False)
|
||||||
|
+
|
||||||
|
+ # Step 4: Perform on line init of master2 from master1
|
||||||
|
+ agmt = Agreements(m1).list()[0]
|
||||||
|
+ agmt.begin_reinit()
|
||||||
|
+ (done, error) = agmt.wait_reinit()
|
||||||
|
+ assert done is True
|
||||||
|
+ assert error is False
|
||||||
|
+
|
||||||
|
+ # Step 5: All keepalive entries should exists on every masters
|
||||||
|
+ # Verify the keep alive entry once replication is in sync
|
||||||
|
+ # (that is the step that fails when bug is not fixed)
|
||||||
|
+ repl.wait_for_ruv(m2,m1)
|
||||||
|
+ verify_keepalive_entries(topo_m2, True);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Run isolated
|
||||||
|
# -s for DEBUG mode
|
||||||
|
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
|
||||||
|
index f01782330..f0ea0f8ef 100644
|
||||||
|
--- a/ldap/servers/plugins/replication/repl5_replica.c
|
||||||
|
+++ b/ldap/servers/plugins/replication/repl5_replica.c
|
||||||
|
@@ -373,6 +373,20 @@ replica_destroy(void **arg)
|
||||||
|
slapi_ch_free((void **)arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
+/******************************************************************************
|
||||||
|
+ ******************** REPLICATION KEEP ALIVE ENTRIES **************************
|
||||||
|
+ ******************************************************************************
|
||||||
|
+ * They are subentries of the replicated suffix and there is one per master. *
|
||||||
|
+ * These entries exist only to trigger a change that get replicated over the *
|
||||||
|
+ * topology. *
|
||||||
|
+ * Their main purpose is to generate records in the changelog and they are *
|
||||||
|
+ * updated from time to time by fractional replication to insure that at *
|
||||||
|
+ * least a change must be replicated by FR after a great number of not *
|
||||||
|
+ * replicated changes are found in the changelog. The interest is that the *
|
||||||
|
+ * fractional RUV get then updated so less changes need to be walked in the *
|
||||||
|
+ * changelog when searching for the first change to send *
|
||||||
|
+ ******************************************************************************/
|
||||||
|
+
|
||||||
|
#define KEEP_ALIVE_ATTR "keepalivetimestamp"
|
||||||
|
#define KEEP_ALIVE_ENTRY "repl keep alive"
|
||||||
|
#define KEEP_ALIVE_DN_FORMAT "cn=%s %d,%s"
|
||||||
|
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
|
||||||
|
index 14c8e0bcc..af486f730 100644
|
||||||
|
--- a/ldap/servers/plugins/replication/repl_extop.c
|
||||||
|
+++ b/ldap/servers/plugins/replication/repl_extop.c
|
||||||
|
@@ -1173,6 +1173,10 @@ multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb)
|
||||||
|
*/
|
||||||
|
if (cl5GetState() == CL5_STATE_OPEN) {
|
||||||
|
replica_log_ruv_elements(r);
|
||||||
|
+ /* now that the changelog is open and started, we can alos cretae the
|
||||||
|
+ * keep alive entry without risk that db and cl will not match
|
||||||
|
+ */
|
||||||
|
+ replica_subentry_check(replica_get_root(r), replica_get_rid(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ONREPL code that dealt with new RUV, etc was moved into the code
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
|
@ -0,0 +1,513 @@
|
||||||
|
From e202c62c3b4c92163d2de9f3da9a9f3efc81e4b8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: progier389 <72748589+progier389@users.noreply.github.com>
|
||||||
|
Date: Thu, 12 Nov 2020 18:50:04 +0100
|
||||||
|
Subject: [PATCH 3/3] do not add referrals for masters with different data
|
||||||
|
generation #2054 (#4427)
|
||||||
|
|
||||||
|
Bug description:
|
||||||
|
The problem is that some operation mandatory in the usual cases are
|
||||||
|
also performed when replication cannot take place because the
|
||||||
|
database set are differents (i.e: RUV generation ids are different)
|
||||||
|
|
||||||
|
One of the issue is that the csn generator state is updated when
|
||||||
|
starting a replication session (it is a problem when trying to
|
||||||
|
reset the time skew, as freshly reinstalled replicas get infected
|
||||||
|
by the old ones)
|
||||||
|
|
||||||
|
A second issue is that the RUV got updated when ending a replication session
|
||||||
|
(which may add replica that does not share the same data set,
|
||||||
|
then update operations on consumer retun referrals towards wrong masters
|
||||||
|
|
||||||
|
Fix description:
|
||||||
|
The fix checks the RUVs generation id before updating the csn generator
|
||||||
|
and before updating the RUV.
|
||||||
|
|
||||||
|
Reviewed by: mreynolds
|
||||||
|
firstyear
|
||||||
|
vashirov
|
||||||
|
|
||||||
|
Platforms tested: F32
|
||||||
|
---
|
||||||
|
.../suites/replication/regression_test.py | 290 ++++++++++++++++++
|
||||||
|
ldap/servers/plugins/replication/repl5.h | 1 +
|
||||||
|
.../plugins/replication/repl5_inc_protocol.c | 20 +-
|
||||||
|
.../plugins/replication/repl5_replica.c | 39 ++-
|
||||||
|
src/lib389/lib389/dseldif.py | 37 +++
|
||||||
|
5 files changed, 368 insertions(+), 19 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/dirsrvtests/tests/suites/replication/regression_test.py b/dirsrvtests/tests/suites/replication/regression_test.py
|
||||||
|
index 14b9d6a44..a72af6b30 100644
|
||||||
|
--- a/dirsrvtests/tests/suites/replication/regression_test.py
|
||||||
|
+++ b/dirsrvtests/tests/suites/replication/regression_test.py
|
||||||
|
@@ -13,6 +13,7 @@ from lib389.idm.user import TEST_USER_PROPERTIES, UserAccounts
|
||||||
|
from lib389.pwpolicy import PwPolicyManager
|
||||||
|
from lib389.utils import *
|
||||||
|
from lib389.topologies import topology_m2 as topo_m2, TopologyMain, topology_m3 as topo_m3, create_topology, _remove_ssca_db, topology_i2 as topo_i2
|
||||||
|
+from lib389.topologies import topology_m2c2 as topo_m2c2
|
||||||
|
from lib389._constants import *
|
||||||
|
from lib389.idm.organizationalunit import OrganizationalUnits
|
||||||
|
from lib389.idm.user import UserAccount
|
||||||
|
@@ -22,6 +23,7 @@ from lib389.idm.directorymanager import DirectoryManager
|
||||||
|
from lib389.replica import Replicas, ReplicationManager, Changelog5, BootstrapReplicationManager
|
||||||
|
from lib389.agreement import Agreements
|
||||||
|
from lib389 import pid_from_file
|
||||||
|
+from lib389.dseldif import *
|
||||||
|
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.tier1
|
||||||
|
@@ -1027,6 +1029,294 @@ def test_online_init_should_create_keepalive_entries(topo_m2):
|
||||||
|
verify_keepalive_entries(topo_m2, True);
|
||||||
|
|
||||||
|
|
||||||
|
+def get_agreement(agmts, consumer):
|
||||||
|
+ # Get agreement towards consumer among the agremment list
|
||||||
|
+ for agmt in agmts.list():
|
||||||
|
+ if (agmt.get_attr_val_utf8('nsDS5ReplicaPort') == str(consumer.port) and
|
||||||
|
+ agmt.get_attr_val_utf8('nsDS5ReplicaHost') == consumer.host):
|
||||||
|
+ return agmt
|
||||||
|
+ return None;
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def test_ruv_url_not_added_if_different_uuid(topo_m2c2):
|
||||||
|
+ """Check that RUV url is not updated if RUV generation uuid are different
|
||||||
|
+
|
||||||
|
+ :id: 7cc30a4e-0ffd-4758-8f00-e500279af344
|
||||||
|
+ :setup: Two masters + two consumers replication setup
|
||||||
|
+ :steps:
|
||||||
|
+ 1. Generate ldif without replication data
|
||||||
|
+ 2. Init both masters from that ldif
|
||||||
|
+ (to clear the ruvs and generates different generation uuid)
|
||||||
|
+ 3. Perform on line init from master1 to consumer1
|
||||||
|
+ and from master2 to consumer2
|
||||||
|
+ 4. Perform update on both masters
|
||||||
|
+ 5. Check that c1 RUV does not contains URL towards m2
|
||||||
|
+ 6. Check that c2 RUV does contains URL towards m2
|
||||||
|
+ 7. Perform on line init from master1 to master2
|
||||||
|
+ 8. Perform update on master2
|
||||||
|
+ 9. Check that c1 RUV does contains URL towards m2
|
||||||
|
+ :expectedresults:
|
||||||
|
+ 1. No error while generating ldif
|
||||||
|
+ 2. No error while importing the ldif file
|
||||||
|
+ 3. No error and Initialization done.
|
||||||
|
+ 4. No error
|
||||||
|
+ 5. master2 replicaid should not be in the consumer1 RUV
|
||||||
|
+ 6. master2 replicaid should be in the consumer2 RUV
|
||||||
|
+ 7. No error and Initialization done.
|
||||||
|
+ 8. No error
|
||||||
|
+ 9. master2 replicaid should be in the consumer1 RUV
|
||||||
|
+
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ # Variables initialization
|
||||||
|
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||||
|
+
|
||||||
|
+ m1 = topo_m2c2.ms["master1"]
|
||||||
|
+ m2 = topo_m2c2.ms["master2"]
|
||||||
|
+ c1 = topo_m2c2.cs["consumer1"]
|
||||||
|
+ c2 = topo_m2c2.cs["consumer2"]
|
||||||
|
+
|
||||||
|
+ replica_m1 = Replicas(m1).get(DEFAULT_SUFFIX)
|
||||||
|
+ replica_m2 = Replicas(m2).get(DEFAULT_SUFFIX)
|
||||||
|
+ replica_c1 = Replicas(c1).get(DEFAULT_SUFFIX)
|
||||||
|
+ replica_c2 = Replicas(c2).get(DEFAULT_SUFFIX)
|
||||||
|
+
|
||||||
|
+ replicid_m2 = replica_m2.get_rid()
|
||||||
|
+
|
||||||
|
+ agmts_m1 = Agreements(m1, replica_m1.dn)
|
||||||
|
+ agmts_m2 = Agreements(m2, replica_m2.dn)
|
||||||
|
+
|
||||||
|
+ m1_m2 = get_agreement(agmts_m1, m2)
|
||||||
|
+ m1_c1 = get_agreement(agmts_m1, c1)
|
||||||
|
+ m1_c2 = get_agreement(agmts_m1, c2)
|
||||||
|
+ m2_m1 = get_agreement(agmts_m2, m1)
|
||||||
|
+ m2_c1 = get_agreement(agmts_m2, c1)
|
||||||
|
+ m2_c2 = get_agreement(agmts_m2, c2)
|
||||||
|
+
|
||||||
|
+ # Step 1: Generate ldif without replication data
|
||||||
|
+ m1.stop()
|
||||||
|
+ m2.stop()
|
||||||
|
+ ldif_file = '%s/norepl.ldif' % m1.get_ldif_dir()
|
||||||
|
+ m1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX],
|
||||||
|
+ excludeSuffixes=None, repl_data=False,
|
||||||
|
+ outputfile=ldif_file, encrypt=False)
|
||||||
|
+ # Remove replication metadata that are still in the ldif
|
||||||
|
+ # _remove_replication_data(ldif_file)
|
||||||
|
+
|
||||||
|
+ # Step 2: Init both masters from that ldif
|
||||||
|
+ m1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file)
|
||||||
|
+ m2.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file)
|
||||||
|
+ m1.start()
|
||||||
|
+ m2.start()
|
||||||
|
+
|
||||||
|
+ # Step 3: Perform on line init from master1 to consumer1
|
||||||
|
+ # and from master2 to consumer2
|
||||||
|
+ m1_c1.begin_reinit()
|
||||||
|
+ m2_c2.begin_reinit()
|
||||||
|
+ (done, error) = m1_c1.wait_reinit()
|
||||||
|
+ assert done is True
|
||||||
|
+ assert error is False
|
||||||
|
+ (done, error) = m2_c2.wait_reinit()
|
||||||
|
+ assert done is True
|
||||||
|
+ assert error is False
|
||||||
|
+
|
||||||
|
+ # Step 4: Perform update on both masters
|
||||||
|
+ repl.test_replication(m1, c1)
|
||||||
|
+ repl.test_replication(m2, c2)
|
||||||
|
+
|
||||||
|
+ # Step 5: Check that c1 RUV does not contains URL towards m2
|
||||||
|
+ ruv = replica_c1.get_ruv()
|
||||||
|
+ log.debug(f"c1 RUV: {ruv}")
|
||||||
|
+ url=ruv._rid_url.get(replica_m2.get_rid())
|
||||||
|
+ if (url == None):
|
||||||
|
+ log.debug(f"No URL for RID {replica_m2.get_rid()} in RUV");
|
||||||
|
+ else:
|
||||||
|
+ log.debug(f"URL for RID {replica_m2.get_rid()} in RUV is {url}");
|
||||||
|
+ log.error(f"URL for RID {replica_m2.get_rid()} found in RUV")
|
||||||
|
+ #Note: this assertion fails if issue 2054 is not fixed.
|
||||||
|
+ assert False
|
||||||
|
+
|
||||||
|
+ # Step 6: Check that c2 RUV does contains URL towards m2
|
||||||
|
+ ruv = replica_c2.get_ruv()
|
||||||
|
+ log.debug(f"c1 RUV: {ruv} {ruv._rids} ")
|
||||||
|
+ url=ruv._rid_url.get(replica_m2.get_rid())
|
||||||
|
+ if (url == None):
|
||||||
|
+ log.error(f"No URL for RID {replica_m2.get_rid()} in RUV");
|
||||||
|
+ assert False
|
||||||
|
+ else:
|
||||||
|
+ log.debug(f"URL for RID {replica_m2.get_rid()} in RUV is {url}");
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ # Step 7: Perform on line init from master1 to master2
|
||||||
|
+ m1_m2.begin_reinit()
|
||||||
|
+ (done, error) = m1_m2.wait_reinit()
|
||||||
|
+ assert done is True
|
||||||
|
+ assert error is False
|
||||||
|
+
|
||||||
|
+ # Step 8: Perform update on master2
|
||||||
|
+ repl.test_replication(m2, c1)
|
||||||
|
+
|
||||||
|
+ # Step 9: Check that c1 RUV does contains URL towards m2
|
||||||
|
+ ruv = replica_c1.get_ruv()
|
||||||
|
+ log.debug(f"c1 RUV: {ruv} {ruv._rids} ")
|
||||||
|
+ url=ruv._rid_url.get(replica_m2.get_rid())
|
||||||
|
+ if (url == None):
|
||||||
|
+ log.error(f"No URL for RID {replica_m2.get_rid()} in RUV");
|
||||||
|
+ assert False
|
||||||
|
+ else:
|
||||||
|
+ log.debug(f"URL for RID {replica_m2.get_rid()} in RUV is {url}");
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+def test_csngen_state_not_updated_if_different_uuid(topo_m2c2):
|
||||||
|
+ """Check that csngen remote offset is not updated if RUV generation uuid are different
|
||||||
|
+
|
||||||
|
+ :id: 77694b8e-22ae-11eb-89b2-482ae39447e5
|
||||||
|
+ :setup: Two masters + two consumers replication setup
|
||||||
|
+ :steps:
|
||||||
|
+ 1. Disable m1<->m2 agreement to avoid propagate timeSkew
|
||||||
|
+ 2. Generate ldif without replication data
|
||||||
|
+ 3. Increase time skew on master2
|
||||||
|
+ 4. Init both masters from that ldif
|
||||||
|
+ (to clear the ruvs and generates different generation uuid)
|
||||||
|
+ 5. Perform on line init from master1 to consumer1 and master2 to consumer2
|
||||||
|
+ 6. Perform update on both masters
|
||||||
|
+ 7: Check that c1 has no time skew
|
||||||
|
+ 8: Check that c2 has time skew
|
||||||
|
+ 9. Init master2 from master1
|
||||||
|
+ 10. Perform update on master2
|
||||||
|
+ 11. Check that c1 has time skew
|
||||||
|
+ :expectedresults:
|
||||||
|
+ 1. No error
|
||||||
|
+ 2. No error while generating ldif
|
||||||
|
+ 3. No error
|
||||||
|
+ 4. No error while importing the ldif file
|
||||||
|
+ 5. No error and Initialization done.
|
||||||
|
+ 6. No error
|
||||||
|
+ 7. c1 time skew should be lesser than threshold
|
||||||
|
+ 8. c2 time skew should be higher than threshold
|
||||||
|
+ 9. No error and Initialization done.
|
||||||
|
+ 10. No error
|
||||||
|
+ 11. c1 time skew should be higher than threshold
|
||||||
|
+
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ # Variables initialization
|
||||||
|
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||||
|
+
|
||||||
|
+ m1 = topo_m2c2.ms["master1"]
|
||||||
|
+ m2 = topo_m2c2.ms["master2"]
|
||||||
|
+ c1 = topo_m2c2.cs["consumer1"]
|
||||||
|
+ c2 = topo_m2c2.cs["consumer2"]
|
||||||
|
+
|
||||||
|
+ replica_m1 = Replicas(m1).get(DEFAULT_SUFFIX)
|
||||||
|
+ replica_m2 = Replicas(m2).get(DEFAULT_SUFFIX)
|
||||||
|
+ replica_c1 = Replicas(c1).get(DEFAULT_SUFFIX)
|
||||||
|
+ replica_c2 = Replicas(c2).get(DEFAULT_SUFFIX)
|
||||||
|
+
|
||||||
|
+ replicid_m2 = replica_m2.get_rid()
|
||||||
|
+
|
||||||
|
+ agmts_m1 = Agreements(m1, replica_m1.dn)
|
||||||
|
+ agmts_m2 = Agreements(m2, replica_m2.dn)
|
||||||
|
+
|
||||||
|
+ m1_m2 = get_agreement(agmts_m1, m2)
|
||||||
|
+ m1_c1 = get_agreement(agmts_m1, c1)
|
||||||
|
+ m1_c2 = get_agreement(agmts_m1, c2)
|
||||||
|
+ m2_m1 = get_agreement(agmts_m2, m1)
|
||||||
|
+ m2_c1 = get_agreement(agmts_m2, c1)
|
||||||
|
+ m2_c2 = get_agreement(agmts_m2, c2)
|
||||||
|
+
|
||||||
|
+ # Step 1: Disable m1<->m2 agreement to avoid propagate timeSkew
|
||||||
|
+ m1_m2.pause()
|
||||||
|
+ m2_m1.pause()
|
||||||
|
+
|
||||||
|
+ # Step 2: Generate ldif without replication data
|
||||||
|
+ m1.stop()
|
||||||
|
+ m2.stop()
|
||||||
|
+ ldif_file = '%s/norepl.ldif' % m1.get_ldif_dir()
|
||||||
|
+ m1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX],
|
||||||
|
+ excludeSuffixes=None, repl_data=False,
|
||||||
|
+ outputfile=ldif_file, encrypt=False)
|
||||||
|
+ # Remove replication metadata that are still in the ldif
|
||||||
|
+ # _remove_replication_data(ldif_file)
|
||||||
|
+
|
||||||
|
+ # Step 3: Increase time skew on master2
|
||||||
|
+ timeSkew=6*3600
|
||||||
|
+ # We can modify master2 time skew
|
||||||
|
+ # But the time skew on the consumer may be smaller
|
||||||
|
+ # depending on when the cnsgen generation time is updated
|
||||||
|
+ # and when first csn get replicated.
|
||||||
|
+ # Since we use timeSkew has threshold value to detect
|
||||||
|
+ # whether there are time skew or not,
|
||||||
|
+ # lets add a significative margin (longer than the test duration)
|
||||||
|
+ # to avoid any risk of erroneous failure
|
||||||
|
+ timeSkewMargin = 300
|
||||||
|
+ DSEldif(m2)._increaseTimeSkew(DEFAULT_SUFFIX, timeSkew+timeSkewMargin)
|
||||||
|
+
|
||||||
|
+ # Step 4: Init both masters from that ldif
|
||||||
|
+ m1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file)
|
||||||
|
+ m2.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file)
|
||||||
|
+ m1.start()
|
||||||
|
+ m2.start()
|
||||||
|
+
|
||||||
|
+ # Step 5: Perform on line init from master1 to consumer1
|
||||||
|
+ # and from master2 to consumer2
|
||||||
|
+ m1_c1.begin_reinit()
|
||||||
|
+ m2_c2.begin_reinit()
|
||||||
|
+ (done, error) = m1_c1.wait_reinit()
|
||||||
|
+ assert done is True
|
||||||
|
+ assert error is False
|
||||||
|
+ (done, error) = m2_c2.wait_reinit()
|
||||||
|
+ assert done is True
|
||||||
|
+ assert error is False
|
||||||
|
+
|
||||||
|
+ # Step 6: Perform update on both masters
|
||||||
|
+ repl.test_replication(m1, c1)
|
||||||
|
+ repl.test_replication(m2, c2)
|
||||||
|
+
|
||||||
|
+ # Step 7: Check that c1 has no time skew
|
||||||
|
+ # Stop server to insure that dse.ldif is uptodate
|
||||||
|
+ c1.stop()
|
||||||
|
+ c1_nsState = DSEldif(c1).readNsState(DEFAULT_SUFFIX)[0]
|
||||||
|
+ c1_timeSkew = int(c1_nsState['time_skew'])
|
||||||
|
+ log.debug(f"c1 time skew: {c1_timeSkew}")
|
||||||
|
+ if (c1_timeSkew >= timeSkew):
|
||||||
|
+ log.error(f"c1 csngen state has unexpectedly been synchronized with m2: time skew {c1_timeSkew}")
|
||||||
|
+ assert False
|
||||||
|
+ c1.start()
|
||||||
|
+
|
||||||
|
+ # Step 8: Check that c2 has time skew
|
||||||
|
+ # Stop server to insure that dse.ldif is uptodate
|
||||||
|
+ c2.stop()
|
||||||
|
+ c2_nsState = DSEldif(c2).readNsState(DEFAULT_SUFFIX)[0]
|
||||||
|
+ c2_timeSkew = int(c2_nsState['time_skew'])
|
||||||
|
+ log.debug(f"c2 time skew: {c2_timeSkew}")
|
||||||
|
+ if (c2_timeSkew < timeSkew):
|
||||||
|
+ log.error(f"c2 csngen state has not been synchronized with m2: time skew {c2_timeSkew}")
|
||||||
|
+ assert False
|
||||||
|
+ c2.start()
|
||||||
|
+
|
||||||
|
+ # Step 9: Perform on line init from master1 to master2
|
||||||
|
+ m1_c1.pause()
|
||||||
|
+ m1_m2.resume()
|
||||||
|
+ m1_m2.begin_reinit()
|
||||||
|
+ (done, error) = m1_m2.wait_reinit()
|
||||||
|
+ assert done is True
|
||||||
|
+ assert error is False
|
||||||
|
+
|
||||||
|
+ # Step 10: Perform update on master2
|
||||||
|
+ repl.test_replication(m2, c1)
|
||||||
|
+
|
||||||
|
+ # Step 11: Check that c1 has time skew
|
||||||
|
+ # Stop server to insure that dse.ldif is uptodate
|
||||||
|
+ c1.stop()
|
||||||
|
+ c1_nsState = DSEldif(c1).readNsState(DEFAULT_SUFFIX)[0]
|
||||||
|
+ c1_timeSkew = int(c1_nsState['time_skew'])
|
||||||
|
+ log.debug(f"c1 time skew: {c1_timeSkew}")
|
||||||
|
+ if (c1_timeSkew < timeSkew):
|
||||||
|
+ log.error(f"c1 csngen state has not been synchronized with m2: time skew {c1_timeSkew}")
|
||||||
|
+ assert False
|
||||||
|
+
|
||||||
|
+
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Run isolated
|
||||||
|
# -s for DEBUG mode
|
||||||
|
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
|
||||||
|
index b35f724c2..f1c596a3f 100644
|
||||||
|
--- a/ldap/servers/plugins/replication/repl5.h
|
||||||
|
+++ b/ldap/servers/plugins/replication/repl5.h
|
||||||
|
@@ -708,6 +708,7 @@ void replica_dump(Replica *r);
|
||||||
|
void replica_set_enabled(Replica *r, PRBool enable);
|
||||||
|
Replica *replica_get_replica_from_dn(const Slapi_DN *dn);
|
||||||
|
Replica *replica_get_replica_from_root(const char *repl_root);
|
||||||
|
+int replica_check_generation(Replica *r, const RUV *remote_ruv);
|
||||||
|
int replica_update_ruv(Replica *replica, const CSN *csn, const char *replica_purl);
|
||||||
|
Replica *replica_get_replica_for_op(Slapi_PBlock *pb);
|
||||||
|
/* the functions below manipulate replica hash */
|
||||||
|
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
|
||||||
|
index 29b1fb073..af5e5897c 100644
|
||||||
|
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
|
||||||
|
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
|
||||||
|
@@ -2161,26 +2161,12 @@ examine_update_vector(Private_Repl_Protocol *prp, RUV *remote_ruv)
|
||||||
|
} else if (NULL == remote_ruv) {
|
||||||
|
return_value = EXAMINE_RUV_PRISTINE_REPLICA;
|
||||||
|
} else {
|
||||||
|
- char *local_gen = NULL;
|
||||||
|
- char *remote_gen = ruv_get_replica_generation(remote_ruv);
|
||||||
|
- Object *local_ruv_obj;
|
||||||
|
- RUV *local_ruv;
|
||||||
|
-
|
||||||
|
PR_ASSERT(NULL != prp->replica);
|
||||||
|
- local_ruv_obj = replica_get_ruv(prp->replica);
|
||||||
|
- if (NULL != local_ruv_obj) {
|
||||||
|
- local_ruv = (RUV *)object_get_data(local_ruv_obj);
|
||||||
|
- PR_ASSERT(local_ruv);
|
||||||
|
- local_gen = ruv_get_replica_generation(local_ruv);
|
||||||
|
- object_release(local_ruv_obj);
|
||||||
|
- }
|
||||||
|
- if (NULL == remote_gen || NULL == local_gen || strcmp(remote_gen, local_gen) != 0) {
|
||||||
|
- return_value = EXAMINE_RUV_GENERATION_MISMATCH;
|
||||||
|
- } else {
|
||||||
|
+ if (replica_check_generation(prp->replica, remote_ruv)) {
|
||||||
|
return_value = EXAMINE_RUV_OK;
|
||||||
|
+ } else {
|
||||||
|
+ return_value = EXAMINE_RUV_GENERATION_MISMATCH;
|
||||||
|
}
|
||||||
|
- slapi_ch_free((void **)&remote_gen);
|
||||||
|
- slapi_ch_free((void **)&local_gen);
|
||||||
|
}
|
||||||
|
return return_value;
|
||||||
|
}
|
||||||
|
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
|
||||||
|
index f0ea0f8ef..7e56d6557 100644
|
||||||
|
--- a/ldap/servers/plugins/replication/repl5_replica.c
|
||||||
|
+++ b/ldap/servers/plugins/replication/repl5_replica.c
|
||||||
|
@@ -812,6 +812,36 @@ replica_set_ruv(Replica *r, RUV *ruv)
|
||||||
|
replica_unlock(r->repl_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Check if replica generation is the same than the remote ruv one
|
||||||
|
+ */
|
||||||
|
+int
|
||||||
|
+replica_check_generation(Replica *r, const RUV *remote_ruv)
|
||||||
|
+{
|
||||||
|
+ int return_value;
|
||||||
|
+ char *local_gen = NULL;
|
||||||
|
+ char *remote_gen = ruv_get_replica_generation(remote_ruv);
|
||||||
|
+ Object *local_ruv_obj;
|
||||||
|
+ RUV *local_ruv;
|
||||||
|
+
|
||||||
|
+ PR_ASSERT(NULL != r);
|
||||||
|
+ local_ruv_obj = replica_get_ruv(r);
|
||||||
|
+ if (NULL != local_ruv_obj) {
|
||||||
|
+ local_ruv = (RUV *)object_get_data(local_ruv_obj);
|
||||||
|
+ PR_ASSERT(local_ruv);
|
||||||
|
+ local_gen = ruv_get_replica_generation(local_ruv);
|
||||||
|
+ object_release(local_ruv_obj);
|
||||||
|
+ }
|
||||||
|
+ if (NULL == remote_gen || NULL == local_gen || strcmp(remote_gen, local_gen) != 0) {
|
||||||
|
+ return_value = PR_FALSE;
|
||||||
|
+ } else {
|
||||||
|
+ return_value = PR_TRUE;
|
||||||
|
+ }
|
||||||
|
+ slapi_ch_free_string(&remote_gen);
|
||||||
|
+ slapi_ch_free_string(&local_gen);
|
||||||
|
+ return return_value;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Update one particular CSN in an RUV. This is meant to be called
|
||||||
|
* whenever (a) the server has processed a client operation and
|
||||||
|
@@ -1298,6 +1328,11 @@ replica_update_csngen_state_ext(Replica *r, const RUV *ruv, const CSN *extracsn)
|
||||||
|
|
||||||
|
PR_ASSERT(r && ruv);
|
||||||
|
|
||||||
|
+ if (!replica_check_generation(r, ruv)) /* ruv has wrong generation - we are done */
|
||||||
|
+ {
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
rc = ruv_get_max_csn(ruv, &csn);
|
||||||
|
if (rc != RUV_SUCCESS) {
|
||||||
|
return -1;
|
||||||
|
@@ -3713,8 +3748,8 @@ replica_update_ruv_consumer(Replica *r, RUV *supplier_ruv)
|
||||||
|
replica_lock(r->repl_lock);
|
||||||
|
|
||||||
|
local_ruv = (RUV *)object_get_data(r->repl_ruv);
|
||||||
|
-
|
||||||
|
- if (is_cleaned_rid(supplier_id) || local_ruv == NULL) {
|
||||||
|
+ if (is_cleaned_rid(supplier_id) || local_ruv == NULL ||
|
||||||
|
+ !replica_check_generation(r, supplier_ruv)) {
|
||||||
|
replica_unlock(r->repl_lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py
|
||||||
|
index 10baba4d7..6850c9a8a 100644
|
||||||
|
--- a/src/lib389/lib389/dseldif.py
|
||||||
|
+++ b/src/lib389/lib389/dseldif.py
|
||||||
|
@@ -317,6 +317,43 @@ class DSEldif(DSLint):
|
||||||
|
|
||||||
|
return states
|
||||||
|
|
||||||
|
+ def _increaseTimeSkew(self, suffix, timeSkew):
|
||||||
|
+ # Increase csngen state local_offset by timeSkew
|
||||||
|
+ # Warning: instance must be stopped before calling this function
|
||||||
|
+ assert (timeSkew >= 0)
|
||||||
|
+ nsState = self.readNsState(suffix)[0]
|
||||||
|
+ self._instance.log.debug(f'_increaseTimeSkew nsState is {nsState}')
|
||||||
|
+ oldNsState = self.get(nsState['dn'], 'nsState', True)
|
||||||
|
+ self._instance.log.debug(f'oldNsState is {oldNsState}')
|
||||||
|
+
|
||||||
|
+ # Lets reencode the new nsState
|
||||||
|
+ from lib389.utils import print_nice_time
|
||||||
|
+ if pack('<h', 1) == pack('=h',1):
|
||||||
|
+ end = '<'
|
||||||
|
+ elif pack('>h', 1) == pack('=h',1):
|
||||||
|
+ end = '>'
|
||||||
|
+ else:
|
||||||
|
+ raise ValueError("Unknown endian, unable to proceed")
|
||||||
|
+
|
||||||
|
+ thelen = len(oldNsState)
|
||||||
|
+ if thelen <= 20:
|
||||||
|
+ pad = 2 # padding for short H values
|
||||||
|
+ timefmt = 'I' # timevals are unsigned 32-bit int
|
||||||
|
+ else:
|
||||||
|
+ pad = 6 # padding for short H values
|
||||||
|
+ timefmt = 'Q' # timevals are unsigned 64-bit int
|
||||||
|
+ fmtstr = "%sH%dx3%sH%dx" % (end, pad, timefmt, pad)
|
||||||
|
+ newNsState = base64.b64encode(pack(fmtstr, int(nsState['rid']),
|
||||||
|
+ int(nsState['gen_time']), int(nsState['local_offset'])+timeSkew,
|
||||||
|
+ int(nsState['remote_offset']), int(nsState['seq_num'])))
|
||||||
|
+ newNsState = newNsState.decode('utf-8')
|
||||||
|
+ self._instance.log.debug(f'newNsState is {newNsState}')
|
||||||
|
+ # Lets replace the value.
|
||||||
|
+ (entry_dn_i, attr_data) = self._find_attr(nsState['dn'], 'nsState')
|
||||||
|
+ attr_i = next(iter(attr_data))
|
||||||
|
+ self._contents[entry_dn_i + attr_i] = f"nsState:: {newNsState}"
|
||||||
|
+ self._update()
|
||||||
|
+
|
||||||
|
|
||||||
|
class FSChecks(DSLint):
|
||||||
|
"""This is for the healthcheck feature, check commonly used system config files the
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
179
SOURCES/0004-Ticket-50933-Update-2307compat.ldif.patch
Normal file
179
SOURCES/0004-Ticket-50933-Update-2307compat.ldif.patch
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
From 826a1bb4ea88915ac492828d1cc4a901623f7866 Mon Sep 17 00:00:00 2001
|
||||||
|
From: William Brown <william@blackhats.net.au>
|
||||||
|
Date: Thu, 14 May 2020 14:31:47 +1000
|
||||||
|
Subject: [PATCH 1/2] Ticket 50933 - Update 2307compat.ldif
|
||||||
|
|
||||||
|
Bug Description: This resolves a potential conflict between 60nis.ldif
|
||||||
|
in freeipa and others with 2307compat, by removing the conflicting
|
||||||
|
definitions from 2307bis that were included.
|
||||||
|
|
||||||
|
Fix Description: By not including these in 2307compat, this means that
|
||||||
|
sites that rely on the values provided by 2307bis may ALSO need
|
||||||
|
60nis.ldif to be present. However, these nis values seem like they are
|
||||||
|
likely very rare in reality, and this also will avoid potential
|
||||||
|
issues with freeipa. It also is the least disruptive as we don't need
|
||||||
|
to change an already defined file, and we don't have values where the name
|
||||||
|
to oid relationship changes.
|
||||||
|
|
||||||
|
Fixes: #50933
|
||||||
|
https://pagure.io/389-ds-base/issue/50933
|
||||||
|
|
||||||
|
Author: William Brown <william@blackhats.net.au>
|
||||||
|
|
||||||
|
Review by: tbordaz (Thanks!)
|
||||||
|
---
|
||||||
|
ldap/schema/10rfc2307compat.ldif | 66 --------------------------------
|
||||||
|
ldap/schema/60autofs.ldif | 39 ++++++++++++-------
|
||||||
|
2 files changed, 26 insertions(+), 79 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ldap/schema/10rfc2307compat.ldif b/ldap/schema/10rfc2307compat.ldif
|
||||||
|
index 8810231ac..78c588d08 100644
|
||||||
|
--- a/ldap/schema/10rfc2307compat.ldif
|
||||||
|
+++ b/ldap/schema/10rfc2307compat.ldif
|
||||||
|
@@ -176,50 +176,6 @@ attributeTypes: (
|
||||||
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||||
|
SINGLE-VALUE
|
||||||
|
)
|
||||||
|
-attributeTypes: (
|
||||||
|
- 1.3.6.1.1.1.1.28 NAME 'nisPublicKey'
|
||||||
|
- DESC 'NIS public key'
|
||||||
|
- EQUALITY octetStringMatch
|
||||||
|
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
|
||||||
|
- SINGLE-VALUE
|
||||||
|
- )
|
||||||
|
-attributeTypes: (
|
||||||
|
- 1.3.6.1.1.1.1.29 NAME 'nisSecretKey'
|
||||||
|
- DESC 'NIS secret key'
|
||||||
|
- EQUALITY octetStringMatch
|
||||||
|
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
|
||||||
|
- SINGLE-VALUE
|
||||||
|
- )
|
||||||
|
-attributeTypes: (
|
||||||
|
- 1.3.6.1.1.1.1.30 NAME 'nisDomain'
|
||||||
|
- DESC 'NIS domain'
|
||||||
|
- EQUALITY caseIgnoreIA5Match
|
||||||
|
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||||
|
- )
|
||||||
|
-attributeTypes: (
|
||||||
|
- 1.3.6.1.1.1.1.31 NAME 'automountMapName'
|
||||||
|
- DESC 'automount Map Name'
|
||||||
|
- EQUALITY caseExactIA5Match
|
||||||
|
- SUBSTR caseExactIA5SubstringsMatch
|
||||||
|
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||||
|
- SINGLE-VALUE
|
||||||
|
- )
|
||||||
|
-attributeTypes: (
|
||||||
|
- 1.3.6.1.1.1.1.32 NAME 'automountKey'
|
||||||
|
- DESC 'Automount Key value'
|
||||||
|
- EQUALITY caseExactIA5Match
|
||||||
|
- SUBSTR caseExactIA5SubstringsMatch
|
||||||
|
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||||
|
- SINGLE-VALUE
|
||||||
|
- )
|
||||||
|
-attributeTypes: (
|
||||||
|
- 1.3.6.1.1.1.1.33 NAME 'automountInformation'
|
||||||
|
- DESC 'Automount information'
|
||||||
|
- EQUALITY caseExactIA5Match
|
||||||
|
- SUBSTR caseExactIA5SubstringsMatch
|
||||||
|
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||||
|
- SINGLE-VALUE
|
||||||
|
- )
|
||||||
|
# end of attribute types - beginning of objectclasses
|
||||||
|
objectClasses: (
|
||||||
|
1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY
|
||||||
|
@@ -324,28 +280,6 @@ objectClasses: (
|
||||||
|
seeAlso $ serialNumber'
|
||||||
|
MAY ( bootFile $ bootParameter $ cn $ description $ l $ o $ ou $ owner $ seeAlso $ serialNumber )
|
||||||
|
)
|
||||||
|
-objectClasses: (
|
||||||
|
- 1.3.6.1.1.1.2.14 NAME 'nisKeyObject' SUP top AUXILIARY
|
||||||
|
- DESC 'An object with a public and secret key'
|
||||||
|
- MUST ( cn $ nisPublicKey $ nisSecretKey )
|
||||||
|
- MAY ( uidNumber $ description )
|
||||||
|
- )
|
||||||
|
-objectClasses: (
|
||||||
|
- 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top AUXILIARY
|
||||||
|
- DESC 'Associates a NIS domain with a naming context'
|
||||||
|
- MUST nisDomain
|
||||||
|
- )
|
||||||
|
-objectClasses: (
|
||||||
|
- 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top STRUCTURAL
|
||||||
|
- MUST ( automountMapName )
|
||||||
|
- MAY description
|
||||||
|
- )
|
||||||
|
-objectClasses: (
|
||||||
|
- 1.3.6.1.1.1.2.17 NAME 'automount' SUP top STRUCTURAL
|
||||||
|
- DESC 'Automount information'
|
||||||
|
- MUST ( automountKey $ automountInformation )
|
||||||
|
- MAY description
|
||||||
|
- )
|
||||||
|
## namedObject is needed for groups without members
|
||||||
|
objectClasses: (
|
||||||
|
1.3.6.1.4.1.5322.13.1.1 NAME 'namedObject' SUP top STRUCTURAL
|
||||||
|
diff --git a/ldap/schema/60autofs.ldif b/ldap/schema/60autofs.ldif
|
||||||
|
index 084e9ec30..de3922aa2 100644
|
||||||
|
--- a/ldap/schema/60autofs.ldif
|
||||||
|
+++ b/ldap/schema/60autofs.ldif
|
||||||
|
@@ -6,7 +6,23 @@ dn: cn=schema
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
attributeTypes: (
|
||||||
|
- 1.3.6.1.1.1.1.33
|
||||||
|
+ 1.3.6.1.1.1.1.31 NAME 'automountMapName'
|
||||||
|
+ DESC 'automount Map Name'
|
||||||
|
+ EQUALITY caseExactIA5Match
|
||||||
|
+ SUBSTR caseExactIA5SubstringsMatch
|
||||||
|
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||||
|
+ SINGLE-VALUE
|
||||||
|
+ )
|
||||||
|
+attributeTypes: (
|
||||||
|
+ 1.3.6.1.1.1.1.32 NAME 'automountKey'
|
||||||
|
+ DESC 'Automount Key value'
|
||||||
|
+ EQUALITY caseExactIA5Match
|
||||||
|
+ SUBSTR caseExactIA5SubstringsMatch
|
||||||
|
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
||||||
|
+ SINGLE-VALUE
|
||||||
|
+ )
|
||||||
|
+attributeTypes: (
|
||||||
|
+ 1.3.6.1.1.1.1.33
|
||||||
|
NAME 'automountInformation'
|
||||||
|
DESC 'Information used by the autofs automounter'
|
||||||
|
EQUALITY caseExactIA5Match
|
||||||
|
@@ -18,25 +34,22 @@ attributeTypes: (
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
objectClasses: (
|
||||||
|
- 1.3.6.1.1.1.2.17
|
||||||
|
- NAME 'automount'
|
||||||
|
- DESC 'An entry in an automounter map'
|
||||||
|
+ 1.3.6.1.1.1.2.16
|
||||||
|
+ NAME 'automountMap'
|
||||||
|
+ DESC 'An group of related automount objects'
|
||||||
|
SUP top
|
||||||
|
STRUCTURAL
|
||||||
|
- MUST ( cn $ automountInformation )
|
||||||
|
- MAY ( description )
|
||||||
|
+ MAY ( ou $ automountMapName $ description )
|
||||||
|
X-ORIGIN 'draft-howard-rfc2307bis'
|
||||||
|
)
|
||||||
|
-#
|
||||||
|
-################################################################################
|
||||||
|
-#
|
||||||
|
objectClasses: (
|
||||||
|
- 1.3.6.1.1.1.2.16
|
||||||
|
- NAME 'automountMap'
|
||||||
|
- DESC 'An group of related automount objects'
|
||||||
|
+ 1.3.6.1.1.1.2.17
|
||||||
|
+ NAME 'automount'
|
||||||
|
+ DESC 'An entry in an automounter map'
|
||||||
|
SUP top
|
||||||
|
STRUCTURAL
|
||||||
|
- MUST ( ou )
|
||||||
|
+ MUST ( automountInformation )
|
||||||
|
+ MAY ( cn $ description $ automountKey )
|
||||||
|
X-ORIGIN 'draft-howard-rfc2307bis'
|
||||||
|
)
|
||||||
|
#
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
From 3d9ced9e340678cc02b1a36c2139492c95ef15a6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mark Reynolds <mreynolds@redhat.com>
|
||||||
|
Date: Wed, 12 Aug 2020 12:46:42 -0400
|
||||||
|
Subject: [PATCH 2/2] Issue 50933 - Fix OID change between 10rfc2307 and
|
||||||
|
10rfc2307compat
|
||||||
|
|
||||||
|
Bug Description: 10rfc2307compat changed the OID for nisMap objectclass to
|
||||||
|
match the standard OID, but this breaks replication with
|
||||||
|
older versions of DS.
|
||||||
|
|
||||||
|
Fix Description: Continue to use the old(invalid?) oid for nisMap so that
|
||||||
|
replication does not break in a mixed version environment.
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/389-ds-base/issue/50933
|
||||||
|
|
||||||
|
Reviewed by: firstyear & tbordaz(Thanks!!)
|
||||||
|
---
|
||||||
|
ldap/schema/10rfc2307compat.ldif | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/ldap/schema/10rfc2307compat.ldif b/ldap/schema/10rfc2307compat.ldif
|
||||||
|
index 78c588d08..8ba72e1e3 100644
|
||||||
|
--- a/ldap/schema/10rfc2307compat.ldif
|
||||||
|
+++ b/ldap/schema/10rfc2307compat.ldif
|
||||||
|
@@ -253,7 +253,7 @@ objectClasses: (
|
||||||
|
MAY ( nisNetgroupTriple $ memberNisNetgroup $ description )
|
||||||
|
)
|
||||||
|
objectClasses: (
|
||||||
|
- 1.3.6.1.1.1.2.9 NAME 'nisMap' SUP top STRUCTURAL
|
||||||
|
+ 1.3.6.1.1.1.2.13 NAME 'nisMap' SUP top STRUCTURAL
|
||||||
|
DESC 'A generic abstraction of a NIS map'
|
||||||
|
MUST nisMapName
|
||||||
|
MAY description
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
147
SOURCES/0006-Ticket-51131-improve-mutex-alloc-in-conntable.patch
Normal file
147
SOURCES/0006-Ticket-51131-improve-mutex-alloc-in-conntable.patch
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
From 1085823bf5586d55103cfba249fdf212e9afcb7c Mon Sep 17 00:00:00 2001
|
||||||
|
From: William Brown <william@blackhats.net.au>
|
||||||
|
Date: Thu, 4 Jun 2020 11:51:53 +1000
|
||||||
|
Subject: [PATCH] Ticket 51131 - improve mutex alloc in conntable
|
||||||
|
|
||||||
|
Bug Description: We previously did delayed allocation
|
||||||
|
of mutexs, which @tbordaz noted can lead to high usage
|
||||||
|
of the pthread mutex init routines. This was done under
|
||||||
|
the conntable lock, as well as cleaning the connection
|
||||||
|
|
||||||
|
Fix Description: rather than delayed allocation, we
|
||||||
|
initialise everything at start up instead, which means
|
||||||
|
that while startup may have a delay, at run time we have
|
||||||
|
a smaller and lighter connection allocation routine,
|
||||||
|
that is able to release the CT lock sooner.
|
||||||
|
|
||||||
|
https://pagure.io/389-ds-base/issue/51131
|
||||||
|
|
||||||
|
Author: William Brown <william@blackhats.net.au>
|
||||||
|
|
||||||
|
Review by: ???
|
||||||
|
---
|
||||||
|
ldap/servers/slapd/conntable.c | 86 +++++++++++++++++++---------------
|
||||||
|
1 file changed, 47 insertions(+), 39 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
|
||||||
|
index b23dc3435..feb9c0d75 100644
|
||||||
|
--- a/ldap/servers/slapd/conntable.c
|
||||||
|
+++ b/ldap/servers/slapd/conntable.c
|
||||||
|
@@ -138,10 +138,21 @@ connection_table_new(int table_size)
|
||||||
|
ct->conn_next_offset = 1;
|
||||||
|
ct->conn_free_offset = 1;
|
||||||
|
|
||||||
|
+ pthread_mutexattr_t monitor_attr = {0};
|
||||||
|
+ pthread_mutexattr_init(&monitor_attr);
|
||||||
|
+ pthread_mutexattr_settype(&monitor_attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
+
|
||||||
|
/* We rely on the fact that we called calloc, which zeros the block, so we don't
|
||||||
|
* init any structure element unless a zero value is troublesome later
|
||||||
|
*/
|
||||||
|
for (i = 0; i < table_size; i++) {
|
||||||
|
+ /*
|
||||||
|
+ * Technically this is a no-op due to calloc, but we should always be
|
||||||
|
+ * careful with things like this ....
|
||||||
|
+ */
|
||||||
|
+ ct->c[i].c_state = CONN_STATE_FREE;
|
||||||
|
+ /* Start the conn setup. */
|
||||||
|
+
|
||||||
|
LBER_SOCKET invalid_socket;
|
||||||
|
/* DBDB---move this out of here once everything works */
|
||||||
|
ct->c[i].c_sb = ber_sockbuf_alloc();
|
||||||
|
@@ -161,11 +172,20 @@ connection_table_new(int table_size)
|
||||||
|
ct->c[i].c_prev = NULL;
|
||||||
|
ct->c[i].c_ci = i;
|
||||||
|
ct->c[i].c_fdi = SLAPD_INVALID_SOCKET_INDEX;
|
||||||
|
- /*
|
||||||
|
- * Technically this is a no-op due to calloc, but we should always be
|
||||||
|
- * careful with things like this ....
|
||||||
|
- */
|
||||||
|
- ct->c[i].c_state = CONN_STATE_FREE;
|
||||||
|
+
|
||||||
|
+ if (pthread_mutex_init(&(ct->c[i].c_mutex), &monitor_attr) != 0) {
|
||||||
|
+ slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "pthread_mutex_init failed\n");
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ct->c[i].c_pdumutex = PR_NewLock();
|
||||||
|
+ if (ct->c[i].c_pdumutex == NULL) {
|
||||||
|
+ slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "PR_NewLock failed\n");
|
||||||
|
+ exit(1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Ready to rock, mark as such. */
|
||||||
|
+ ct->c[i].c_state = CONN_STATE_INIT;
|
||||||
|
/* Prepare the connection into the freelist. */
|
||||||
|
ct->c_freelist[i] = &(ct->c[i]);
|
||||||
|
}
|
||||||
|
@@ -241,44 +261,32 @@ connection_table_get_connection(Connection_Table *ct, int sd)
|
||||||
|
/* Never use slot 0 */
|
||||||
|
ct->conn_next_offset += 1;
|
||||||
|
}
|
||||||
|
- /* Now prep the slot for usage. */
|
||||||
|
- PR_ASSERT(c->c_next == NULL);
|
||||||
|
- PR_ASSERT(c->c_prev == NULL);
|
||||||
|
- PR_ASSERT(c->c_extension == NULL);
|
||||||
|
-
|
||||||
|
- if (c->c_state == CONN_STATE_FREE) {
|
||||||
|
-
|
||||||
|
- c->c_state = CONN_STATE_INIT;
|
||||||
|
-
|
||||||
|
- pthread_mutexattr_t monitor_attr = {0};
|
||||||
|
- pthread_mutexattr_init(&monitor_attr);
|
||||||
|
- pthread_mutexattr_settype(&monitor_attr, PTHREAD_MUTEX_RECURSIVE);
|
||||||
|
- if (pthread_mutex_init(&(c->c_mutex), &monitor_attr) != 0) {
|
||||||
|
- slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "pthread_mutex_init failed\n");
|
||||||
|
- exit(1);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- c->c_pdumutex = PR_NewLock();
|
||||||
|
- if (c->c_pdumutex == NULL) {
|
||||||
|
- c->c_pdumutex = NULL;
|
||||||
|
- slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "PR_NewLock failed\n");
|
||||||
|
- exit(1);
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- /* Let's make sure there's no cruft left on there from the last time this connection was used. */
|
||||||
|
- /* Note: no need to lock c->c_mutex because this function is only
|
||||||
|
- * called by one thread (the slapd_daemon thread), and if we got this
|
||||||
|
- * far then `c' is not being used by any operation threads, etc.
|
||||||
|
- */
|
||||||
|
- connection_cleanup(c);
|
||||||
|
- c->c_ct = ct; /* pointer to connection table that owns this connection */
|
||||||
|
+ PR_Unlock(ct->table_mutex);
|
||||||
|
} else {
|
||||||
|
- /* couldn't find a Connection */
|
||||||
|
+ /* couldn't find a Connection, table must be full */
|
||||||
|
slapi_log_err(SLAPI_LOG_CONNS, "connection_table_get_connection", "Max open connections reached\n");
|
||||||
|
+ PR_Unlock(ct->table_mutex);
|
||||||
|
+ return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* We could move this to before the c alloc as there is no point to remain here. */
|
||||||
|
- PR_Unlock(ct->table_mutex);
|
||||||
|
+ /* Now prep the slot for usage. */
|
||||||
|
+ PR_ASSERT(c != NULL);
|
||||||
|
+ PR_ASSERT(c->c_next == NULL);
|
||||||
|
+ PR_ASSERT(c->c_prev == NULL);
|
||||||
|
+ PR_ASSERT(c->c_extension == NULL);
|
||||||
|
+ PR_ASSERT(c->c_state == CONN_STATE_INIT);
|
||||||
|
+ /* Let's make sure there's no cruft left on there from the last time this connection was used. */
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Note: no need to lock c->c_mutex because this function is only
|
||||||
|
+ * called by one thread (the slapd_daemon thread), and if we got this
|
||||||
|
+ * far then `c' is not being used by any operation threads, etc. The
|
||||||
|
+ * memory ordering will be provided by the work queue sending c to a
|
||||||
|
+ * thread.
|
||||||
|
+ */
|
||||||
|
+ connection_cleanup(c);
|
||||||
|
+ /* pointer to connection table that owns this connection */
|
||||||
|
+ c->c_ct = ct;
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
From a9f53e9958861e6a7a827bd852d72d51a6512396 Mon Sep 17 00:00:00 2001
|
||||||
|
From: tbordaz <tbordaz@redhat.com>
|
||||||
|
Date: Wed, 25 Nov 2020 18:07:34 +0100
|
||||||
|
Subject: [PATCH] Issue 4297 - 2nd fix for on ADD replication URP issue
|
||||||
|
internal searches with filter containing unescaped chars (#4439)
|
||||||
|
|
||||||
|
Bug description:
|
||||||
|
Previous fix is buggy because slapi_filter_escape_filter_value returns
|
||||||
|
a escaped filter component not an escaped assertion value.
|
||||||
|
|
||||||
|
Fix description:
|
||||||
|
use the escaped filter component
|
||||||
|
|
||||||
|
relates: https://github.com/389ds/389-ds-base/issues/4297
|
||||||
|
|
||||||
|
Reviewed by: William Brown
|
||||||
|
|
||||||
|
Platforms tested: F31
|
||||||
|
---
|
||||||
|
ldap/servers/plugins/replication/urp.c | 16 ++++++++--------
|
||||||
|
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c
|
||||||
|
index f41dbc72d..ed340c9d8 100644
|
||||||
|
--- a/ldap/servers/plugins/replication/urp.c
|
||||||
|
+++ b/ldap/servers/plugins/replication/urp.c
|
||||||
|
@@ -1411,12 +1411,12 @@ urp_add_check_tombstone (Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry,
|
||||||
|
Slapi_Entry **entries = NULL;
|
||||||
|
Slapi_PBlock *newpb;
|
||||||
|
char *basedn = slapi_entry_get_ndn(entry);
|
||||||
|
- char *escaped_basedn;
|
||||||
|
+ char *escaped_filter;
|
||||||
|
const Slapi_DN *suffix = slapi_get_suffix_by_dn(slapi_entry_get_sdn (entry));
|
||||||
|
- escaped_basedn = slapi_filter_escape_filter_value("nscpentrydn", basedn);
|
||||||
|
+ escaped_filter = slapi_filter_escape_filter_value("nscpentrydn", basedn);
|
||||||
|
|
||||||
|
- char *filter = slapi_filter_sprintf("(&(objectclass=nstombstone)(nscpentrydn=%s))", escaped_basedn);
|
||||||
|
- slapi_ch_free((void **)&escaped_basedn);
|
||||||
|
+ char *filter = slapi_filter_sprintf("(&(objectclass=nstombstone)%s)", escaped_filter);
|
||||||
|
+ slapi_ch_free((void **)&escaped_filter);
|
||||||
|
newpb = slapi_pblock_new();
|
||||||
|
slapi_search_internal_set_pb(newpb,
|
||||||
|
slapi_sdn_get_dn(suffix), /* Base DN */
|
||||||
|
@@ -1605,15 +1605,15 @@ urp_find_tombstone_for_glue (Slapi_PBlock *pb, char *sessionid, const Slapi_Entr
|
||||||
|
Slapi_Entry **entries = NULL;
|
||||||
|
Slapi_PBlock *newpb;
|
||||||
|
const char *basedn = slapi_sdn_get_dn(parentdn);
|
||||||
|
- char *escaped_basedn;
|
||||||
|
- escaped_basedn = slapi_filter_escape_filter_value("nscpentrydn", (char *)basedn);
|
||||||
|
+ char *escaped_filter;
|
||||||
|
+ escaped_filter = slapi_filter_escape_filter_value("nscpentrydn", (char *)basedn);
|
||||||
|
|
||||||
|
char *conflict_csnstr = (char*)slapi_entry_attr_get_ref((Slapi_Entry *)entry, "conflictcsn");
|
||||||
|
CSN *conflict_csn = csn_new_by_string(conflict_csnstr);
|
||||||
|
CSN *tombstone_csn = NULL;
|
||||||
|
|
||||||
|
- char *filter = slapi_filter_sprintf("(&(objectclass=nstombstone)(nscpentrydn=%s))", escaped_basedn);
|
||||||
|
- slapi_ch_free((void **)&escaped_basedn);
|
||||||
|
+ char *filter = slapi_filter_sprintf("(&(objectclass=nstombstone)%s)", escaped_filter);
|
||||||
|
+ slapi_ch_free((void **)&escaped_filter);
|
||||||
|
newpb = slapi_pblock_new();
|
||||||
|
char *parent_dn = slapi_dn_parent (basedn);
|
||||||
|
slapi_search_internal_set_pb(newpb,
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
|
@ -45,7 +45,7 @@ ExcludeArch: i686
|
||||||
Summary: 389 Directory Server (base)
|
Summary: 389 Directory Server (base)
|
||||||
Name: 389-ds-base
|
Name: 389-ds-base
|
||||||
Version: 1.4.3.16
|
Version: 1.4.3.16
|
||||||
Release: %{?relprefix}1%{?prerel}%{?dist}
|
Release: %{?relprefix}3%{?prerel}%{?dist}
|
||||||
License: GPLv3+
|
License: GPLv3+
|
||||||
URL: https://www.port389.org
|
URL: https://www.port389.org
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
@ -174,6 +174,13 @@ Source2: %{name}-devel.README
|
||||||
%if %{bundle_jemalloc}
|
%if %{bundle_jemalloc}
|
||||||
Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download/%{jemalloc_ver}/%{jemalloc_name}-%{jemalloc_ver}.tar.bz2
|
Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download/%{jemalloc_ver}/%{jemalloc_name}-%{jemalloc_ver}.tar.bz2
|
||||||
%endif
|
%endif
|
||||||
|
Patch01: 0001-Issue-4383-Do-not-normalize-escaped-spaces-in-a-DN.patch
|
||||||
|
Patch02: 0002-ticket-2058-Add-keep-alive-entry-after-on-line-initi.patch
|
||||||
|
Patch03: 0003-do-not-add-referrals-for-masters-with-different-data.patch
|
||||||
|
Patch04: 0004-Ticket-50933-Update-2307compat.ldif.patch
|
||||||
|
Patch05: 0005-Issue-50933-Fix-OID-change-between-10rfc2307-and-10r.patch
|
||||||
|
Patch06: 0006-Ticket-51131-improve-mutex-alloc-in-conntable.patch
|
||||||
|
Patch07: 0007-Issue-4297-2nd-fix-for-on-ADD-replication-URP-issue-.patch
|
||||||
|
|
||||||
%description
|
%description
|
||||||
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
||||||
|
@ -791,6 +798,18 @@ exit 0
|
||||||
%doc README.md
|
%doc README.md
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Nov 25 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.16-3
|
||||||
|
- Bump version to 1.4.3.16-3
|
||||||
|
- Resolves: Bug 1859219 - rfc2307 and rfc2307bis compat schema
|
||||||
|
- Resolves: Bug 1843604 - reduce the cost of allocation/free when open/close a connection
|
||||||
|
- Resolves: Bug 1898850 - Entries conflict not resolved by replication
|
||||||
|
|
||||||
|
* Thu Nov 19 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.16-2
|
||||||
|
- Bump version to 1.4.3.16-2
|
||||||
|
- Resolves: Bug 1859227 - create keep alive entry after on line init
|
||||||
|
- Resolves: Bug 1888863 - group rdn with leading space char and add fails error 21 invalid syntax and delete fails error 32
|
||||||
|
- Resolves: Bug 1859228 - do not add referrals for masters with different data generation
|
||||||
|
|
||||||
* Mon Oct 26 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.16-1
|
* Mon Oct 26 2020 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.16-1
|
||||||
- Bump version to 1.4.3.16-1
|
- Bump version to 1.4.3.16-1
|
||||||
- Resolves: Bug 1887415 - Sync repl - if a serie of updates target the same entry then the cookie get wrong changenumber
|
- Resolves: Bug 1887415 - Sync repl - if a serie of updates target the same entry then the cookie get wrong changenumber
|
||||||
|
|
Loading…
Add table
Reference in a new issue