Blame SOURCES/0034-Issue-4526-sync_repl-when-completing-an-operation-in.patch

3280a9
From 5bca57b52069508a55b36fafe3729b7d1243743b Mon Sep 17 00:00:00 2001
3280a9
From: tbordaz <tbordaz@redhat.com>
3280a9
Date: Wed, 27 Jan 2021 11:58:38 +0100
3280a9
Subject: [PATCH 2/3] Issue 4526 - sync_repl: when completing an operation in
3280a9
 the pending list, it can select the wrong operation (#4553)
3280a9
3280a9
Bug description:
3280a9
	When an operation complete, it was retrieved in the pending list with
3280a9
	the address of the Operation structure. In case of POST OP nested operations
3280a9
	the same address can be reused. So when completing an operation there could be
3280a9
	a confusion which operation actually completed.
3280a9
	A second problem is that if an update its DB_DEADLOCK, the BETXN_PREOP can
3280a9
	be called several times. During retry, the operation is already in the pending
3280a9
	list.
3280a9
3280a9
Fix description:
3280a9
	The fix defines a new operation extension (sync_persist_extension_type).
3280a9
	This operation extension contains an index (idx_pl) of the op_pl in the
3280a9
	the pending list.
3280a9
3280a9
	And additional safety fix is to dump the pending list in case it becomes large (>10).
3280a9
	The pending list is dumped with SLAPI_LOG_PLUGIN.
3280a9
3280a9
	When there is a retry (operation extension exists) the call to sync_update_persist_betxn_pre_op
3280a9
	becomes a NOOP: the operation is not added again in the pending list.
3280a9
3280a9
relates: https://github.com/389ds/389-ds-base/issues/4526
3280a9
3280a9
Reviewed by: William Brown (Thanks !!)
3280a9
---
3280a9
 ldap/servers/plugins/sync/sync.h         |   9 ++
3280a9
 ldap/servers/plugins/sync/sync_init.c    |  64 +++++++-
3280a9
 ldap/servers/plugins/sync/sync_persist.c | 194 ++++++++++++++++-------
3280a9
 3 files changed, 208 insertions(+), 59 deletions(-)
3280a9
3280a9
diff --git a/ldap/servers/plugins/sync/sync.h b/ldap/servers/plugins/sync/sync.h
3280a9
index 7241fddbf..2fdf24476 100644
3280a9
--- a/ldap/servers/plugins/sync/sync.h
3280a9
+++ b/ldap/servers/plugins/sync/sync.h
3280a9
@@ -82,6 +82,12 @@ typedef enum _pl_flags {
3280a9
     OPERATION_PL_IGNORED = 5
3280a9
 } pl_flags_t;
3280a9
 
3280a9
+typedef struct op_ext_ident
3280a9
+{
3280a9
+    uint32_t idx_pl;   /* To uniquely identify an operation in PL, the operation extension
3280a9
+                        * contains the index of that operation in the pending list
3280a9
+                        */
3280a9
+} op_ext_ident_t;
3280a9
 /* Pending list operations.
3280a9
  * it contains a list ('next') of nested operations. The
3280a9
  * order the same order that the server applied the operation
3280a9
@@ -90,6 +96,7 @@ typedef enum _pl_flags {
3280a9
 typedef struct OPERATION_PL_CTX
3280a9
 {
3280a9
     Operation *op;      /* Pending operation, should not be freed as it belongs to the pblock */
3280a9
+    uint32_t idx_pl;    /* index of the operation in the pending list */
3280a9
     pl_flags_t flags;  /* operation is completed (set to TRUE in POST) */
3280a9
     Slapi_Entry *entry; /* entry to be store in the enqueued node. 1st arg sync_queue_change */
3280a9
     Slapi_Entry *eprev; /* pre-entry to be stored in the enqueued node. 2nd arg sync_queue_change */
3280a9
@@ -99,6 +106,8 @@ typedef struct OPERATION_PL_CTX
3280a9
 
3280a9
 OPERATION_PL_CTX_T * get_thread_primary_op(void);
3280a9
 void set_thread_primary_op(OPERATION_PL_CTX_T *op);
3280a9
+const op_ext_ident_t * sync_persist_get_operation_extension(Slapi_PBlock *pb);
3280a9
+void sync_persist_set_operation_extension(Slapi_PBlock *pb, op_ext_ident_t *op_ident);
3280a9
 
3280a9
 int sync_register_operation_extension(void);
3280a9
 int sync_unregister_operation_entension(void);
3280a9
diff --git a/ldap/servers/plugins/sync/sync_init.c b/ldap/servers/plugins/sync/sync_init.c
3280a9
index 74af14512..9e6a12000 100644
3280a9
--- a/ldap/servers/plugins/sync/sync_init.c
3280a9
+++ b/ldap/servers/plugins/sync/sync_init.c
3280a9
@@ -16,6 +16,7 @@ static int sync_preop_init(Slapi_PBlock *pb);
3280a9
 static int sync_postop_init(Slapi_PBlock *pb);
3280a9
 static int sync_be_postop_init(Slapi_PBlock *pb);
3280a9
 static int sync_betxn_preop_init(Slapi_PBlock *pb);
3280a9
+static int sync_persist_register_operation_extension(void);
3280a9
 
3280a9
 static PRUintn thread_primary_op;
3280a9
 
3280a9
@@ -43,7 +44,8 @@ sync_init(Slapi_PBlock *pb)
3280a9
         slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
3280a9
                          (void *)sync_close) != 0 ||
3280a9
         slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
3280a9
-                         (void *)&pdesc) != 0) {
3280a9
+                         (void *)&pdesc) != 0 ||
3280a9
+        sync_persist_register_operation_extension()) {
3280a9
         slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM,
3280a9
                       "sync_init - Failed to register plugin\n");
3280a9
         rc = 1;
3280a9
@@ -242,4 +244,64 @@ set_thread_primary_op(OPERATION_PL_CTX_T *op)
3280a9
         PR_SetThreadPrivate(thread_primary_op, (void *) head);
3280a9
     }
3280a9
     head->next = op;
3280a9
+}
3280a9
+
3280a9
+/* The following definitions are used for the operation pending list
3280a9
+ * (used by sync_repl). To retrieve a specific operation in the pending
3280a9
+ * list, the operation extension contains the index of the operation in
3280a9
+ * the pending list
3280a9
+ */
3280a9
+static int sync_persist_extension_type;   /* initialized in sync_persist_register_operation_extension */
3280a9
+static int sync_persist_extension_handle; /* initialized in sync_persist_register_operation_extension */
3280a9
+
3280a9
+const op_ext_ident_t *
3280a9
+sync_persist_get_operation_extension(Slapi_PBlock *pb)
3280a9
+{
3280a9
+    Slapi_Operation *op;
3280a9
+    op_ext_ident_t *ident;
3280a9
+
3280a9
+    slapi_pblock_get(pb, SLAPI_OPERATION, &op);
3280a9
+    ident = slapi_get_object_extension(sync_persist_extension_type, op,
3280a9
+                                       sync_persist_extension_handle);
3280a9
+    slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "sync_persist_get_operation_extension operation (op=0x%lx) -> %d\n",
3280a9
+                    (ulong) op, ident ? ident->idx_pl : -1);
3280a9
+    return (const op_ext_ident_t *) ident;
3280a9
+
3280a9
+}
3280a9
+
3280a9
+void
3280a9
+sync_persist_set_operation_extension(Slapi_PBlock *pb, op_ext_ident_t *op_ident)
3280a9
+{
3280a9
+    Slapi_Operation *op;
3280a9
+
3280a9
+    slapi_pblock_get(pb, SLAPI_OPERATION, &op);
3280a9
+    slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "sync_persist_set_operation_extension operation (op=0x%lx) -> %d\n",
3280a9
+                    (ulong) op, op_ident ? op_ident->idx_pl : -1);
3280a9
+    slapi_set_object_extension(sync_persist_extension_type, op,
3280a9
+                               sync_persist_extension_handle, (void *)op_ident);
3280a9
+}
3280a9
+/* operation extension constructor */
3280a9
+static void *
3280a9
+sync_persist_operation_extension_constructor(void *object __attribute__((unused)), void *parent __attribute__((unused)))
3280a9
+{
3280a9
+    /* we only set the extension value explicitly in sync_update_persist_betxn_pre_op */
3280a9
+    return NULL; /* we don't set anything in the ctor */
3280a9
+}
3280a9
+
3280a9
+/* consumer operation extension destructor */
3280a9
+static void
3280a9
+sync_persist_operation_extension_destructor(void *ext, void *object __attribute__((unused)), void *parent __attribute__((unused)))
3280a9
+{
3280a9
+    op_ext_ident_t *op_ident = (op_ext_ident_t *)ext;
3280a9
+    slapi_ch_free((void **)&op_ident);
3280a9
+}
3280a9
+static int
3280a9
+sync_persist_register_operation_extension(void)
3280a9
+{
3280a9
+    return slapi_register_object_extension(SYNC_PLUGIN_SUBSYSTEM,
3280a9
+                                           SLAPI_EXT_OPERATION,
3280a9
+                                           sync_persist_operation_extension_constructor,
3280a9
+                                           sync_persist_operation_extension_destructor,
3280a9
+                                           &sync_persist_extension_type,
3280a9
+                                           &sync_persist_extension_handle);
3280a9
 }
3280a9
\ No newline at end of file
3280a9
diff --git a/ldap/servers/plugins/sync/sync_persist.c b/ldap/servers/plugins/sync/sync_persist.c
3280a9
index d13f142b0..e93a8fa83 100644
3280a9
--- a/ldap/servers/plugins/sync/sync_persist.c
3280a9
+++ b/ldap/servers/plugins/sync/sync_persist.c
3280a9
@@ -47,6 +47,9 @@ static int sync_release_connection(Slapi_PBlock *pb, Slapi_Connection *conn, Sla
3280a9
  * per thread pending list of nested operation..
3280a9
  * being a betxn_preop the pending list has the same order
3280a9
  * that the server received the operation
3280a9
+ *
3280a9
+ * In case of DB_RETRY, this callback can be called several times
3280a9
+ * The detection of the DB_RETRY is done via the operation extension
3280a9
  */
3280a9
 int
3280a9
 sync_update_persist_betxn_pre_op(Slapi_PBlock *pb)
3280a9
@@ -54,64 +57,128 @@ sync_update_persist_betxn_pre_op(Slapi_PBlock *pb)
3280a9
     OPERATION_PL_CTX_T *prim_op;
3280a9
     OPERATION_PL_CTX_T *new_op;
3280a9
     Slapi_DN *sdn;
3280a9
+    uint32_t idx_pl = 0;
3280a9
+    op_ext_ident_t *op_ident;
3280a9
+    Operation *op;
3280a9
 
3280a9
     if (!SYNC_IS_INITIALIZED()) {
3280a9
         /* not initialized if sync plugin is not started */
3280a9
         return 0;
3280a9
     }
3280a9
 
3280a9
+    prim_op = get_thread_primary_op();
3280a9
+    op_ident = sync_persist_get_operation_extension(pb);
3280a9
+    slapi_pblock_get(pb, SLAPI_OPERATION, &op);
3280a9
+    slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn;;
3280a9
+
3280a9
+    /* Check if we are in a DB retry case */
3280a9
+    if (op_ident && prim_op) {
3280a9
+        OPERATION_PL_CTX_T *current_op;
3280a9
+
3280a9
+        /* This callback is called (with the same operation) because of a DB_RETRY */
3280a9
+
3280a9
+        /* It already existed (in the operation extension) an index of the operation in the pending list */
3280a9
+        for (idx_pl = 0, current_op = prim_op; current_op->next; idx_pl++, current_op = current_op->next) {
3280a9
+            if (op_ident->idx_pl == idx_pl) {
3280a9
+                break;
3280a9
+            }
3280a9
+        }
3280a9
+
3280a9
+        /* The retrieved operation in the pending list is at the right
3280a9
+         * index and state. Just return making this callback a noop
3280a9
+         */
3280a9
+        PR_ASSERT(current_op);
3280a9
+        PR_ASSERT(current_op->op == op);
3280a9
+        PR_ASSERT(current_op->flags == OPERATION_PL_PENDING);
3280a9
+        slapi_log_err(SLAPI_LOG_WARNING, SYNC_PLUGIN_SUBSYSTEM, "sync_update_persist_betxn_pre_op - DB retried operation targets "
3280a9
+                      "\"%s\" (op=0x%lx idx_pl=%d) => op not changed in PL\n",
3280a9
+                      slapi_sdn_get_dn(sdn), (ulong) op, idx_pl);
3280a9
+        return 0;
3280a9
+    }
3280a9
+
3280a9
     /* Create a new pending operation node */
3280a9
     new_op = (OPERATION_PL_CTX_T *)slapi_ch_calloc(1, sizeof(OPERATION_PL_CTX_T));
3280a9
     new_op->flags = OPERATION_PL_PENDING;
3280a9
-    slapi_pblock_get(pb, SLAPI_OPERATION, &new_op->op);
3280a9
-    slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn;;
3280a9
+    new_op->op = op;
3280a9
 
3280a9
-    prim_op = get_thread_primary_op();
3280a9
     if (prim_op) {
3280a9
         /* It already exists a primary operation, so the current
3280a9
          * operation is a nested one that we need to register at the end
3280a9
          * of the pending nested operations
3280a9
+         * Also computes the idx_pl that will be the identifier (index) of the operation
3280a9
+         * in the pending list
3280a9
          */
3280a9
         OPERATION_PL_CTX_T *current_op;
3280a9
-        for (current_op = prim_op; current_op->next; current_op = current_op->next);
3280a9
+        for (idx_pl = 0, current_op = prim_op; current_op->next; idx_pl++, current_op = current_op->next);
3280a9
         current_op->next = new_op;
3280a9
+        idx_pl++; /* idx_pl is currently the index of the last op
3280a9
+                   * as we are adding a new op we need to increase that index
3280a9
+                   */
3280a9
         slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "sync_update_persist_betxn_pre_op - nested operation targets "
3280a9
-                      "\"%s\" (0x%lx)\n",
3280a9
-                      slapi_sdn_get_dn(sdn), (ulong) new_op->op);
3280a9
+                      "\"%s\" (op=0x%lx idx_pl=%d)\n",
3280a9
+                      slapi_sdn_get_dn(sdn), (ulong) new_op->op, idx_pl);
3280a9
     } else {
3280a9
         /* The current operation is the first/primary one in the txn
3280a9
          * registers it directly in the thread private data (head)
3280a9
          */
3280a9
         set_thread_primary_op(new_op);
3280a9
+        idx_pl = 0; /* as primary operation, its index in the pending list is 0 */
3280a9
         slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "sync_update_persist_betxn_pre_op - primary operation targets "
3280a9
                       "\"%s\" (0x%lx)\n",
3280a9
                       slapi_sdn_get_dn(sdn), (ulong) new_op->op);
3280a9
     }
3280a9
+
3280a9
+    /* records, in the operation extension AND in the pending list, the identifier (index) of
3280a9
+     * this operation into the pending list
3280a9
+     */
3280a9
+    op_ident = (op_ext_ident_t *) slapi_ch_calloc(1, sizeof (op_ext_ident_t));
3280a9
+    op_ident->idx_pl = idx_pl;
3280a9
+    new_op->idx_pl   = idx_pl;
3280a9
+    sync_persist_set_operation_extension(pb, op_ident);
3280a9
     return 0;
3280a9
 }
3280a9
 
3280a9
-/* This operation can not be proceed by sync_repl listener because
3280a9
- * of internal problem. For example, POST entry does not exist
3280a9
+/* This operation failed or skipped (e.g. no MODs).
3280a9
+ * In such case POST entry does not exist
3280a9
  */
3280a9
 static void
3280a9
-ignore_op_pl(Operation *op)
3280a9
+ignore_op_pl(Slapi_PBlock *pb)
3280a9
 {
3280a9
     OPERATION_PL_CTX_T *prim_op, *curr_op;
3280a9
+    op_ext_ident_t *ident;
3280a9
+    Operation *op;
3280a9
+
3280a9
+    slapi_pblock_get(pb, SLAPI_OPERATION, &op);
3280a9
+
3280a9
+    /* prim_op is set if betxn was called
3280a9
+     * In case of invalid update (schema violation) the
3280a9
+     * operation skip betxn and prim_op is not set.
3280a9
+     * This is the same for ident
3280a9
+     */
3280a9
     prim_op = get_thread_primary_op();
3280a9
+    ident = sync_persist_get_operation_extension(pb);
3280a9
 
3280a9
-    for (curr_op = prim_op; curr_op; curr_op = curr_op->next) {
3280a9
-        if ((curr_op->op == op) && 
3280a9
-            (curr_op->flags == OPERATION_PL_PENDING)) {  /* If by any "chance" a same operation structure was reused in consecutive updates
3280a9
-                                                         * we can not only rely on 'op' value
3280a9
-                                                         */
3280a9
-            slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM, "ignore_op_pl operation (0x%lx) from the pending list\n",
3280a9
-                    (ulong) op);
3280a9
-            curr_op->flags = OPERATION_PL_IGNORED;
3280a9
-            return;
3280a9
+    if (ident) {
3280a9
+        /* The TXN_BEPROP was called, so the operation is
3280a9
+         * registered in the pending list
3280a9
+         */
3280a9
+        for (curr_op = prim_op; curr_op; curr_op = curr_op->next) {
3280a9
+            if (curr_op->idx_pl == ident->idx_pl) {
3280a9
+                /* The operation extension (ident) refers this operation (currop in the pending list).
3280a9
+                 * This is called during sync_repl postop. At this moment
3280a9
+                 * the operation in the pending list (identified by idx_pl in the operation extension)
3280a9
+                 * should be pending
3280a9
+                 */
3280a9
+                PR_ASSERT(curr_op->flags == OPERATION_PL_PENDING);
3280a9
+                slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "ignore_op_pl operation (op=0x%lx, idx_pl=%d) from the pending list\n",
3280a9
+                        (ulong) op, ident->idx_pl);
3280a9
+                curr_op->flags = OPERATION_PL_IGNORED;
3280a9
+                return;
3280a9
+            }
3280a9
         }
3280a9
     }
3280a9
-    slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM, "ignore_op_pl can not retrieve an operation (0x%lx) in pending list\n",
3280a9
-                    (ulong) op);
3280a9
+    slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "ignore_op_pl failing operation (op=0x%lx, idx_pl=%d) was not in the pending list\n",
3280a9
+                    (ulong) op, ident ? ident->idx_pl : -1);
3280a9
 }
3280a9
 
3280a9
 /* This is a generic function that is called by betxn_post of this plugin.
3280a9
@@ -126,7 +193,9 @@ sync_update_persist_op(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eprev, ber
3280a9
 {
3280a9
     OPERATION_PL_CTX_T *prim_op = NULL, *curr_op;
3280a9
     Operation *pb_op;
3280a9
+    op_ext_ident_t *ident;
3280a9
     Slapi_DN *sdn;
3280a9
+    uint32_t count; /* use for diagnostic of the lenght of the pending list */
3280a9
     int32_t rc;
3280a9
 
3280a9
     if (!SYNC_IS_INITIALIZED()) {
3280a9
@@ -138,7 +207,7 @@ sync_update_persist_op(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eprev, ber
3280a9
 
3280a9
     if (NULL == e) {
3280a9
         /* Ignore this operation (for example case of failure of the operation) */
3280a9
-        ignore_op_pl(pb_op);
3280a9
+        ignore_op_pl(pb);
3280a9
         return;
3280a9
     }
3280a9
     
3280a9
@@ -161,16 +230,21 @@ sync_update_persist_op(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eprev, ber
3280a9
 
3280a9
 
3280a9
     prim_op = get_thread_primary_op();
3280a9
+    ident = sync_persist_get_operation_extension(pb);
3280a9
     PR_ASSERT(prim_op);
3280a9
+    PR_ASSERT(ident);
3280a9
     /* First mark the operation as completed/failed
3280a9
      * the param to be used once the operation will be pushed
3280a9
      * on the listeners queue
3280a9
      */
3280a9
     for (curr_op = prim_op; curr_op; curr_op = curr_op->next) {
3280a9
-        if ((curr_op->op == pb_op) &&
3280a9
-            (curr_op->flags == OPERATION_PL_PENDING)) {  /* If by any "chance" a same operation structure was reused in consecutive updates
3280a9
-                                                         * we can not only rely on 'op' value
3280a9
-                                                         */
3280a9
+        if (curr_op->idx_pl == ident->idx_pl) {
3280a9
+            /* The operation extension (ident) refers this operation (currop in the pending list)
3280a9
+             * This is called during sync_repl postop. At this moment
3280a9
+             * the operation in the pending list (identified by idx_pl in the operation extension)
3280a9
+             * should be pending
3280a9
+             */
3280a9
+            PR_ASSERT(curr_op->flags == OPERATION_PL_PENDING);
3280a9
             if (rc == LDAP_SUCCESS) {
3280a9
                 curr_op->flags = OPERATION_PL_SUCCEEDED;
3280a9
                 curr_op->entry = e ? slapi_entry_dup(e) : NULL;
3280a9
@@ -183,46 +257,50 @@ sync_update_persist_op(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eprev, ber
3280a9
         }
3280a9
     }
3280a9
     if (!curr_op) {
3280a9
-        slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM, "%s - operation not found on the pendling list\n", label);
3280a9
+        slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM, "%s - operation (op=0x%lx, idx_pl=%d) not found on the pendling list\n", 
3280a9
+                      label, (ulong) pb_op, ident->idx_pl);
3280a9
         PR_ASSERT(curr_op);
3280a9
     }
3280a9
     
3280a9
-#if DEBUG
3280a9
-    /* dump the pending queue */
3280a9
-    for (curr_op = prim_op; curr_op; curr_op = curr_op->next) {
3280a9
-        char *flags_str;
3280a9
-        char * entry_str;
3280a9
+    /* for diagnostic of the pending list, dump its content if it is too long */
3280a9
+    for (count = 0, curr_op = prim_op; curr_op; count++, curr_op = curr_op->next);
3280a9
+    if (loglevel_is_set(SLAPI_LOG_PLUGIN) && (count > 10)) {
3280a9
 
3280a9
-        if (curr_op->entry) {
3280a9
-            entry_str = slapi_entry_get_dn(curr_op->entry);
3280a9
-        } else if (curr_op->eprev){
3280a9
-            entry_str = slapi_entry_get_dn(curr_op->eprev);
3280a9
-        } else {
3280a9
-            entry_str = "unknown";
3280a9
-        }
3280a9
-        switch (curr_op->flags) {
3280a9
-            case OPERATION_PL_SUCCEEDED:
3280a9
-                flags_str = "succeeded";
3280a9
-                break;
3280a9
-            case OPERATION_PL_FAILED:
3280a9
-                flags_str = "failed";
3280a9
-                break;
3280a9
-            case OPERATION_PL_IGNORED:
3280a9
-                flags_str = "ignored";
3280a9
-                break;
3280a9
-            case OPERATION_PL_PENDING:
3280a9
-                flags_str = "pending";
3280a9
-                break;
3280a9
-            default:
3280a9
-                flags_str = "unknown";
3280a9
-                break;
3280a9
-                        
3280a9
+        /* if pending list looks abnormally too long, dump the pending list */
3280a9
+        for (curr_op = prim_op; curr_op; curr_op = curr_op->next) {
3280a9
+            char *flags_str;
3280a9
+            char * entry_str;
3280a9
 
3280a9
-        }
3280a9
-        slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "dump pending list(0x%lx) %s %s\n",
3280a9
+            if (curr_op->entry) {
3280a9
+                entry_str = slapi_entry_get_dn(curr_op->entry);
3280a9
+            } else if (curr_op->eprev) {
3280a9
+                entry_str = slapi_entry_get_dn(curr_op->eprev);
3280a9
+            } else {
3280a9
+                entry_str = "unknown";
3280a9
+            }
3280a9
+            switch (curr_op->flags) {
3280a9
+                case OPERATION_PL_SUCCEEDED:
3280a9
+                    flags_str = "succeeded";
3280a9
+                    break;
3280a9
+                case OPERATION_PL_FAILED:
3280a9
+                    flags_str = "failed";
3280a9
+                    break;
3280a9
+                case OPERATION_PL_IGNORED:
3280a9
+                    flags_str = "ignored";
3280a9
+                    break;
3280a9
+                case OPERATION_PL_PENDING:
3280a9
+                    flags_str = "pending";
3280a9
+                    break;
3280a9
+                default:
3280a9
+                    flags_str = "unknown";
3280a9
+                    break;
3280a9
+
3280a9
+
3280a9
+            }
3280a9
+            slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM, "dump pending list(0x%lx) %s %s\n",
3280a9
                     (ulong) curr_op->op, entry_str, flags_str);
3280a9
+        }
3280a9
     }
3280a9
-#endif
3280a9
 
3280a9
     /* Second check if it remains a pending operation in the pending list */
3280a9
     for (curr_op = prim_op; curr_op; curr_op = curr_op->next) {
3280a9
-- 
3280a9
2.26.2
3280a9