diff --git a/SOURCES/0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch b/SOURCES/0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch
new file mode 100644
index 0000000..64608a7
--- /dev/null
+++ b/SOURCES/0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch
@@ -0,0 +1,55 @@
+From ffeb863e47ab35cbb2e5666847561451d0394ed9 Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Mon, 11 Jan 2021 17:33:06 +0100
+Subject: [PATCH] Issue 4521 - DS crash in deref plugin if dereferenced entry
+ exists but is not returned by internal search (#4525)
+
+Bug description:
+	For each returned entry, deref plugin dereferences some attribute values that refer to entries.
+	To do this it does an internal search (scope base) with each attribute values.
+	Deref plugin assumes that if internal search succeeds, a single entry is returned.
+	It exists cases (not identified) where internal search succeeds but returns no entry.
+	In such case (search succeeds but no entry returned) the server crash.
+	Note: wonder if DB deadlock could lead to such situation.
+
+Fix description:
+	Make a hardening fix that logs warning in such case
+
+relates: https://github.com/389ds/389-ds-base/issues/4521
+
+Reviewed by: Mark Reynolds (thanks)
+
+Platforms tested: F31
+---
+ ldap/servers/plugins/deref/deref.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/ldap/servers/plugins/deref/deref.c b/ldap/servers/plugins/deref/deref.c
+index ec1884ba3..fc1c10f71 100644
+--- a/ldap/servers/plugins/deref/deref.c
++++ b/ldap/servers/plugins/deref/deref.c
+@@ -592,6 +592,21 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
+                 slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
+                               "deref_do_deref_attr - More than one entry matching DN [%s]\n",
+                               derefdn);
++            } else if (entries[0] == NULL) {
++                int32_t op_id;
++                uint64_t conn_id;
++
++                slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id);
++                slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id);
++                /* Weird case not clearly understood:
++                 * the entry 'derefdn' exists (else we would have NOT_SUCH_ENTRY in 'rc')
++                 * but it is not returned by the internal search. Note that internal search
++                 * returns tombstone or subentry.
++                 * Just to prevent a crash, catch this error condition and log a warning
++                 */
++                slapi_log_err(SLAPI_LOG_WARNING, DEREF_PLUGIN_SUBSYSTEM,
++                              "deref_do_deref_attr - conn=%" PRIu64 " op=%d - failed to retrieve the entry [%s], although the entry exists\n",
++                              conn_id, op_id, derefdn);
+             } else {
+                 int ii;
+                 int needattrvals = 1; /* need attrvals sequence? */
+-- 
+2.26.2
+
diff --git a/SOURCES/0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch b/SOURCES/0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch
new file mode 100644
index 0000000..2462641
--- /dev/null
+++ b/SOURCES/0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch
@@ -0,0 +1,206 @@
+From f22fe3da910889ab2530d84b647b5b36b6e7e95f Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Mon, 14 Dec 2020 10:02:24 +0100
+Subject: [PATCH] Issue 4492 - Changelog cache can upload updates from a wrong
+ starting point (CSN) (#4493)
+
+Bug description:
+          When a replication session starts, a starting point is computed
+          according to supplier/consumer RUVs.
+	  from the starting point the updates are bulk loaded from the CL.
+          When a bulk set have been fully evaluated the server needs to bulk load another set.
+	  It iterates until there is no more updates to send.
+          The bug is that during bulk load, it recomputes the CL cursor position
+          and this computation can be wrong. For example if a new update on
+          a rarely updated replica (or not known replica) the new position will
+          be set before the inital starting point
+
+Fix description:
+          Fixing the invalid computation is a bit risky (complex code resulting from
+          years of corner cases handling) and a fix could fail to address others flavor
+          with the same symptom
+          The fix is only (sorry for that) safety checking fix that would end a replication session
+          if the computed cursor position goes before the initial starting point.
+	  In case of large jump behind (24h) the starting point, a warning is logged.
+
+relates: https://github.com/389ds/389-ds-base/issues/4492
+
+Reviewed by: Mark Reynolds, William Brown
+
+Platforms tested: F31
+---
+ ldap/servers/plugins/replication/cl5_api.c    |  6 +-
+ .../servers/plugins/replication/cl5_clcache.c | 60 ++++++++++++++++++-
+ .../servers/plugins/replication/cl5_clcache.h |  4 +-
+ 3 files changed, 63 insertions(+), 7 deletions(-)
+
+diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
+index 65801bc01..1d6e20b07 100644
+--- a/ldap/servers/plugins/replication/cl5_api.c
++++ b/ldap/servers/plugins/replication/cl5_api.c
+@@ -143,6 +143,7 @@ struct cl5replayiterator
+     ReplicaId consumerRID;  /* consumer's RID */
+     const RUV *consumerRuv; /* consumer's update vector                    */
+     Object *supplierRuvObj; /* supplier's update vector object          */
++    char starting_csn[CSN_STRSIZE];
+ };
+ 
+ typedef struct cl5iterator
+@@ -1542,7 +1543,7 @@ cl5GetNextOperationToReplay(CL5ReplayIterator *iterator, CL5Entry *entry)
+         return CL5_BAD_DATA;
+     }
+ 
+-    rc = clcache_get_next_change(iterator->clcache, (void **)&key, &keylen, (void **)&data, &datalen, &csn);
++    rc = clcache_get_next_change(iterator->clcache, (void **)&key, &keylen, (void **)&data, &datalen, &csn, iterator->starting_csn);
+ 
+     if (rc == DB_NOTFOUND) {
+         /*
+@@ -5256,7 +5257,7 @@ _cl5PositionCursorForReplay(ReplicaId consumerRID, const RUV *consumerRuv, Objec
+     if (rc != 0)
+         goto done;
+ 
+-    rc = clcache_load_buffer(clcache, &startCSN, continue_on_missing);
++    rc = clcache_load_buffer(clcache, &startCSN, continue_on_missing, NULL /* retrieving startCSN, no limit enforced on this call */);
+ 
+     if (rc == 0) {
+         haveChanges = PR_TRUE;
+@@ -5320,6 +5321,7 @@ _cl5PositionCursorForReplay(ReplicaId consumerRID, const RUV *consumerRuv, Objec
+         (*iterator)->consumerRID = consumerRID;
+         (*iterator)->consumerRuv = consumerRuv;
+         (*iterator)->supplierRuvObj = supplierRuvObj;
++        csn_as_string(startCSN, PR_FALSE, (*iterator)->starting_csn);
+     } else if (rc == CL5_SUCCESS) {
+         /* we have no changes to send */
+         rc = CL5_NOTFOUND;
+diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
+index a8477a83a..43b7c77d8 100644
+--- a/ldap/servers/plugins/replication/cl5_clcache.c
++++ b/ldap/servers/plugins/replication/cl5_clcache.c
+@@ -15,6 +15,8 @@
+ #include "db.h"    /* Berkeley DB */
+ #include "cl5.h"   /* changelog5Config */
+ #include "cl5_clcache.h"
++#include "slap.h"
++#include "proto-slap.h"
+ 
+ /* newer bdb uses DB_BUFFER_SMALL instead of ENOMEM as the
+    error return if the given buffer in which to load a
+@@ -323,14 +325,21 @@ clcache_return_buffer(CLC_Buffer **buf)
+  * anchorcsn - passed in for the first load of a replication session;
+  * flag         - DB_SET to load in the key CSN record.
+  *                DB_NEXT to load in the records greater than key CSN.
++ * initial_starting_csn
++ *              This is the starting_csn computed at the beginning of
++ *              the replication session. It never change during a session
++ *              (aka iterator creation).
++ *              This is used for safety checking that the next CSN use
++ *              for bulk load is not before the initial csn
+  * return    - DB error code instead of cl5 one because of the
+  *               historic reason.
+  */
+ int
+-clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss)
++clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, char *initial_starting_csn)
+ {
+     int rc = 0;
+     int flag = DB_NEXT;
++    CSN limit_csn = {0};
+ 
+     if (anchorCSN)
+         *anchorCSN = NULL;
+@@ -343,6 +352,30 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss)
+         rc = clcache_adjust_anchorcsn(buf, &flag);
+     }
+ 
++    /* safety checking, we do not want to (re)start replication before
++     * the inital computed starting point
++     */
++    if (initial_starting_csn) {
++        csn_init_by_string(&limit_csn, initial_starting_csn);
++        if (csn_compare(&limit_csn, buf->buf_current_csn) > 0) {
++            char curr[CSN_STRSIZE];
++            int loglevel = SLAPI_LOG_REPL;
++
++            if (csn_time_difference(&limit_csn, buf->buf_current_csn) > (24 * 60 * 60)) {
++                /* This is a big jump (more than a day) behind the
++                 * initial starting csn. Log a warning before ending
++                 * the session
++                 */
++                loglevel = SLAPI_LOG_WARNING;
++            }
++            csn_as_string(buf->buf_current_csn, 0, curr);
++            slapi_log_err(loglevel, buf->buf_agmt_name,
++                      "clcache_load_buffer - bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn);
++            /* it just end the session with UPDATE_NO_MORE_UPDATES */
++            rc = CLC_STATE_DONE;
++        }
++    }
++
+     if (rc == 0) {
+ 
+         buf->buf_state = CLC_STATE_READY;
+@@ -365,6 +398,27 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss)
+             }
+             /* the use of alternative start csns can be limited, record its usage */
+             (*continue_on_miss)--;
++
++            if (initial_starting_csn) {
++                if (csn_compare(&limit_csn, buf->buf_current_csn) > 0) {
++                    char curr[CSN_STRSIZE];
++                    int loglevel = SLAPI_LOG_REPL;
++
++                    if (csn_time_difference(&limit_csn, buf->buf_current_csn) > (24 * 60 * 60)) {
++                        /* This is a big jump (more than a day) behind the
++                         * initial starting csn. Log a warning before ending
++                         * the session
++                         */
++                        loglevel = SLAPI_LOG_WARNING;
++                    }
++                    csn_as_string(buf->buf_current_csn, 0, curr);
++                    slapi_log_err(loglevel, buf->buf_agmt_name,
++                            "clcache_load_buffer - (DB_SET_RANGE) bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn);
++                    rc = DB_NOTFOUND;
++
++                    return rc;
++                }
++            }
+         }
+         /* Reset some flag variables */
+         if (rc == 0) {
+@@ -492,7 +546,7 @@ retry:
+  * *data: output - data of the next change, or NULL if no more change
+  */
+ int
+-clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn)
++clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn, char *initial_starting_csn)
+ {
+     int skip = 1;
+     int rc = 0;
+@@ -510,7 +564,7 @@ clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data
+          * We're done with the current buffer. Now load the next chunk.
+          */
+         if (NULL == *key && CLC_STATE_READY == buf->buf_state) {
+-            rc = clcache_load_buffer(buf, NULL, NULL);
++            rc = clcache_load_buffer(buf, NULL, NULL, initial_starting_csn);
+             if (0 == rc && buf->buf_record_ptr) {
+                 DB_MULTIPLE_KEY_NEXT(buf->buf_record_ptr, &buf->buf_data,
+                                      *key, *keylen, *data, *datalen);
+diff --git a/ldap/servers/plugins/replication/cl5_clcache.h b/ldap/servers/plugins/replication/cl5_clcache.h
+index 73eb41590..16d53d563 100644
+--- a/ldap/servers/plugins/replication/cl5_clcache.h
++++ b/ldap/servers/plugins/replication/cl5_clcache.h
+@@ -23,9 +23,9 @@ typedef struct clc_buffer CLC_Buffer;
+ int clcache_init(DB_ENV **dbenv);
+ void clcache_set_config(void);
+ int clcache_get_buffer(CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv);
+-int clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss);
++int clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, char *initial_starting_csn);
+ void clcache_return_buffer(CLC_Buffer **buf);
+-int clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn);
++int clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn, char *initial_starting_csn);
+ void clcache_destroy(void);
+ 
+ #endif
+-- 
+2.26.2
+
diff --git a/SOURCES/0018-Issue-5442-Search-results-are-different-between-RHDS.patch b/SOURCES/0018-Issue-5442-Search-results-are-different-between-RHDS.patch
new file mode 100644
index 0000000..c67df62
--- /dev/null
+++ b/SOURCES/0018-Issue-5442-Search-results-are-different-between-RHDS.patch
@@ -0,0 +1,639 @@
+From 21bfb590a53c078d3dfeb982497f049d4627c71d Mon Sep 17 00:00:00 2001
+From: Mark Reynolds <mreynolds@redhat.com>
+Date: Wed, 20 Jan 2021 16:42:15 -0500
+Subject: [PATCH] Issue 5442 - Search results are different between RHDS10 and
+ RHDS11
+
+Bug Description:  In 1.4.x we introduced a change that was overly strict about
+                  how a search on a non-existent subtree returned its error code.
+                  It was changed from returning an error 32 to an error 0 with
+                  zero entries returned.
+
+Fix Description:  When finding the entry and processing acl's make sure to
+                  gather the aci's that match the resource even if the resource
+                  does not exist.  This requires some extra checks when processing
+                  the target attribute.
+
+relates: https://github.com/389ds/389-ds-base/issues/4542
+
+Reviewed by: firstyear, elkris, and tbordaz (Thanks!)
+
+Apply Thierry's changes
+
+round 2
+
+Apply more suggestions from Thierry
+---
+ ldap/servers/plugins/acl/acl.c           | 296 ++++++++++-------------
+ ldap/servers/slapd/back-ldbm/findentry.c |   6 +-
+ src/lib389/lib389/_mapped_object.py      |   1 +
+ 3 files changed, 134 insertions(+), 169 deletions(-)
+
+diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
+index 6d105f4fa..ecd23aa88 100644
+--- a/ldap/servers/plugins/acl/acl.c
++++ b/ldap/servers/plugins/acl/acl.c
+@@ -2109,10 +2109,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+     aci_right = aci->aci_access;
+     res_right = aclpb->aclpb_access;
+     if (!(aci_right & res_right)) {
+-        /* If we are looking for read/search and the acl has read/search
+-        ** then go further because if targets match we may keep that
+-        ** acl in  the entry cache list.
+-        */
++        /*
++         * If we are looking for read/search and the acl has read/search
++         * then go further because if targets match we may keep that
++         * acl in the entry cache list.
++         */
+         if (!((res_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) &&
+               (aci_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)))) {
+             matches = ACL_FALSE;
+@@ -2120,30 +2121,29 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+         }
+     }
+ 
+-
+-    /* first Let's see if the entry is under the subtree where the
+-    ** ACL resides. We can't let somebody affect a target beyond the
+-    ** scope of where the ACL resides
+-    ** Example: ACL is located in "ou=engineering, o=ace industry, c=us
+-    ** but if the target is "o=ace industry, c=us", then we are in trouble.
+-    **
+-    ** If the aci is in the rootdse and the entry is not, then we do not
+-    ** match--ie. acis in the rootdse do NOT apply below...for the moment.
+-    **
+-    */
++    /*
++     * First Let's see if the entry is under the subtree where the
++     * ACL resides. We can't let somebody affect a target beyond the
++     * scope of where the ACL resides
++     * Example: ACL is located in "ou=engineering, o=ace industry, c=us
++     * but if the target is "o=ace industry, c=us", then we are in trouble.
++     *
++     * If the aci is in the rootdse and the entry is not, then we do not
++     * match--ie. acis in the rootdse do NOT apply below...for the moment.
++     */
+     res_ndn = slapi_sdn_get_ndn(aclpb->aclpb_curr_entry_sdn);
+     aci_ndn = slapi_sdn_get_ndn(aci->aci_sdn);
+-    if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) || (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn))) {
+-
+-        /* cant' poke around */
++    if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) ||
++        (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn)))
++    {
++        /* can't poke around */
+         matches = ACL_FALSE;
+         goto acl__resource_match_aci_EXIT;
+     }
+ 
+     /*
+-    ** We have a single ACI which we need to find if it applies to
+-    ** the resource or not.
+-    */
++     * We have a single ACI which we need to find if it applies to the resource or not.
++     */
+     if ((aci->aci_type & ACI_TARGET_DN) && (aclpb->aclpb_curr_entry_sdn)) {
+         char *avaType;
+         struct berval *avaValue;
+@@ -2171,25 +2171,23 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+         char *avaType;
+         struct berval *avaValue;
+         char logbuf[1024];
+-
+-        /* We are evaluating the moddn permission.
+-                 * The aci contains target_to and target_from
+-                 *
+-                 * target_to filter must be checked against the resource ndn that was stored in
+-                 * aclpb->aclpb_curr_entry_sdn
+-                 *
+-                 * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn
+-                 * (sdn was stored in the pblock)
+-                 */
++        /*
++         * We are evaluating the moddn permission.
++         * The aci contains target_to and target_from
++         *
++         * target_to filter must be checked against the resource ndn that was stored in
++         * aclpb->aclpb_curr_entry_sdn
++         *
++         * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn
++         * (sdn was stored in the pblock)
++         */
+         if (aci->target_to) {
+             f = aci->target_to;
+             dn_matched = ACL_TRUE;
+ 
+             /* Now check if the filter is a simple or substring filter */
+             if (aci->aci_type & ACI_TARGET_MODDN_TO_PATTERN) {
+-                /* This is a filter with substring
+-                     * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
+-                     */
++                /* This is a filter with substring e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com */
+                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to substring: %s\n",
+                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
+                 if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffix */)) != ACL_TRUE) {
+@@ -2202,9 +2200,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+                     }
+                 }
+             } else {
+-                /* This is a filter without substring
+-                     * e.g. ldap:///cn=accounts,dc=example,dc=com
+-                     */
++                /* This is a filter without substring  e.g. ldap:///cn=accounts,dc=example,dc=com */
+                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to: %s\n",
+                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
+                 slapi_filter_get_ava(f, &avaType, &avaValue);
+@@ -2228,8 +2224,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+             /* Now check if the filter is a simple or substring filter */
+             if (aci->aci_type & ACI_TARGET_MODDN_FROM_PATTERN) {
+                 /* This is a filter with substring
+-                         * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
+-                         */
++                 * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com
++                 */
+                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from substring: %s\n",
+                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
+                 if ((rv = acl_match_substring(f, (char *)slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), 0 /* match suffix */)) != ACL_TRUE) {
+@@ -2241,11 +2237,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+                         goto acl__resource_match_aci_EXIT;
+                     }
+                 }
+-
+             } else {
+-                /* This is a filter without substring
+-                         * e.g. ldap:///cn=accounts,dc=example,dc=com
+-                         */
++                /* This is a filter without substring  e.g. ldap:///cn=accounts,dc=example,dc=com */
+                 slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from: %s\n",
+                               slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
+                 if (!slapi_dn_issuffix(slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), avaValue->bv_val)) {
+@@ -2267,10 +2260,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+     }
+ 
+     if (aci->aci_type & ACI_TARGET_PATTERN) {
+-
+         f = aci->target;
+         dn_matched = ACL_TRUE;
+-
+         if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffux */)) != ACL_TRUE) {
+             dn_matched = ACL_FALSE;
+             if (rv == ACL_ERR) {
+@@ -2294,7 +2285,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+ 
+     /*
+      * Is it a (target="ldap://cn=*,($dn),o=sun.com") kind of thing.
+-    */
++     */
+     if (aci->aci_type & ACI_TARGET_MACRO_DN) {
+         /*
+          * See if the ($dn) component matches the string and
+@@ -2304,8 +2295,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+          * entry is the same one don't recalculate it--
+          * this flag only works for search right now, could
+          * also optimise for mods by making it work for mods.
+-        */
+-
++         */
+         if ((aclpb->aclpb_res_type & ACLPB_NEW_ENTRY) == 0) {
+             /*
+              * Here same entry so just look up the matched value,
+@@ -2354,8 +2344,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+                  * If there is already an entry for this aci in this
+                  * aclpb then remove it--it's an old value for a
+                  * different entry.
+-                */
+-
++                 */
+                 acl_ht_add_and_freeOld(aclpb->aclpb_macro_ht,
+                                        (PLHashNumber)aci->aci_index,
+                                        matched_val);
+@@ -2379,30 +2368,27 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+     }
+ 
+     /*
+-    ** Here, if there's a targetfilter field, see if it matches.
+-    **
+-    ** The commented out code below was an erroneous attempt to skip
+-    ** this test.  It is wrong because: 1. you need to store
+-    ** whether the last test matched or not (you cannot just assume it did)
+-    ** and 2. It may not be the same aci, so the previous matched
+-    ** value is a function of the aci.
+-    ** May be interesting to build such a cache...but no evidence for
+-    ** for that right now. See Bug 383424.
+-    **
+-    **
+-    **   && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
+-    **    (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
+-    */
++     * Here, if there's a targetfilter field, see if it matches.
++     *
++     * The commented out code below was an erroneous attempt to skip
++     * this test.  It is wrong because: 1. you need to store
++     * whether the last test matched or not (you cannot just assume it did)
++     * and 2. It may not be the same aci, so the previous matched
++     * value is a function of the aci.
++     * May be interesting to build such a cache...but no evidence for
++     * for that right now. See Bug 383424.
++     *
++     *
++     *   && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
++     *    (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
++     */
+     if (aci->aci_type & ACI_TARGET_FILTER) {
+         int filter_matched = ACL_TRUE;
+-
+         /*
+          * Check for macros.
+          * For targetfilter we need to fake the lasinfo structure--it's
+          * created "naturally" for subjects but not targets.
+-        */
+-
+-
++         */
+         if (aci->aci_type & ACI_TARGET_FILTER_MACRO_DN) {
+ 
+             lasInfo *lasinfo = NULL;
+@@ -2417,11 +2403,9 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+                                                     ACL_EVAL_TARGET_FILTER);
+             slapi_ch_free((void **)&lasinfo);
+         } else {
+-
+-
+             if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry,
+                                         aci->targetFilter,
+-                                        0 /*don't do acess chk*/) != 0) {
++                                        0 /*don't do access check*/) != 0) {
+                 filter_matched = ACL_FALSE;
+             }
+         }
+@@ -2448,7 +2432,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+      * Check to see if we need to evaluate any targetattrfilters.
+      * They look as follows:
+      * (targetattrfilters="add=sn:(sn=rob) && gn:(gn!=byrne),
+-     *                       del=sn:(sn=rob) && gn:(gn=byrne)")
++     *                     del=sn:(sn=rob) && gn:(gn=byrne)")
+      *
+      * For ADD/DELETE:
+      * If theres's a targetattrfilter then each add/del filter
+@@ -2456,29 +2440,25 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+      * by each value of the attribute in the entry.
+      *
+      * For MODIFY:
+-     *    If there's a targetattrfilter then the add/del filter
++     * If there's a targetattrfilter then the add/del filter
+      * must be satisfied by the attribute to be added/deleted.
+      * (MODIFY acl is evaluated one value at a time).
+      *
+      *
+-    */
+-
++     */
+     if (((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
+          (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) ||
+         ((aclpb->aclpb_access & SLAPI_ACL_DELETE) &&
+-         (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) {
+-
++         (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)))
++    {
+         Targetattrfilter **attrFilterArray = NULL;
+-
+         Targetattrfilter *attrFilter = NULL;
+-
+         Slapi_Attr *attr_ptr = NULL;
+         Slapi_Value *sval;
+         const struct berval *attrVal;
+         int k;
+         int done;
+ 
+-
+         if ((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
+             (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) {
+ 
+@@ -2495,28 +2475,20 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+ 
+         while (attrFilterArray && attrFilterArray[num_attrs] && attr_matched) {
+             attrFilter = attrFilterArray[num_attrs];
+-
+             /*
+-                 * If this filter applies to an attribute in the entry,
+-                 * apply it to the entry.
+-                 * Otherwise just ignore it.
+-                 *
+-                */
+-
+-            if (slapi_entry_attr_find(aclpb->aclpb_curr_entry,
+-                                      attrFilter->attr_str,
+-                                      &attr_ptr) == 0) {
+-
++             * If this filter applies to an attribute in the entry,
++             * apply it to the entry.
++             * Otherwise just ignore it.
++             *
++             */
++            if (slapi_entry_attr_find(aclpb->aclpb_curr_entry, attrFilter->attr_str, &attr_ptr) == 0) {
+                 /*
+-                     * This is an applicable filter.
+-                     *  The filter is to be appplied to the entry being added
+-                     * or deleted.
+-                     * The filter needs to be satisfied by _each_ occurence
+-                     * of the attribute in the entry--otherwise you
+-                     * could satisfy the filter and then put loads of other
+-                     * values in on the back of it.
+-                     */
+-
++                 * This is an applicable filter.
++                 * The filter is to be applied to the entry being added or deleted.
++                 * The filter needs to be satisfied by _each_ occurrence of the
++                 * attribute in the entry--otherwise you could satisfy the filter
++                 * and then put loads of other values in on the back of it.
++                 */
+                 sval = NULL;
+                 attrVal = NULL;
+                 k = slapi_attr_first_value(attr_ptr, &sval);
+@@ -2526,12 +2498,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+ 
+                     if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry,
+                                                     attrFilter->attr_str,
+-                                                    (struct berval *)attrVal) == LDAP_SUCCESS) {
+-
++                                                    (struct berval *)attrVal) == LDAP_SUCCESS)
++                    {
+                         attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry,
+                                                         attrFilter->filter,
+-                                                        1 /* Do filter sense evaluation below */
+-                                                        );
++                                                        1 /* Do filter sense evaluation below */);
+                         done = !attr_matched;
+                         slapi_entry_free(aclpb->aclpb_filter_test_entry);
+                     }
+@@ -2540,19 +2511,19 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+                 } /* while */
+ 
+                 /*
+-                     * Here, we applied an applicable filter to the entry.
+-                     * So if attr_matched is ACL_TRUE then every value
+-                     * of the attribute in the entry satisfied the filter.
+-                     * Otherwise, attr_matched is ACL_FALSE and not every
+-                     * value satisfied the filter, so we will teminate the
+-                     * scan of the filter list.
+-                     */
++                 * Here, we applied an applicable filter to the entry.
++                 * So if attr_matched is ACL_TRUE then every value
++                 * of the attribute in the entry satisfied the filter.
++                 * Otherwise, attr_matched is ACL_FALSE and not every
++                 * value satisfied the filter, so we will terminate the
++                 * scan of the filter list.
++                 */
+             }
+ 
+             num_attrs++;
+         } /* while */
+ 
+-/*
++        /*
+          * Here, we've applied all the applicable filters to the entry.
+          * Each one must have been satisfied by all the values of the attribute.
+          * The result of this is stored in attr_matched.
+@@ -2583,7 +2554,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+     } else if (((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) &&
+                 (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) ||
+                ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) &&
+-                (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) {
++                (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)))
++    {
+         /*
+          * Here, it's a modify add/del and we have attr filters.
+          * So, we need to scan the add/del filter list to find the filter
+@@ -2633,11 +2605,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+         */
+ 
+         if (found) {
+-
+             if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry,
+                                             aclpb->aclpb_curr_attrEval->attrEval_name,
+-                                            aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS) {
+-
++                                            aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS)
++            {
+                 attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry,
+                                                 attrFilter->filter,
+                                                 1 /* Do filter sense evaluation below */
+@@ -2655,20 +2626,21 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+              * Here this attribute appeared and was matched in a
+              * targetattrfilters list, so record this fact so we do
+              * not have to scan the targetattr list for the attribute.
+-            */
++             */
+ 
+             attr_matched_in_targetattrfilters = 1;
+         }
+     } /* targetvaluefilters */
+ 
+ 
+-    /* There are 3 cases  by which acis are selected.
+-    ** 1) By scanning the whole list and picking based on the resource.
+-    ** 2) By picking a subset of the list which will be used for the whole
+-    **    acl evaluation.
+-    ** 3) A finer granularity, i.e, a selected list of acls which will be
+-    ** used for only that entry's evaluation.
+-    */
++    /*
++     * There are 3 cases  by which acis are selected.
++     * 1) By scanning the whole list and picking based on the resource.
++     * 2) By picking a subset of the list which will be used for the whole
++     *    acl evaluation.
++     * 3) A finer granularity, i.e, a selected list of acls which will be
++     * used for only that entry's evaluation.
++     */
+     if (!(skip_attrEval) && (aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_ENTRY_LIST) &&
+         (res_right & SLAPI_ACL_SEARCH) &&
+         ((aci->aci_access & SLAPI_ACL_READ) || (aci->aci_access & SLAPI_ACL_SEARCH))) {
+@@ -2684,7 +2656,6 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+         }
+     }
+ 
+-
+     /* If we are suppose to skip attr eval, then let's skip it */
+     if ((aclpb->aclpb_access & SLAPI_ACL_SEARCH) && (!skip_attrEval) &&
+         (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY)) {
+@@ -2701,9 +2672,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+         goto acl__resource_match_aci_EXIT;
+     }
+ 
+-    /* We need to check again because we don't want to select this handle
+-    ** if the right doesn't match for now.
+-    */
++    /*
++     * We need to check again because we don't want to select this handle
++     * if the right doesn't match for now.
++     */
+     if (!(aci_right & res_right)) {
+         matches = ACL_FALSE;
+         goto acl__resource_match_aci_EXIT;
+@@ -2722,20 +2694,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+      * rbyrneXXX if we had a proper permission for modrdn eg SLAPI_ACL_MODRDN
+      * then we would not need this crappy way of telling it was a MODRDN
+      * request ie. SLAPI_ACL_WRITE && !(c_attrEval).
+-    */
+-
++     */
+     c_attrEval = aclpb->aclpb_curr_attrEval;
+ 
+     /*
+      * If we've already matched on targattrfilter then do not
+      * bother to look at the attrlist.
+-    */
+-
++     */
+     if (!attr_matched_in_targetattrfilters) {
+-
+         /* match target attr */
+-        if ((c_attrEval) &&
+-            (aci->aci_type & ACI_TARGET_ATTR)) {
++        if ((c_attrEval) && (aci->aci_type & ACI_TARGET_ATTR)) {
+             /* there is a target ATTR */
+             Targetattr **attrArray = aci->targetAttr;
+             Targetattr *attr = NULL;
+@@ -2777,46 +2745,43 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+                 matches = (attr_matched ? ACL_TRUE : ACL_FALSE);
+             }
+ 
+-
+             aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
+             /* figure out how it matched, i.e star matched */
+-            if (matches && star_matched && num_attrs == 1 &&
+-                !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE))
++            if (matches && star_matched && num_attrs == 1 && !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE)) {
+                 aclpb->aclpb_state |= ACLPB_ATTR_STAR_MATCHED;
+-            else {
++            } else {
+                 /* we are here means that there is a specific
+-                ** attr in the rule for this resource.
+-                ** We need to avoid this case
+-                ** Rule 1: (targetattr = "uid")
+-                ** Rule 2: (targetattr = "*")
+-                ** we cannot use STAR optimization
+-                */
++                 * attr in the rule for this resource.
++                 * We need to avoid this case
++                 * Rule 1: (targetattr = "uid")
++                 * Rule 2: (targetattr = "*")
++                 * we cannot use STAR optimization
++                 */
+                 aclpb->aclpb_state |= ACLPB_FOUND_ATTR_RULE;
+                 aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
+             }
+-        } else if ((c_attrEval) ||
+-                   (aci->aci_type & ACI_TARGET_ATTR)) {
++        } else if ((c_attrEval) || (aci->aci_type & ACI_TARGET_ATTR)) {
+             if ((aci_right & ACL_RIGHTS_TARGETATTR_NOT_NEEDED) &&
+                 (aclpb->aclpb_access & ACL_RIGHTS_TARGETATTR_NOT_NEEDED)) {
+                 /*
+-            ** Targetattr rule doesn't  make any sense
+-            ** in this case. So select this rule
+-            ** default: matches = ACL_TRUE;
+-            */
++                 * Targetattr rule doesn't make any sense
++                 * in this case. So select this rule
++                 * default: matches = ACL_TRUE;
++                 */
+                 ;
+-            } else if (aci_right & SLAPI_ACL_WRITE &&
++            } else if ((aci_right & SLAPI_ACL_WRITE) &&
+                        (aci->aci_type & ACI_TARGET_ATTR) &&
+                        !(c_attrEval) &&
+                        (aci->aci_type & ACI_HAS_ALLOW_RULE)) {
+                 /* We need to handle modrdn operation.  Modrdn doesn't
+-            ** change any attrs but changes the RDN and so (attr=NULL).
+-            ** Here we found an acl which has a targetattr but
+-            ** the resource doesn't need one. In that case, we should
+-            ** consider this acl.
+-            ** the opposite is true if it is a deny rule, only a deny without
+-            ** any targetattr should deny modrdn
+-            ** default: matches = ACL_TRUE;
+-            */
++                 * change any attrs but changes the RDN and so (attr=NULL).
++                 * Here we found an acl which has a targetattr but
++                 * the resource doesn't need one. In that case, we should
++                 * consider this acl.
++                 * the opposite is true if it is a deny rule, only a deny without
++                 * any targetattr should deny modrdn
++                 * default: matches = ACL_TRUE;
++                 */
+                 ;
+             } else {
+                 matches = ACL_FALSE;
+@@ -2825,16 +2790,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a
+     } /* !attr_matched_in_targetattrfilters */
+ 
+     /*
+-    ** Here we are testing if we find a entry test rule (which should
+-    ** be rare). In that case, just remember it. An entry test rule
+-    ** doesn't have "(targetattr)".
+-    */
++     * Here we are testing if we find a entry test rule (which should
++     * be rare). In that case, just remember it. An entry test rule
++     * doesn't have "(targetattr)".
++     */
+     if ((aclpb->aclpb_state & ACLPB_EVALUATING_FIRST_ATTR) &&
+         (!(aci->aci_type & ACI_TARGET_ATTR))) {
+         aclpb->aclpb_state |= ACLPB_FOUND_A_ENTRY_TEST_RULE;
+     }
+ 
+-/*
++    /*
+      * Generic exit point for this routine:
+      * matches is ACL_TRUE if the aci matches the target of the resource,
+      * ACL_FALSE othrewise.
+@@ -2857,6 +2822,7 @@ acl__resource_match_aci_EXIT:
+ 
+     return (matches);
+ }
++
+ /* Macro to determine if the cached result is valid or not. */
+ #define ACL_CACHED_RESULT_VALID(result)          \
+     (((result & ACLPB_CACHE_READ_RES_ALLOW) &&   \
+diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c
+index 6e53a0aea..bff751c88 100644
+--- a/ldap/servers/slapd/back-ldbm/findentry.c
++++ b/ldap/servers/slapd/back-ldbm/findentry.c
+@@ -93,7 +93,6 @@ find_entry_internal_dn(
+     size_t tries = 0;
+     int isroot = 0;
+     int op_type;
+-    char *errbuf = NULL;
+ 
+     /* get the managedsait ldap message control */
+     slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+@@ -207,8 +206,8 @@ find_entry_internal_dn(
+                     break;
+                 }
+                 if (acl_type > 0) {
+-                    err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type,
+-                                                 ACLPLUGIN_ACCESS_DEFAULT, &errbuf);
++                    char *dummy_attr = "1.1";
++                    err = slapi_access_allowed(pb, me->ep_entry, dummy_attr, NULL, acl_type);
+                 }
+                 if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) {
+                     /*
+@@ -237,7 +236,6 @@ find_entry_internal_dn(
+         CACHE_RETURN(&inst->inst_cache, &me);
+     }
+ 
+-    slapi_ch_free_string(&errbuf);
+     slapi_log_err(SLAPI_LOG_TRACE, "find_entry_internal_dn", "<= Not found (%s)\n",
+                   slapi_sdn_get_dn(sdn));
+     return (NULL);
+diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py
+index f73cb25f3..ada3f4976 100644
+--- a/src/lib389/lib389/_mapped_object.py
++++ b/src/lib389/lib389/_mapped_object.py
+@@ -838,3 +838,4 @@ class DSLdapObjects(DSLogging):
+         (rdn, properties) = self._validate(rdn, properties)
+         # Now actually commit the creation req
+         return co.create(rdn, properties, self._basedn)
++
+-- 
+2.26.2
+
diff --git a/SOURCES/0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch b/SOURCES/0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch
new file mode 100644
index 0000000..0ad2d5d
--- /dev/null
+++ b/SOURCES/0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch
@@ -0,0 +1,146 @@
+From 905d243347e13a342ce39491927f158b5337fd43 Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Tue, 23 Feb 2021 13:42:31 +0100
+Subject: [PATCH] Issue 4644 - Large updates can reset the CLcache to the
+ beginning of the changelog (#4647)
+
+Bug description:
+	The replication agreements are using bulk load to load updates.
+	For bulk load it uses a cursor with DB_MULTIPLE_KEY and DB_NEXT.
+	Before using the cursor, it must be initialized with DB_SET.
+
+	If during the cursor/DB_SET the CSN refers to an update that is larger than
+	the size of the provided buffer, then the cursor remains not initialized and
+	c_get returns DB_BUFFER_SMALL.
+
+	The consequence is that the next c_get(DB_MULTIPLE_KEY and DB_NEXT) will return the
+	first record in the changelog DB. This break CLcache.
+
+Fix description:
+	The fix is to harden cursor initialization so that if DB_SET fails
+	because of DB_BUFFER_SMALL. It reallocates buf_data and retries a DB_SET.
+	If DB_SET can not be initialized it logs a warning.
+
+	The patch also changes the behaviour of the fix #4492.
+	#4492 detected a massive (1day) jump prior the starting csn and ended the
+	replication session. If the jump was systematic, for example
+	if the CLcache got broken because of a too large updates, then
+	replication was systematically stopped.
+	This patch suppress the systematically stop, letting RA doing a big jump.
+	From #4492 only remains the warning.
+
+relates: https://github.com/389ds/389-ds-base/issues/4644
+
+Reviewed by: Pierre Rogier (Thanks !!!!)
+
+Platforms tested: F31
+---
+ .../servers/plugins/replication/cl5_clcache.c | 68 +++++++++++++++----
+ 1 file changed, 53 insertions(+), 15 deletions(-)
+
+diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
+index 43b7c77d8..0b1f48f0c 100644
+--- a/ldap/servers/plugins/replication/cl5_clcache.c
++++ b/ldap/servers/plugins/replication/cl5_clcache.c
+@@ -370,9 +370,7 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, cha
+             }
+             csn_as_string(buf->buf_current_csn, 0, curr);
+             slapi_log_err(loglevel, buf->buf_agmt_name,
+-                      "clcache_load_buffer - bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn);
+-            /* it just end the session with UPDATE_NO_MORE_UPDATES */
+-            rc = CLC_STATE_DONE;
++                      "clcache_load_buffer - bulk load cursor (%s) is lower than starting csn %s.\n", curr, initial_starting_csn);
+         }
+     }
+ 
+@@ -413,10 +411,7 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, cha
+                     }
+                     csn_as_string(buf->buf_current_csn, 0, curr);
+                     slapi_log_err(loglevel, buf->buf_agmt_name,
+-                            "clcache_load_buffer - (DB_SET_RANGE) bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn);
+-                    rc = DB_NOTFOUND;
+-
+-                    return rc;
++                            "clcache_load_buffer - (DB_SET_RANGE) bulk load cursor (%s) is lower than starting csn %s.\n", curr, initial_starting_csn);
+                 }
+             }
+         }
+@@ -444,6 +439,42 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, cha
+     return rc;
+ }
+ 
++/* Set a cursor to a specific key (buf->buf_key)
++ * In case buf_data is too small to receive the value, DB_SET fails
++ * (DB_BUFFER_SMALL). This let the cursor uninitialized that is
++ * problematic because further cursor DB_NEXT will reset the cursor
++ * to the beginning of the CL.
++ * If buf_data is too small, this function reallocates enough space
++ *
++ * It returns the return code of cursor->c_get
++ */
++static int
++clcache_cursor_set(DBC *cursor, CLC_Buffer *buf)
++{
++    int rc;
++    uint32_t ulen;
++    uint32_t dlen;
++    uint32_t size;
++
++    rc = cursor->c_get(cursor, &buf->buf_key, &buf->buf_data, DB_SET);
++    if (rc == DB_BUFFER_SMALL) {
++        uint32_t ulen;
++
++        /* Fortunately, buf->buf_data.size has been set by
++         * c_get() to the actual data size needed. So we can
++         * reallocate the data buffer and try to set again.
++         */
++        ulen = buf->buf_data.ulen;
++        buf->buf_data.ulen = (buf->buf_data.size / DEFAULT_CLC_BUFFER_PAGE_SIZE + 1) * DEFAULT_CLC_BUFFER_PAGE_SIZE;
++        buf->buf_data.data = slapi_ch_realloc(buf->buf_data.data, buf->buf_data.ulen);
++        slapi_log_err(SLAPI_LOG_REPL, buf->buf_agmt_name,
++                      "clcache_cursor_set - buf data len reallocated %d -> %d bytes (DB_BUFFER_SMALL)\n",
++                      ulen, buf->buf_data.ulen);
++        rc = cursor->c_get(cursor, &buf->buf_key, &buf->buf_data, DB_SET);
++    }
++    return rc;
++}
++
+ static int
+ clcache_load_buffer_bulk(CLC_Buffer *buf, int flag)
+ {
+@@ -478,17 +509,24 @@ retry:
+ 
+         if (use_flag == DB_NEXT) {
+             /* For bulk read, position the cursor before read the next block */
+-            rc = cursor->c_get(cursor,
+-                               &buf->buf_key,
+-                               &buf->buf_data,
+-                               DB_SET);
++            rc = clcache_cursor_set(cursor, buf);
+         }
+ 
+-        /*
+-         * Continue if the error is no-mem since we don't need to
+-         * load in the key record anyway with DB_SET.
+-         */
+         if (0 == rc || DB_BUFFER_SMALL == rc) {
++           /*
++            * It should not have failed  with DB_BUFFER_SMALL as we tried
++            * to adjust buf_data in clcache_cursor_set.
++            * But if it failed with DB_BUFFER_SMALL, there is a risk in clcache_cursor_get
++            * that the cursor will be reset to the beginning of the changelog.
++            * Returning an error at this point will stop replication that is
++            * a risk. So just accept the risk of a reset to the beginning of the CL
++            * and log an alarming message.
++            */
++           if (rc == DB_BUFFER_SMALL) {
++               slapi_log_err(SLAPI_LOG_WARNING, buf->buf_agmt_name,
++                             "clcache_load_buffer_bulk - Fail to position on csn=%s from the changelog (too large update ?). Risk of full CL evaluation.\n",
++                             (char *)buf->buf_key.data);
++           }
+             rc = clcache_cursor_get(cursor, buf, use_flag);
+         }
+     }
+-- 
+2.26.2
+
diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec
index 17de959..70fb029 100644
--- a/SPECS/389-ds-base.spec
+++ b/SPECS/389-ds-base.spec
@@ -39,7 +39,7 @@
 Summary:          389 Directory Server (%{variant})
 Name:             389-ds-base
 Version:          1.3.10.2
-Release:          %{?relprefix}9%{?prerel}%{?dist}
+Release:          %{?relprefix}10%{?prerel}%{?dist}
 License:          GPLv3+
 URL:              https://www.port389.org/
 Group:            System Environment/Daemons
@@ -161,6 +161,11 @@ Patch12:          0012-Issue-51166-Log-an-error-when-a-search-is-fully-unin.patc
 Patch13:          0013-Issue-4297-2nd-fix-for-on-ADD-replication-URP-issue-.patch
 Patch14:          0014-0002-Issue-4383-Do-not-normalize-escaped-spaces-in-a-DN.patch
 Patch15:          0015-Issue-4219-fix-crash-around-logging-internal-unindex.patch
+Patch16:          0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch
+Patch17:          0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch
+Patch18:          0018-Issue-5442-Search-results-are-different-between-RHDS.patch
+Patch19:          0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch
+
 
 %description
 389 Directory Server is an LDAPv3 compliant server.  The base package includes
@@ -514,8 +519,14 @@ fi
 %{_sysconfdir}/%{pkgname}/dirsrvtests
 
 %changelog
+* Thu Feb 25 2021 Mark Reynolds <mreynolds@redhat.com> - 1.3.10.2-10
+- Bump version to 1.3.10.2-10
+- Resolves: Bug 1909342 - DS crash in deref plugin while dereferencing an entry that exists but that is not returned by internal search
+- Resolves: Bug 1921856 - “write” permission of ACI changes ns-slapd’s behavior on search operation 
+- Resolves: Bug 1881968 - Replication Lag under high load
+
 * Thu Jan 7 2021 Mark Reynolds <mreynolds@redhat.com> - 1.3.10.2-9
-- Bump version to 1.3.10.2-8
+- Bump version to 1.3.10.2-9
 - Resolves: Bug 1905450 - Internal unindexed search crashes the server
 
 * Thu Dec 3 2020 Mark Reynolds <mreynolds@redhat.com> - 1.3.10.2-8