Blame SOURCES/0013-Ticket-49076-To-debug-DB_DEADLOCK-condition-allow-to.patch

6f51e1
From 1a66f5f232d6c2869ef4e439eafe5a820f61a976 Mon Sep 17 00:00:00 2001
6f51e1
From: Thierry Bordaz <tbordaz@redhat.com>
6f51e1
Date: Wed, 15 Feb 2017 11:31:27 +0100
6f51e1
Subject: [PATCH] Ticket 49076 - To debug DB_DEADLOCK condition, allow to reset
6f51e1
 DB_TXN_NOWAIT flag on txn_begin
6f51e1
6f51e1
Bug Description:
6f51e1
    For debug reason it is interesting to have a new configuration ldbm backend config
6f51e1
    option (nsslapd-db-transaction-wait) that allows to hang on deadlock
6f51e1
    rather to let the server handling retries.
6f51e1
6f51e1
Fix Description:
6f51e1
    The fix introduce a new attribute nsslapd-db-transaction-wait under
6f51e1
    "cn=config,cn=ldbm database,cn=plugins,cn=config".
6f51e1
    By default it is "off" (ldbm returns DB_DEADLOCK) and can be changed
6f51e1
    online.
6f51e1
    It is taken into account when a new transcation begin.
6f51e1
6f51e1
https://pagure.io/389-ds-base/issue/49076
6f51e1
6f51e1
Reviewed by: William Brown, Ludwig Krispenz
6f51e1
6f51e1
Platforms tested: F23
6f51e1
6f51e1
Flag Day: no
6f51e1
6f51e1
Doc impact: no
6f51e1
---
6f51e1
 dirsrvtests/tests/tickets/ticket49076_test.py | 103 ++++++++++++++++++++++++++
6f51e1
 ldap/servers/slapd/back-ldbm/dblayer.c        |   9 ++-
6f51e1
 ldap/servers/slapd/back-ldbm/dblayer.h        |   3 +
6f51e1
 ldap/servers/slapd/back-ldbm/ldbm_config.c    |  22 ++++++
6f51e1
 ldap/servers/slapd/back-ldbm/ldbm_config.h    |   1 +
6f51e1
 5 files changed, 137 insertions(+), 1 deletion(-)
6f51e1
 create mode 100644 dirsrvtests/tests/tickets/ticket49076_test.py
6f51e1
6f51e1
diff --git a/dirsrvtests/tests/tickets/ticket49076_test.py b/dirsrvtests/tests/tickets/ticket49076_test.py
6f51e1
new file mode 100644
6f51e1
index 0000000..c4a2c1b
6f51e1
--- /dev/null
6f51e1
+++ b/dirsrvtests/tests/tickets/ticket49076_test.py
6f51e1
@@ -0,0 +1,103 @@
6f51e1
+import time
6f51e1
+import ldap
6f51e1
+import logging
6f51e1
+import pytest
6f51e1
+from lib389 import DirSrv, Entry, tools, tasks
6f51e1
+from lib389.tools import DirSrvTools
6f51e1
+from lib389._constants import *
6f51e1
+from lib389.properties import *
6f51e1
+from lib389.tasks import *
6f51e1
+from lib389.utils import *
6f51e1
+from lib389.topologies import topology_st as topo
6f51e1
+
6f51e1
+DEBUGGING = os.getenv("DEBUGGING", default=False)
6f51e1
+if DEBUGGING:
6f51e1
+    logging.getLogger(__name__).setLevel(logging.DEBUG)
6f51e1
+else:
6f51e1
+    logging.getLogger(__name__).setLevel(logging.INFO)
6f51e1
+log = logging.getLogger(__name__)
6f51e1
+
6f51e1
+ldbm_config = "cn=config,%s" % (DN_LDBM)
6f51e1
+txn_begin_flag = "nsslapd-db-transaction-wait"
6f51e1
+TEST_USER_DN = 'cn=test,%s' % SUFFIX
6f51e1
+TEST_USER = "test"
6f51e1
+
6f51e1
+def _check_configured_value(topology_st, attr=txn_begin_flag, expected_value=None, required=False):
6f51e1
+    entries = topology_st.standalone.search_s(ldbm_config, ldap.SCOPE_BASE, 'cn=config')
6f51e1
+    if required:
6f51e1
+        assert (entries[0].hasValue(attr))
6f51e1
+    if entries[0].hasValue(attr):
6f51e1
+        topology_st.standalone.log.info('Current value is %s' % entries[0].getValue(attr))
6f51e1
+        assert (entries[0].getValue(attr) == expected_value)
6f51e1
+        
6f51e1
+def _update_db(topology_st):
6f51e1
+    topology_st.standalone.add_s(
6f51e1
+        Entry((TEST_USER_DN, {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
6f51e1
+                              'cn': TEST_USER,
6f51e1
+                              'sn': TEST_USER,
6f51e1
+                              'givenname': TEST_USER})))
6f51e1
+    topology_st.standalone.delete_s(TEST_USER_DN)
6f51e1
+
6f51e1
+def test_ticket49076(topo):
6f51e1
+    """Write your testcase here...
6f51e1
+
6f51e1
+    Also, if you need any testcase initialization,
6f51e1
+    please, write additional fixture for that(include finalizer).
6f51e1
+    """
6f51e1
+    
6f51e1
+    # check default value is DB_TXN_NOWAIT
6f51e1
+    _check_configured_value(topo, expected_value="off")
6f51e1
+    
6f51e1
+    # tests we are able to update DB
6f51e1
+    _update_db(topo)
6f51e1
+    
6f51e1
+    # switch to wait mode
6f51e1
+    topo.standalone.modify_s(ldbm_config,
6f51e1
+                                    [(ldap.MOD_REPLACE, txn_begin_flag, "on")])
6f51e1
+                                    # check default value is DB_TXN_NOWAIT
6f51e1
+    _check_configured_value(topo, expected_value="on")
6f51e1
+    _update_db(topo)
6f51e1
+    
6f51e1
+    
6f51e1
+    # switch back to "normal mode"
6f51e1
+    topo.standalone.modify_s(ldbm_config,
6f51e1
+                                    [(ldap.MOD_REPLACE, txn_begin_flag, "off")])
6f51e1
+    # check default value is DB_TXN_NOWAIT
6f51e1
+    _check_configured_value(topo, expected_value="off")
6f51e1
+    # tests we are able to update DB
6f51e1
+    _update_db(topo)
6f51e1
+    
6f51e1
+    # check that settings are not reset by restart
6f51e1
+    topo.standalone.modify_s(ldbm_config,
6f51e1
+                                    [(ldap.MOD_REPLACE, txn_begin_flag, "on")])
6f51e1
+                                    # check default value is DB_TXN_NOWAIT
6f51e1
+    _check_configured_value(topo, expected_value="on")
6f51e1
+    _update_db(topo)
6f51e1
+    topo.standalone.restart(timeout=10)
6f51e1
+    _check_configured_value(topo, expected_value="on")
6f51e1
+    _update_db(topo)
6f51e1
+    
6f51e1
+    # switch default value
6f51e1
+    topo.standalone.modify_s(ldbm_config,
6f51e1
+                                    [(ldap.MOD_DELETE, txn_begin_flag, None)])
6f51e1
+    # check default value is DB_TXN_NOWAIT
6f51e1
+    _check_configured_value(topo, expected_value="off")
6f51e1
+    # tests we are able to update DB
6f51e1
+    _update_db(topo)
6f51e1
+    topo.standalone.restart(timeout=10)
6f51e1
+    _check_configured_value(topo, expected_value="off")
6f51e1
+    # tests we are able to update DB
6f51e1
+    _update_db(topo)    
6f51e1
+                              
6f51e1
+
6f51e1
+    if DEBUGGING:
6f51e1
+        # Add debugging steps(if any)...
6f51e1
+        pass
6f51e1
+
6f51e1
+
6f51e1
+if __name__ == '__main__':
6f51e1
+    # Run isolated
6f51e1
+    # -s for DEBUG mode
6f51e1
+    CURRENT_FILE = os.path.realpath(__file__)
6f51e1
+    pytest.main("-s %s" % CURRENT_FILE)
6f51e1
+
6f51e1
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
6f51e1
index 683994f..507a3cc 100644
6f51e1
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
6f51e1
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
6f51e1
@@ -3374,6 +3374,8 @@ dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn,
6f51e1
 
6f51e1
     if (priv->dblayer_enable_transactions)
6f51e1
     {
6f51e1
+        int txn_begin_flags;
6f51e1
+
6f51e1
         dblayer_private_env *pEnv = priv->dblayer_env;
6f51e1
         if(use_lock) slapi_rwlock_rdlock(pEnv->dblayer_env_lock);
6f51e1
         if (!parent_txn)
6f51e1
@@ -3383,11 +3385,16 @@ dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn,
6f51e1
             if (par_txn_txn) {
6f51e1
                 parent_txn = par_txn_txn->back_txn_txn;
6f51e1
             }
6f51e1
+                }
6f51e1
+        if (priv->dblayer_txn_wait) {
6f51e1
+                txn_begin_flags = 0;
6f51e1
+        } else {
6f51e1
+                txn_begin_flags = DB_TXN_NOWAIT;
6f51e1
         }
6f51e1
         return_value = TXN_BEGIN(pEnv->dblayer_DB_ENV,
6f51e1
                                  (DB_TXN*)parent_txn,
6f51e1
                                  &new_txn.back_txn_txn,
6f51e1
-                                 DB_TXN_NOWAIT);
6f51e1
+                                 txn_begin_flags);
6f51e1
         if (0 != return_value) 
6f51e1
         {
6f51e1
             if(use_lock) slapi_rwlock_unlock(priv->dblayer_env->dblayer_env_lock);
6f51e1
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.h b/ldap/servers/slapd/back-ldbm/dblayer.h
6f51e1
index e02e6e0..e4307fc 100644
6f51e1
--- a/ldap/servers/slapd/back-ldbm/dblayer.h
6f51e1
+++ b/ldap/servers/slapd/back-ldbm/dblayer.h
6f51e1
@@ -104,6 +104,9 @@ struct dblayer_private
6f51e1
                                         * the mpool */
6f51e1
     int dblayer_recovery_required;
6f51e1
     int dblayer_enable_transactions;
6f51e1
+    int dblayer_txn_wait;           /* Default is "off" (DB_TXN_NOWAIT) but for
6f51e1
+                                     * support purpose it could be helpful to set
6f51e1
+                                     * "on" so that backend hang on deadlock */
6f51e1
     int dblayer_durable_transactions;
6f51e1
     int dblayer_checkpoint_interval;
6f51e1
     int dblayer_circular_logging;
6f51e1
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c
6f51e1
index 8541224..dfe7a13 100644
6f51e1
--- a/ldap/servers/slapd/back-ldbm/ldbm_config.c
6f51e1
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c
6f51e1
@@ -636,6 +636,27 @@ static int ldbm_config_db_transaction_logging_set(void *arg, void *value, char *
6f51e1
     return retval;
6f51e1
 }
6f51e1
 
6f51e1
+
6f51e1
+static void *ldbm_config_db_transaction_wait_get(void *arg)
6f51e1
+{
6f51e1
+    struct ldbminfo *li = (struct ldbminfo *) arg;
6f51e1
+
6f51e1
+    return (void *) ((uintptr_t)li->li_dblayer_private->dblayer_txn_wait);
6f51e1
+}
6f51e1
+
6f51e1
+static int ldbm_config_db_transaction_wait_set(void *arg, void *value, char *errorbuf, int phase, int apply)
6f51e1
+{
6f51e1
+    struct ldbminfo *li = (struct ldbminfo *) arg;
6f51e1
+    int retval = LDAP_SUCCESS;
6f51e1
+    int val = (int) ((uintptr_t)value);
6f51e1
+
6f51e1
+    if (apply) {
6f51e1
+        li->li_dblayer_private->dblayer_txn_wait = val;
6f51e1
+    }
6f51e1
+
6f51e1
+    return retval;
6f51e1
+}
6f51e1
+
6f51e1
 static void *ldbm_config_db_logbuf_size_get(void *arg) 
6f51e1
 {
6f51e1
     struct ldbminfo *li = (struct ldbminfo *) arg;
6f51e1
@@ -1517,6 +1538,7 @@ static config_info ldbm_config[] = {
6f51e1
     {CONFIG_DB_DURABLE_TRANSACTIONS, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_durable_transactions_get, &ldbm_config_db_durable_transactions_set, CONFIG_FLAG_ALWAYS_SHOW},
6f51e1
     {CONFIG_DB_CIRCULAR_LOGGING, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_circular_logging_get, &ldbm_config_db_circular_logging_set, 0},
6f51e1
     {CONFIG_DB_TRANSACTION_LOGGING, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_transaction_logging_get, &ldbm_config_db_transaction_logging_set, 0},
6f51e1
+    {CONFIG_DB_TRANSACTION_WAIT, CONFIG_TYPE_ONOFF, "off", &ldbm_config_db_transaction_wait_get, &ldbm_config_db_transaction_wait_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
6f51e1
     {CONFIG_DB_CHECKPOINT_INTERVAL, CONFIG_TYPE_INT, "60", &ldbm_config_db_checkpoint_interval_get, &ldbm_config_db_checkpoint_interval_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
6f51e1
     {CONFIG_DB_COMPACTDB_INTERVAL, CONFIG_TYPE_INT, "2592000"/*30days*/, &ldbm_config_db_compactdb_interval_get, &ldbm_config_db_compactdb_interval_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
6f51e1
     {CONFIG_DB_TRANSACTION_BATCH, CONFIG_TYPE_INT, "0", &dblayer_get_batch_transactions, &dblayer_set_batch_transactions, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
6f51e1
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.h b/ldap/servers/slapd/back-ldbm/ldbm_config.h
6f51e1
index f481937..ddec3a8 100644
6f51e1
--- a/ldap/servers/slapd/back-ldbm/ldbm_config.h
6f51e1
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.h
6f51e1
@@ -80,6 +80,7 @@ struct config_info {
6f51e1
 #define CONFIG_DB_DURABLE_TRANSACTIONS "nsslapd-db-durable-transaction"
6f51e1
 #define CONFIG_DB_CIRCULAR_LOGGING "nsslapd-db-circular-logging"
6f51e1
 #define CONFIG_DB_TRANSACTION_LOGGING "nsslapd-db-transaction-logging"
6f51e1
+#define CONFIG_DB_TRANSACTION_WAIT "nsslapd-db-transaction-wait"
6f51e1
 #define CONFIG_DB_CHECKPOINT_INTERVAL "nsslapd-db-checkpoint-interval"
6f51e1
 #define CONFIG_DB_COMPACTDB_INTERVAL "nsslapd-db-compactdb-interval"
6f51e1
 #define CONFIG_DB_TRANSACTION_BATCH  "nsslapd-db-transaction-batch-val"
6f51e1
-- 
6f51e1
2.9.3
6f51e1