From 4989e77e2866d53c8bd79a3439b7dd84390cf576 Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Jun 28 2013 17:24:02 +0000 Subject: Ticket #47409 - allow setting db deadlock rejection policy https://fedorahosted.org/389/ticket/47409 Reviewed by: nhosoi (Thanks!) Branch: master Fix Description: Add the db config attribute nsslapd-db-deadlock-policy. This takes values from 1-9. The values correspond to the deadlock detector modes in db.h. These are the valid values to pass to the DBENV->lock_detect method for the atype parameter. The default value is 9 (DB_LOCK_YOUNGEST) - select the youngest locker and reject it. A value of 0 (DB_LOCK_NORUN) means to disable deadlock detection and rejection - not recommended except for testing purposes. Attempting to use other values will cause an error. Platforms tested: RHEL6 x86_64 Flag Day: no Doc impact: yes - document new config parameter --- diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c index dbe1886..bbe0ee4 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.c +++ b/ldap/servers/slapd/back-ldbm/dblayer.c @@ -4466,6 +4466,7 @@ static int deadlock_threadmain(void *param) dblayer_private *priv = NULL; struct ldbminfo *li = NULL; PRIntervalTime interval; /*NSPR timeout stuffy*/ + u_int32_t flags = 0; PR_ASSERT(NULL != param); li = (struct ldbminfo*)param; @@ -4480,13 +4481,19 @@ static int deadlock_threadmain(void *param) { if (priv->dblayer_enable_transactions) { - if (dblayer_db_uses_locking(priv->dblayer_env->dblayer_DB_ENV)) { - int aborted; - if ((rval = LOCK_DETECT(priv->dblayer_env->dblayer_DB_ENV, - 0, DB_LOCK_YOUNGEST, &aborted)) != 0) { + DB_ENV *db_env = priv->dblayer_env->dblayer_DB_ENV; + u_int32_t deadlock_policy = priv->dblayer_deadlock_policy; + + if (dblayer_db_uses_locking(db_env) && (deadlock_policy > DB_LOCK_NORUN)) { + int rejected = 0; + + if ((rval = LOCK_DETECT(db_env, 0, deadlock_policy, &rejected)) != 0) { LDAPDebug(LDAP_DEBUG_ANY, - "Serious Error---Failed in deadlock detect (aborted at 0x%x), err=%d (%s)\n", - aborted, rval, dblayer_strerror(rval)); + "Serious Error---Failed in deadlock detect (aborted at 0x%x), err=%d (%s)\n", + rejected, rval, dblayer_strerror(rval)); + } else if (rejected) { + LDAPDebug1Arg(LDAP_DEBUG_TRACE, "deadlock_threadmain: found and rejected %d lock requests\n", rejected); + } } } diff --git a/ldap/servers/slapd/back-ldbm/dblayer.h b/ldap/servers/slapd/back-ldbm/dblayer.h index ab9a85d..7f3200c 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.h +++ b/ldap/servers/slapd/back-ldbm/dblayer.h @@ -178,6 +178,7 @@ struct dblayer_private PRCondVar *thread_count_cv; /* condition variable for housekeeping thread shutdown */ int dblayer_lockdown; /* use DB_LOCKDOWN */ int dblayer_lock_config; + u_int32_t dblayer_deadlock_policy; /* i.e. the atype to DB_ENV->lock_detect in deadlock_threadmain */ }; #if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4300 diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c index a10f0c7..c39e69b 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_config.c +++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c @@ -1394,6 +1394,40 @@ static int ldbm_config_db_tx_max_set( return retval; } +static void *ldbm_config_db_deadlock_policy_get(void *arg) +{ + struct ldbminfo *li = (struct ldbminfo *) arg; + + return (void *) ((uintptr_t)li->li_dblayer_private->dblayer_deadlock_policy); +} + +static int ldbm_config_db_deadlock_policy_set(void *arg, void *value, char *errorbuf, int phase, int apply) +{ + struct ldbminfo *li = (struct ldbminfo *) arg; + int retval = LDAP_SUCCESS; + u_int32_t val = (u_int32_t) ((uintptr_t)value); + + if ((val < DB_LOCK_NORUN) || (val > DB_LOCK_YOUNGEST)) { + PR_snprintf(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "Error: Invalid value for %s (%d). Must be between %d and %d inclusive", + CONFIG_DB_DEADLOCK_POLICY, val, DB_LOCK_DEFAULT, DB_LOCK_YOUNGEST); + LDAPDebug1Arg(LDAP_DEBUG_ANY, "%s\n", errorbuf); + return LDAP_UNWILLING_TO_PERFORM; + } + if (val == DB_LOCK_NORUN) { + PR_snprintf(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, + "Warning: Setting value for %s to (%d) will disable deadlock detection", + CONFIG_DB_DEADLOCK_POLICY, val); + LDAPDebug1Arg(LDAP_DEBUG_ANY, "%s\n", errorbuf); + } + + if (apply) { + li->li_dblayer_private->dblayer_deadlock_policy = val; + } + + return retval; +} + /*------------------------------------------------------------------------ * Configuration array for ldbm and dblayer variables @@ -1458,6 +1492,7 @@ static config_info ldbm_config[] = { {CONFIG_PAGEDIDLISTSCANLIMIT, CONFIG_TYPE_INT, "0", &ldbm_config_pagedallidsthreshold_get, &ldbm_config_pagedallidsthreshold_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, {CONFIG_RANGELOOKTHROUGHLIMIT, CONFIG_TYPE_INT, "5000", &ldbm_config_rangelookthroughlimit_get, &ldbm_config_rangelookthroughlimit_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, {CONFIG_BACKEND_OPT_LEVEL, CONFIG_TYPE_INT, "1", &ldbm_config_backend_opt_level_get, &ldbm_config_backend_opt_level_set, CONFIG_FLAG_ALWAYS_SHOW}, + {CONFIG_DB_DEADLOCK_POLICY, CONFIG_TYPE_INT, STRINGIFYDEFINE(DB_LOCK_YOUNGEST), &ldbm_config_db_deadlock_policy_get, &ldbm_config_db_deadlock_policy_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, {NULL, 0, NULL, NULL, NULL, 0} }; diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.h b/ldap/servers/slapd/back-ldbm/ldbm_config.h index b0a7fab..f420707 100644 --- a/ldap/servers/slapd/back-ldbm/ldbm_config.h +++ b/ldap/servers/slapd/back-ldbm/ldbm_config.h @@ -164,6 +164,8 @@ struct config_info { #define CONFIG_USE_LEGACY_ERRORCODE "nsslapd-do-not-use-vlv-error" +#define CONFIG_DB_DEADLOCK_POLICY "nsslapd-db-deadlock-policy" + #define CONFIG_LDBM_DN "cn=config,cn=ldbm database,cn=plugins,cn=config" #define LDBM_INSTANCE_CONFIG_DONT_WRITE 1 diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h index 9a66f2a..f08540f 100644 --- a/ldap/servers/slapd/slapi-plugin.h +++ b/ldap/servers/slapd/slapi-plugin.h @@ -107,6 +107,9 @@ NSPR_API(PRUint32) PR_fprintf(struct PRFileDesc* fd, const char *fmt, ...) #define BERLEN_T "u" #endif +#define DEFINETOSTR(xxx) #xxx +#define STRINGIFYDEFINE(xxx) DEFINETOSTR(xxx) + /* Common check on berval before accessing the contents. */ /* bv is a struct berval *bv */ #define BV_HAS_DATA(bv) ((bv != NULL) && (bv->bv_len > 0) && (bv->bv_val != NULL))