927 lines
43 KiB
Diff
927 lines
43 KiB
Diff
|
From 8df95679519364d0993572ecbea72ab89e5250a5 Mon Sep 17 00:00:00 2001
|
||
|
From: Simon Pichugin <spichugi@redhat.com>
|
||
|
Date: Thu, 20 May 2021 14:24:25 +0200
|
||
|
Subject: [PATCH 09/12] Issue 4623 - RFE - Monitor the current DB locks (#4762)
|
||
|
|
||
|
Description: DB lock gets exhausted because of unindexed internal searches
|
||
|
(under a transaction). Indexing those searches is the way to prevent exhaustion.
|
||
|
If db lock get exhausted during a txn, it leads to db panic and the later recovery
|
||
|
can possibly fail. That leads to a full reinit of the instance where the db locks
|
||
|
got exhausted.
|
||
|
|
||
|
Add three attributes to global BDB config: "nsslapd-db-locks-monitoring-enabled",
|
||
|
"nsslapd-db-locks-monitoring-threshold" and "nsslapd-db-locks-monitoring-pause".
|
||
|
By default, nsslapd-db-locks-monitoring-enabled is turned on, nsslapd-db-locks-monitoring-threshold is set to 90% and nsslapd-db-locks-monitoring-threshold is 500ms.
|
||
|
|
||
|
When current locks are close to the maximum locks value of 90% - returning
|
||
|
the next candidate will fail until the maximum of locks won't be
|
||
|
increased or current locks are released.
|
||
|
The monitoring thread runs with the configurable interval of 500ms.
|
||
|
|
||
|
Add the setting to UI and CLI tools.
|
||
|
|
||
|
Fixes: https://github.com/389ds/389-ds-base/issues/4623
|
||
|
|
||
|
Reviewed by: @Firstyear, @tbordaz, @jchapma, @mreynolds389 (Thank you!!)
|
||
|
---
|
||
|
.../suites/monitor/db_locks_monitor_test.py | 251 ++++++++++++++++++
|
||
|
ldap/servers/slapd/back-ldbm/back-ldbm.h | 13 +-
|
||
|
.../slapd/back-ldbm/db-bdb/bdb_config.c | 99 +++++++
|
||
|
.../slapd/back-ldbm/db-bdb/bdb_layer.c | 85 ++++++
|
||
|
ldap/servers/slapd/back-ldbm/init.c | 3 +
|
||
|
ldap/servers/slapd/back-ldbm/ldbm_config.c | 3 +
|
||
|
ldap/servers/slapd/back-ldbm/ldbm_config.h | 3 +
|
||
|
ldap/servers/slapd/back-ldbm/ldbm_search.c | 13 +
|
||
|
ldap/servers/slapd/libglobs.c | 4 +-
|
||
|
src/cockpit/389-console/src/css/ds.css | 4 +
|
||
|
src/cockpit/389-console/src/database.jsx | 7 +
|
||
|
src/cockpit/389-console/src/index.html | 2 +-
|
||
|
.../src/lib/database/databaseConfig.jsx | 88 +++++-
|
||
|
src/lib389/lib389/backend.py | 3 +
|
||
|
src/lib389/lib389/cli_conf/backend.py | 10 +
|
||
|
15 files changed, 576 insertions(+), 12 deletions(-)
|
||
|
create mode 100644 dirsrvtests/tests/suites/monitor/db_locks_monitor_test.py
|
||
|
|
||
|
diff --git a/dirsrvtests/tests/suites/monitor/db_locks_monitor_test.py b/dirsrvtests/tests/suites/monitor/db_locks_monitor_test.py
|
||
|
new file mode 100644
|
||
|
index 000000000..7f9938f30
|
||
|
--- /dev/null
|
||
|
+++ b/dirsrvtests/tests/suites/monitor/db_locks_monitor_test.py
|
||
|
@@ -0,0 +1,251 @@
|
||
|
+# --- BEGIN COPYRIGHT BLOCK ---
|
||
|
+# Copyright (C) 2021 Red Hat, Inc.
|
||
|
+# All rights reserved.
|
||
|
+#
|
||
|
+# License: GPL (version 3 or any later version).
|
||
|
+# See LICENSE for details.
|
||
|
+# --- END COPYRIGHT BLOCK ---
|
||
|
+#
|
||
|
+import logging
|
||
|
+import pytest
|
||
|
+import datetime
|
||
|
+import subprocess
|
||
|
+from multiprocessing import Process, Queue
|
||
|
+from lib389 import pid_from_file
|
||
|
+from lib389.utils import ldap, os
|
||
|
+from lib389._constants import DEFAULT_SUFFIX, ReplicaRole
|
||
|
+from lib389.cli_base import LogCapture
|
||
|
+from lib389.idm.user import UserAccounts
|
||
|
+from lib389.idm.organizationalunit import OrganizationalUnits
|
||
|
+from lib389.tasks import AccessLog
|
||
|
+from lib389.backend import Backends
|
||
|
+from lib389.ldclt import Ldclt
|
||
|
+from lib389.dbgen import dbgen_users
|
||
|
+from lib389.tasks import ImportTask
|
||
|
+from lib389.index import Indexes
|
||
|
+from lib389.plugins import AttributeUniquenessPlugin
|
||
|
+from lib389.config import BDB_LDBMConfig
|
||
|
+from lib389.monitor import MonitorLDBM
|
||
|
+from lib389.topologies import create_topology, _remove_ssca_db
|
||
|
+
|
||
|
+pytestmark = pytest.mark.tier2
|
||
|
+db_locks_monitoring_ack = pytest.mark.skipif(not os.environ.get('DB_LOCKS_MONITORING_ACK', False),
|
||
|
+ reason="DB locks monitoring tests may take hours if the feature is not present or another failure exists. "
|
||
|
+ "Also, the feature requires a big amount of space as we set nsslapd-db-locks to 1300000.")
|
||
|
+
|
||
|
+DEBUGGING = os.getenv('DEBUGGING', default=False)
|
||
|
+if DEBUGGING:
|
||
|
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
|
||
|
+else:
|
||
|
+ logging.getLogger(__name__).setLevel(logging.INFO)
|
||
|
+log = logging.getLogger(__name__)
|
||
|
+
|
||
|
+
|
||
|
+def _kill_ns_slapd(inst):
|
||
|
+ pid = str(pid_from_file(inst.ds_paths.pid_file))
|
||
|
+ cmd = ['kill', '-9', pid]
|
||
|
+ subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
||
|
+
|
||
|
+
|
||
|
+@pytest.fixture(scope="function")
|
||
|
+def topology_st_fn(request):
|
||
|
+ """Create DS standalone instance for each test case"""
|
||
|
+
|
||
|
+ topology = create_topology({ReplicaRole.STANDALONE: 1})
|
||
|
+
|
||
|
+ def fin():
|
||
|
+ # Kill the hanging process at the end of test to prevent failures in the following tests
|
||
|
+ if DEBUGGING:
|
||
|
+ [_kill_ns_slapd(inst) for inst in topology]
|
||
|
+ else:
|
||
|
+ [_kill_ns_slapd(inst) for inst in topology]
|
||
|
+ assert _remove_ssca_db(topology)
|
||
|
+ [inst.stop() for inst in topology if inst.exists()]
|
||
|
+ [inst.delete() for inst in topology if inst.exists()]
|
||
|
+ request.addfinalizer(fin)
|
||
|
+
|
||
|
+ topology.logcap = LogCapture()
|
||
|
+ return topology
|
||
|
+
|
||
|
+
|
||
|
+@pytest.fixture(scope="function")
|
||
|
+def setup_attruniq_index_be_import(topology_st_fn):
|
||
|
+ """Enable Attribute Uniqueness, disable indexes and
|
||
|
+ import 120000 entries to the default backend
|
||
|
+ """
|
||
|
+ inst = topology_st_fn.standalone
|
||
|
+
|
||
|
+ inst.config.loglevel([AccessLog.DEFAULT, AccessLog.INTERNAL], service='access')
|
||
|
+ inst.config.set('nsslapd-plugin-logging', 'on')
|
||
|
+ inst.restart()
|
||
|
+
|
||
|
+ attruniq = AttributeUniquenessPlugin(inst, dn="cn=attruniq,cn=plugins,cn=config")
|
||
|
+ attruniq.create(properties={'cn': 'attruniq'})
|
||
|
+ for cn in ['uid', 'cn', 'sn', 'uidNumber', 'gidNumber', 'homeDirectory', 'givenName', 'description']:
|
||
|
+ attruniq.add_unique_attribute(cn)
|
||
|
+ attruniq.add_unique_subtree(DEFAULT_SUFFIX)
|
||
|
+ attruniq.enable_all_subtrees()
|
||
|
+ attruniq.enable()
|
||
|
+
|
||
|
+ indexes = Indexes(inst)
|
||
|
+ for cn in ['uid', 'cn', 'sn', 'uidNumber', 'gidNumber', 'homeDirectory', 'givenName', 'description']:
|
||
|
+ indexes.ensure_state(properties={
|
||
|
+ 'cn': cn,
|
||
|
+ 'nsSystemIndex': 'false',
|
||
|
+ 'nsIndexType': 'none'})
|
||
|
+
|
||
|
+ bdb_config = BDB_LDBMConfig(inst)
|
||
|
+ bdb_config.replace("nsslapd-db-locks", "130000")
|
||
|
+ inst.restart()
|
||
|
+
|
||
|
+ ldif_dir = inst.get_ldif_dir()
|
||
|
+ import_ldif = ldif_dir + '/perf_import.ldif'
|
||
|
+
|
||
|
+ # Valid online import
|
||
|
+ import_task = ImportTask(inst)
|
||
|
+ dbgen_users(inst, 120000, import_ldif, DEFAULT_SUFFIX, entry_name="userNew")
|
||
|
+ import_task.import_suffix_from_ldif(ldiffile=import_ldif, suffix=DEFAULT_SUFFIX)
|
||
|
+ import_task.wait()
|
||
|
+ assert import_task.is_complete()
|
||
|
+
|
||
|
+
|
||
|
+def create_user_wrapper(q, users):
|
||
|
+ try:
|
||
|
+ users.create_test_user()
|
||
|
+ except Exception as ex:
|
||
|
+ q.put(ex)
|
||
|
+
|
||
|
+
|
||
|
+def spawn_worker_thread(function, users, log, timeout, info):
|
||
|
+ log.info(f"Starting the thread - {info}")
|
||
|
+ q = Queue()
|
||
|
+ p = Process(target=function, args=(q,users,))
|
||
|
+ p.start()
|
||
|
+
|
||
|
+ log.info(f"Waiting for {timeout} seconds for the thread to finish")
|
||
|
+ p.join(timeout)
|
||
|
+
|
||
|
+ if p.is_alive():
|
||
|
+ log.info("Killing the thread as it's still running")
|
||
|
+ p.terminate()
|
||
|
+ p.join()
|
||
|
+ raise RuntimeError(f"Function call was aborted: {info}")
|
||
|
+ result = q.get()
|
||
|
+ if isinstance(result, Exception):
|
||
|
+ raise result
|
||
|
+ else:
|
||
|
+ return result
|
||
|
+
|
||
|
+
|
||
|
+@db_locks_monitoring_ack
|
||
|
+@pytest.mark.parametrize("lock_threshold", [("70"), ("80"), ("95")])
|
||
|
+def test_exhaust_db_locks_basic(topology_st_fn, setup_attruniq_index_be_import, lock_threshold):
|
||
|
+ """Test that when all of the locks are exhausted the instance still working
|
||
|
+ and database is not corrupted
|
||
|
+
|
||
|
+ :id: 299108cc-04d8-4ddc-b58e-99157fccd643
|
||
|
+ :setup: Standalone instance with Attr Uniq plugin and user indexes disabled
|
||
|
+ :steps: 1. Set nsslapd-db-locks to 11000
|
||
|
+ 2. Check that we stop acquiring new locks when the threshold is reached
|
||
|
+ 3. Check that we can regulate a pause interval for DB locks monitoring thread
|
||
|
+ 4. Make sure the feature works for different backends on the same suffix
|
||
|
+ :expectedresults:
|
||
|
+ 1. Success
|
||
|
+ 2. Success
|
||
|
+ 3. Success
|
||
|
+ 4. Success
|
||
|
+ """
|
||
|
+
|
||
|
+ inst = topology_st_fn.standalone
|
||
|
+ ADDITIONAL_SUFFIX = 'ou=newpeople,dc=example,dc=com'
|
||
|
+
|
||
|
+ backends = Backends(inst)
|
||
|
+ backends.create(properties={'nsslapd-suffix': ADDITIONAL_SUFFIX,
|
||
|
+ 'name': ADDITIONAL_SUFFIX[-3:]})
|
||
|
+ ous = OrganizationalUnits(inst, DEFAULT_SUFFIX)
|
||
|
+ ous.create(properties={'ou': 'newpeople'})
|
||
|
+
|
||
|
+ bdb_config = BDB_LDBMConfig(inst)
|
||
|
+ bdb_config.replace("nsslapd-db-locks", "11000")
|
||
|
+
|
||
|
+ # Restart server
|
||
|
+ inst.restart()
|
||
|
+
|
||
|
+ for lock_enabled in ["on", "off"]:
|
||
|
+ for lock_pause in ["100", "500", "1000"]:
|
||
|
+ bdb_config.replace("nsslapd-db-locks-monitoring-enabled", lock_enabled)
|
||
|
+ bdb_config.replace("nsslapd-db-locks-monitoring-threshold", lock_threshold)
|
||
|
+ bdb_config.replace("nsslapd-db-locks-monitoring-pause", lock_pause)
|
||
|
+ inst.restart()
|
||
|
+
|
||
|
+ if lock_enabled == "off":
|
||
|
+ raised_exception = (RuntimeError, ldap.SERVER_DOWN)
|
||
|
+ else:
|
||
|
+ raised_exception = ldap.OPERATIONS_ERROR
|
||
|
+
|
||
|
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||
|
+ with pytest.raises(raised_exception):
|
||
|
+ spawn_worker_thread(create_user_wrapper, users, log, 30,
|
||
|
+ f"Adding user with monitoring enabled='{lock_enabled}'; "
|
||
|
+ f"threshold='{lock_threshold}'; pause='{lock_pause}'.")
|
||
|
+ # Restart because we already run out of locks and the next unindexed searches will fail eventually
|
||
|
+ if lock_enabled == "off":
|
||
|
+ _kill_ns_slapd(inst)
|
||
|
+ inst.restart()
|
||
|
+
|
||
|
+ users = UserAccounts(inst, ADDITIONAL_SUFFIX, rdn=None)
|
||
|
+ with pytest.raises(raised_exception):
|
||
|
+ spawn_worker_thread(create_user_wrapper, users, log, 30,
|
||
|
+ f"Adding user with monitoring enabled='{lock_enabled}'; "
|
||
|
+ f"threshold='{lock_threshold}'; pause='{lock_pause}'.")
|
||
|
+ # In case feature is disabled - restart for the clean up
|
||
|
+ if lock_enabled == "off":
|
||
|
+ _kill_ns_slapd(inst)
|
||
|
+ inst.restart()
|
||
|
+
|
||
|
+
|
||
|
+@db_locks_monitoring_ack
|
||
|
+def test_exhaust_db_locks_big_pause(topology_st_fn, setup_attruniq_index_be_import):
|
||
|
+ """Test that DB lock pause setting increases the wait interval value for the monitoring thread
|
||
|
+
|
||
|
+ :id: 7d5bf838-5d4e-4ad5-8c03-5716afb84ea6
|
||
|
+ :setup: Standalone instance with Attr Uniq plugin and user indexes disabled
|
||
|
+ :steps: 1. Set nsslapd-db-locks to 20000 while using the default threshold value (95%)
|
||
|
+ 2. Set nsslapd-db-locks-monitoring-pause to 10000 (10 seconds)
|
||
|
+ 3. Make sure that the pause is successfully increased a few times in a row
|
||
|
+ :expectedresults:
|
||
|
+ 1. Success
|
||
|
+ 2. Success
|
||
|
+ 3. Success
|
||
|
+ """
|
||
|
+
|
||
|
+ inst = topology_st_fn.standalone
|
||
|
+
|
||
|
+ bdb_config = BDB_LDBMConfig(inst)
|
||
|
+ bdb_config.replace("nsslapd-db-locks", "20000")
|
||
|
+ lock_pause = bdb_config.get_attr_val_int("nsslapd-db-locks-monitoring-pause")
|
||
|
+ assert lock_pause == 500
|
||
|
+ lock_pause = "10000"
|
||
|
+ bdb_config.replace("nsslapd-db-locks-monitoring-pause", lock_pause)
|
||
|
+
|
||
|
+ # Restart server
|
||
|
+ inst.restart()
|
||
|
+
|
||
|
+ lock_enabled = bdb_config.get_attr_val_utf8_l("nsslapd-db-locks-monitoring-enabled")
|
||
|
+ lock_threshold = bdb_config.get_attr_val_int("nsslapd-db-locks-monitoring-threshold")
|
||
|
+ assert lock_enabled == "on"
|
||
|
+ assert lock_threshold == 90
|
||
|
+
|
||
|
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||
|
+ start = datetime.datetime.now()
|
||
|
+ with pytest.raises(ldap.OPERATIONS_ERROR):
|
||
|
+ spawn_worker_thread(create_user_wrapper, users, log, 30,
|
||
|
+ f"Adding user with monitoring enabled='{lock_enabled}'; "
|
||
|
+ f"threshold='{lock_threshold}'; pause='{lock_pause}'. Expect it to 'Work'")
|
||
|
+ end = datetime.datetime.now()
|
||
|
+ time_delta = end - start
|
||
|
+ if time_delta.seconds < 9:
|
||
|
+ raise RuntimeError("nsslapd-db-locks-monitoring-pause attribute doesn't function correctly. "
|
||
|
+ f"Finished the execution in {time_delta.seconds} seconds")
|
||
|
+ # In case something has failed - restart for the clean up
|
||
|
+ inst.restart()
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
||
|
index 571b0a58b..afb831c32 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
||
|
@@ -155,6 +155,8 @@ typedef unsigned short u_int16_t;
|
||
|
#define DEFAULT_DNCACHE_MAXCOUNT -1 /* no limit */
|
||
|
#define DEFAULT_DBCACHE_SIZE 33554432
|
||
|
#define DEFAULT_DBCACHE_SIZE_STR "33554432"
|
||
|
+#define DEFAULT_DBLOCK_PAUSE 500
|
||
|
+#define DEFAULT_DBLOCK_PAUSE_STR "500"
|
||
|
#define DEFAULT_MODE 0600
|
||
|
#define DEFAULT_ALLIDSTHRESHOLD 4000
|
||
|
#define DEFAULT_IDL_TUNE 1
|
||
|
@@ -575,12 +577,21 @@ struct ldbminfo
|
||
|
char *li_backend_implement; /* low layer backend implementation */
|
||
|
int li_noparentcheck; /* check if parent exists on add */
|
||
|
|
||
|
- /* the next 3 fields are for the params that don't get changed until
|
||
|
+ /* db lock monitoring */
|
||
|
+ /* if we decide to move the values to bdb_config, we can use slapi_back_get_info function to retrieve the values */
|
||
|
+ int32_t li_dblock_monitoring; /* enables db locks monitoring thread - requires restart */
|
||
|
+ uint32_t li_dblock_monitoring_pause; /* an interval for db locks monitoring thread */
|
||
|
+ uint32_t li_dblock_threshold; /* when the percentage is reached, abort the search in ldbm_back_next_search_entry - requires restart*/
|
||
|
+ uint32_t li_dblock_threshold_reached;
|
||
|
+
|
||
|
+ /* the next 4 fields are for the params that don't get changed until
|
||
|
* the server is restarted (used by the admin console)
|
||
|
*/
|
||
|
char *li_new_directory;
|
||
|
uint64_t li_new_dbcachesize;
|
||
|
int li_new_dblock;
|
||
|
+ int32_t li_new_dblock_monitoring;
|
||
|
+ uint64_t li_new_dblock_threshold;
|
||
|
|
||
|
int li_new_dbncache;
|
||
|
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_config.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_config.c
|
||
|
index 738b841aa..167644943 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_config.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_config.c
|
||
|
@@ -190,6 +190,102 @@ bdb_config_db_lock_set(void *arg, void *value, char *errorbuf, int phase, int ap
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
+static void *
|
||
|
+bdb_config_db_lock_monitoring_get(void *arg)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+
|
||
|
+ return (void *)((intptr_t)(li->li_new_dblock_monitoring));
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+bdb_config_db_lock_monitoring_set(void *arg, void *value, char *errorbuf __attribute__((unused)), int phase __attribute__((unused)), int apply)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+ int retval = LDAP_SUCCESS;
|
||
|
+ int val = (int32_t)((intptr_t)value);
|
||
|
+
|
||
|
+ if (apply) {
|
||
|
+ if (CONFIG_PHASE_RUNNING == phase) {
|
||
|
+ li->li_new_dblock_monitoring = val;
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_config_db_lock_monitoring_set",
|
||
|
+ "New nsslapd-db-lock-monitoring value will not take affect until the server is restarted\n");
|
||
|
+ } else {
|
||
|
+ li->li_new_dblock_monitoring = val;
|
||
|
+ li->li_dblock_monitoring = val;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+static void *
|
||
|
+bdb_config_db_lock_pause_get(void *arg)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+
|
||
|
+ return (void *)((uintptr_t)(slapi_atomic_load_32((int32_t *)&(li->li_dblock_monitoring_pause), __ATOMIC_RELAXED)));
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+bdb_config_db_lock_pause_set(void *arg, void *value, char *errorbuf, int phase __attribute__((unused)), int apply)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+ int retval = LDAP_SUCCESS;
|
||
|
+ u_int32_t val = (u_int32_t)((uintptr_t)value);
|
||
|
+
|
||
|
+ if (val == 0) {
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_config_db_lock_pause_set",
|
||
|
+ "%s was set to '0'. The default value will be used (%s)",
|
||
|
+ CONFIG_DB_LOCKS_PAUSE, DEFAULT_DBLOCK_PAUSE_STR);
|
||
|
+ val = DEFAULT_DBLOCK_PAUSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (apply) {
|
||
|
+ slapi_atomic_store_32((int32_t *)&(li->li_dblock_monitoring_pause), val, __ATOMIC_RELAXED);
|
||
|
+ }
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
+static void *
|
||
|
+bdb_config_db_lock_threshold_get(void *arg)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+
|
||
|
+ return (void *)((uintptr_t)(li->li_new_dblock_threshold));
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+bdb_config_db_lock_threshold_set(void *arg, void *value, char *errorbuf, int phase __attribute__((unused)), int apply)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+ int retval = LDAP_SUCCESS;
|
||
|
+ u_int32_t val = (u_int32_t)((uintptr_t)value);
|
||
|
+
|
||
|
+ if (val < 70 || val > 95) {
|
||
|
+ slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
|
||
|
+ "%s: \"%d\" is invalid, threshold is indicated as a percentage and it must lie in range of 70 and 95",
|
||
|
+ CONFIG_DB_LOCKS_THRESHOLD, val);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_config_db_lock_threshold_set",
|
||
|
+ "%s: \"%d\" is invalid, threshold is indicated as a percentage and it must lie in range of 70 and 95",
|
||
|
+ CONFIG_DB_LOCKS_THRESHOLD, val);
|
||
|
+ retval = LDAP_OPERATIONS_ERROR;
|
||
|
+ return retval;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (apply) {
|
||
|
+ if (CONFIG_PHASE_RUNNING == phase) {
|
||
|
+ li->li_new_dblock_threshold = val;
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_config_db_lock_threshold_set",
|
||
|
+ "New nsslapd-db-lock-monitoring-threshold value will not take affect until the server is restarted\n");
|
||
|
+ } else {
|
||
|
+ li->li_new_dblock_threshold = val;
|
||
|
+ li->li_dblock_threshold = val;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
static void *
|
||
|
bdb_config_dbcachesize_get(void *arg)
|
||
|
{
|
||
|
@@ -1409,6 +1505,9 @@ static config_info bdb_config_param[] = {
|
||
|
{CONFIG_SERIAL_LOCK, CONFIG_TYPE_ONOFF, "on", &bdb_config_serial_lock_get, &bdb_config_serial_lock_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
{CONFIG_USE_LEGACY_ERRORCODE, CONFIG_TYPE_ONOFF, "off", &bdb_config_legacy_errcode_get, &bdb_config_legacy_errcode_set, 0},
|
||
|
{CONFIG_DB_DEADLOCK_POLICY, CONFIG_TYPE_INT, STRINGIFYDEFINE(DB_LOCK_YOUNGEST), &bdb_config_db_deadlock_policy_get, &bdb_config_db_deadlock_policy_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
+ {CONFIG_DB_LOCKS_MONITORING, CONFIG_TYPE_ONOFF, "on", &bdb_config_db_lock_monitoring_get, &bdb_config_db_lock_monitoring_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
+ {CONFIG_DB_LOCKS_THRESHOLD, CONFIG_TYPE_INT, "90", &bdb_config_db_lock_threshold_get, &bdb_config_db_lock_threshold_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
+ {CONFIG_DB_LOCKS_PAUSE, CONFIG_TYPE_INT, DEFAULT_DBLOCK_PAUSE_STR, &bdb_config_db_lock_pause_get, &bdb_config_db_lock_pause_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
{NULL, 0, NULL, NULL, NULL, 0}};
|
||
|
|
||
|
void
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||
|
index 6cccad8e6..2f25f67a2 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||
|
@@ -35,6 +35,8 @@
|
||
|
(env)->txn_checkpoint((env), (kbyte), (min), (flags))
|
||
|
#define MEMP_STAT(env, gsp, fsp, flags, malloc) \
|
||
|
(env)->memp_stat((env), (gsp), (fsp), (flags))
|
||
|
+#define LOCK_STAT(env, statp, flags, malloc) \
|
||
|
+ (env)->lock_stat((env), (statp), (flags))
|
||
|
#define MEMP_TRICKLE(env, pct, nwrotep) \
|
||
|
(env)->memp_trickle((env), (pct), (nwrotep))
|
||
|
#define LOG_ARCHIVE(env, listp, flags, malloc) \
|
||
|
@@ -66,6 +68,7 @@
|
||
|
#define NEWDIR_MODE 0755
|
||
|
#define DB_REGION_PREFIX "__db."
|
||
|
|
||
|
+static int locks_monitoring_threadmain(void *param);
|
||
|
static int perf_threadmain(void *param);
|
||
|
static int checkpoint_threadmain(void *param);
|
||
|
static int trickle_threadmain(void *param);
|
||
|
@@ -84,6 +87,7 @@ static int bdb_start_checkpoint_thread(struct ldbminfo *li);
|
||
|
static int bdb_start_trickle_thread(struct ldbminfo *li);
|
||
|
static int bdb_start_perf_thread(struct ldbminfo *li);
|
||
|
static int bdb_start_txn_test_thread(struct ldbminfo *li);
|
||
|
+static int bdb_start_locks_monitoring_thread(struct ldbminfo *li);
|
||
|
static int trans_batch_count = 0;
|
||
|
static int trans_batch_limit = 0;
|
||
|
static int trans_batch_txn_min_sleep = 50; /* ms */
|
||
|
@@ -1299,6 +1303,10 @@ bdb_start(struct ldbminfo *li, int dbmode)
|
||
|
return return_value;
|
||
|
}
|
||
|
|
||
|
+ if (0 != (return_value = bdb_start_locks_monitoring_thread(li))) {
|
||
|
+ return return_value;
|
||
|
+ }
|
||
|
+
|
||
|
/* We need to free the memory to avoid a leak
|
||
|
* Also, we have to evaluate if the performance counter
|
||
|
* should be preserved or not for database restore.
|
||
|
@@ -2885,6 +2893,7 @@ bdb_start_perf_thread(struct ldbminfo *li)
|
||
|
return return_value;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
/* Performance thread */
|
||
|
static int
|
||
|
perf_threadmain(void *param)
|
||
|
@@ -2910,6 +2919,82 @@ perf_threadmain(void *param)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+/*
|
||
|
+ * create a thread for locks_monitoring_threadmain
|
||
|
+ */
|
||
|
+static int
|
||
|
+bdb_start_locks_monitoring_thread(struct ldbminfo *li)
|
||
|
+{
|
||
|
+ int return_value = 0;
|
||
|
+ if (li->li_dblock_monitoring) {
|
||
|
+ if (NULL == PR_CreateThread(PR_USER_THREAD,
|
||
|
+ (VFP)(void *)locks_monitoring_threadmain, li,
|
||
|
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||
|
+ PR_UNJOINABLE_THREAD,
|
||
|
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) {
|
||
|
+ PRErrorCode prerr = PR_GetError();
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_start_locks_monitoring_thread",
|
||
|
+ "Failed to create database locks monitoring thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
|
||
|
+ prerr, slapd_pr_strerror(prerr));
|
||
|
+ return_value = -1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return return_value;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+/* DB Locks Monitoring thread */
|
||
|
+static int
|
||
|
+locks_monitoring_threadmain(void *param)
|
||
|
+{
|
||
|
+ int ret = 0;
|
||
|
+ uint64_t current_locks = 0;
|
||
|
+ uint64_t max_locks = 0;
|
||
|
+ uint32_t lock_exhaustion = 0;
|
||
|
+ PRIntervalTime interval;
|
||
|
+ struct ldbminfo *li = NULL;
|
||
|
+
|
||
|
+ PR_ASSERT(NULL != param);
|
||
|
+ li = (struct ldbminfo *)param;
|
||
|
+
|
||
|
+ dblayer_private *priv = li->li_dblayer_private;
|
||
|
+ bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
|
||
|
+ PR_ASSERT(NULL != priv);
|
||
|
+
|
||
|
+ INCR_THREAD_COUNT(pEnv);
|
||
|
+
|
||
|
+ while (!BDB_CONFIG(li)->bdb_stop_threads) {
|
||
|
+ if (dblayer_db_uses_locking(pEnv->bdb_DB_ENV)) {
|
||
|
+ DB_LOCK_STAT *lockstat = NULL;
|
||
|
+ ret = LOCK_STAT(pEnv->bdb_DB_ENV, &lockstat, 0, (void *)slapi_ch_malloc);
|
||
|
+ if (0 == ret) {
|
||
|
+ current_locks = lockstat->st_nlocks;
|
||
|
+ max_locks = lockstat->st_maxlocks;
|
||
|
+ if (max_locks){
|
||
|
+ lock_exhaustion = (uint32_t)((double)current_locks / (double)max_locks * 100.0);
|
||
|
+ } else {
|
||
|
+ lock_exhaustion = 0;
|
||
|
+ }
|
||
|
+ if ((li->li_dblock_threshold) &&
|
||
|
+ (lock_exhaustion >= li->li_dblock_threshold)) {
|
||
|
+ slapi_atomic_store_32((int32_t *)&(li->li_dblock_threshold_reached), 1, __ATOMIC_RELAXED);
|
||
|
+ } else {
|
||
|
+ slapi_atomic_store_32((int32_t *)&(li->li_dblock_threshold_reached), 0, __ATOMIC_RELAXED);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ slapi_ch_free((void **)&lockstat);
|
||
|
+ }
|
||
|
+ interval = PR_MillisecondsToInterval(slapi_atomic_load_32((int32_t *)&(li->li_dblock_monitoring_pause), __ATOMIC_RELAXED));
|
||
|
+ DS_Sleep(interval);
|
||
|
+ }
|
||
|
+
|
||
|
+ DECR_THREAD_COUNT(pEnv);
|
||
|
+ slapi_log_err(SLAPI_LOG_TRACE, "locks_monitoring_threadmain", "Leaving locks_monitoring_threadmain\n");
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
/*
|
||
|
* create a thread for deadlock_threadmain
|
||
|
*/
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/init.c b/ldap/servers/slapd/back-ldbm/init.c
|
||
|
index 893776699..4165c8fad 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/init.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/init.c
|
||
|
@@ -70,6 +70,9 @@ ldbm_back_init(Slapi_PBlock *pb)
|
||
|
/* Initialize the set of instances. */
|
||
|
li->li_instance_set = objset_new(&ldbm_back_instance_set_destructor);
|
||
|
|
||
|
+ /* Init lock threshold value */
|
||
|
+ li->li_dblock_threshold_reached = 0;
|
||
|
+
|
||
|
/* ask the factory to give us space in the Connection object
|
||
|
* (only bulk import uses this)
|
||
|
*/
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c
|
||
|
index 10cef250f..60884cf33 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/ldbm_config.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c
|
||
|
@@ -87,6 +87,9 @@ static char *ldbm_config_moved_attributes[] =
|
||
|
CONFIG_SERIAL_LOCK,
|
||
|
CONFIG_USE_LEGACY_ERRORCODE,
|
||
|
CONFIG_DB_DEADLOCK_POLICY,
|
||
|
+ CONFIG_DB_LOCKS_MONITORING,
|
||
|
+ CONFIG_DB_LOCKS_THRESHOLD,
|
||
|
+ CONFIG_DB_LOCKS_PAUSE,
|
||
|
""};
|
||
|
|
||
|
/* Used to add an array of entries, like the one above and
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.h b/ldap/servers/slapd/back-ldbm/ldbm_config.h
|
||
|
index 58e64799c..6fa8292eb 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/ldbm_config.h
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.h
|
||
|
@@ -104,6 +104,9 @@ struct config_info
|
||
|
#define CONFIG_DB_VERBOSE "nsslapd-db-verbose"
|
||
|
#define CONFIG_DB_DEBUG "nsslapd-db-debug"
|
||
|
#define CONFIG_DB_LOCK "nsslapd-db-locks"
|
||
|
+#define CONFIG_DB_LOCKS_MONITORING "nsslapd-db-locks-monitoring-enabled"
|
||
|
+#define CONFIG_DB_LOCKS_THRESHOLD "nsslapd-db-locks-monitoring-threshold"
|
||
|
+#define CONFIG_DB_LOCKS_PAUSE "nsslapd-db-locks-monitoring-pause"
|
||
|
#define CONFIG_DB_NAMED_REGIONS "nsslapd-db-named-regions"
|
||
|
#define CONFIG_DB_PRIVATE_MEM "nsslapd-db-private-mem"
|
||
|
#define CONFIG_DB_PRIVATE_IMPORT_MEM "nsslapd-db-private-import-mem"
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
|
||
|
index 1a7b510d4..6e22debde 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
|
||
|
@@ -1472,6 +1472,7 @@ ldbm_back_next_search_entry_ext(Slapi_PBlock *pb, int use_extension)
|
||
|
slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
|
||
|
slapi_pblock_get(pb, SLAPI_OPERATION, &op);
|
||
|
|
||
|
+
|
||
|
if ((reverse_list = operation_is_flag_set(op, OP_FLAG_REVERSE_CANDIDATE_ORDER))) {
|
||
|
/*
|
||
|
* Start at the end of the list and work our way forward. Since a single
|
||
|
@@ -1538,6 +1539,18 @@ ldbm_back_next_search_entry_ext(Slapi_PBlock *pb, int use_extension)
|
||
|
|
||
|
/* Find the next candidate entry and return it. */
|
||
|
while (1) {
|
||
|
+ if (li->li_dblock_monitoring &&
|
||
|
+ slapi_atomic_load_32((int32_t *)&(li->li_dblock_threshold_reached), __ATOMIC_RELAXED)) {
|
||
|
+ slapi_log_err(SLAPI_LOG_CRIT, "ldbm_back_next_search_entry",
|
||
|
+ "DB locks threshold is reached (nsslapd-db-locks-monitoring-threshold "
|
||
|
+ "under cn=bdb,cn=config,cn=ldbm database,cn=plugins,cn=config). "
|
||
|
+ "Please, increase nsslapd-db-locks according to your needs.\n");
|
||
|
+ slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, NULL);
|
||
|
+ delete_search_result_set(pb, &sr);
|
||
|
+ rc = SLAPI_FAIL_GENERAL;
|
||
|
+ slapi_send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "DB locks threshold is reached (nsslapd-db-locks-monitoring-threshold)", 0, NULL);
|
||
|
+ goto bail;
|
||
|
+ }
|
||
|
|
||
|
/* check for abandon */
|
||
|
if (slapi_op_abandoned(pb) || (NULL == sr)) {
|
||
|
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
|
||
|
index 388616b36..db7d01bbc 100644
|
||
|
--- a/ldap/servers/slapd/libglobs.c
|
||
|
+++ b/ldap/servers/slapd/libglobs.c
|
||
|
@@ -8171,8 +8171,8 @@ config_set(const char *attr, struct berval **values, char *errorbuf, int apply)
|
||
|
#if 0
|
||
|
debugHashTable(attr);
|
||
|
#endif
|
||
|
- slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Unknown attribute %s will be ignored", attr);
|
||
|
- slapi_log_err(SLAPI_LOG_ERR, "config_set", "Unknown attribute %s will be ignored", attr);
|
||
|
+ slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Unknown attribute %s will be ignored\n", attr);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "config_set", "Unknown attribute %s will be ignored\n", attr);
|
||
|
return LDAP_NO_SUCH_ATTRIBUTE;
|
||
|
}
|
||
|
|
||
|
diff --git a/src/cockpit/389-console/src/css/ds.css b/src/cockpit/389-console/src/css/ds.css
|
||
|
index 9248116e7..3cf50b593 100644
|
||
|
--- a/src/cockpit/389-console/src/css/ds.css
|
||
|
+++ b/src/cockpit/389-console/src/css/ds.css
|
||
|
@@ -639,6 +639,10 @@ option {
|
||
|
padding-right: 0 !important;
|
||
|
}
|
||
|
|
||
|
+.ds-vertical-scroll-auto {
|
||
|
+ overflow-y: auto !important;
|
||
|
+}
|
||
|
+
|
||
|
.alert {
|
||
|
max-width: 750px;
|
||
|
}
|
||
|
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
|
||
|
index efa3ce6d5..11cae972c 100644
|
||
|
--- a/src/cockpit/389-console/src/database.jsx
|
||
|
+++ b/src/cockpit/389-console/src/database.jsx
|
||
|
@@ -157,6 +157,7 @@ export class Database extends React.Component {
|
||
|
const attrs = config.attrs;
|
||
|
let db_cache_auto = false;
|
||
|
let import_cache_auto = false;
|
||
|
+ let dblocksMonitoring = false;
|
||
|
let dbhome = "";
|
||
|
|
||
|
if ('nsslapd-db-home-directory' in attrs) {
|
||
|
@@ -168,6 +169,9 @@ export class Database extends React.Component {
|
||
|
if (attrs['nsslapd-import-cache-autosize'] != "0") {
|
||
|
import_cache_auto = true;
|
||
|
}
|
||
|
+ if (attrs['nsslapd-db-locks-monitoring-enabled'][0] == "on") {
|
||
|
+ dblocksMonitoring = true;
|
||
|
+ }
|
||
|
|
||
|
this.setState(() => (
|
||
|
{
|
||
|
@@ -187,6 +191,9 @@ export class Database extends React.Component {
|
||
|
txnlogdir: attrs['nsslapd-db-logdirectory'],
|
||
|
dbhomedir: dbhome,
|
||
|
dblocks: attrs['nsslapd-db-locks'],
|
||
|
+ dblocksMonitoring: dblocksMonitoring,
|
||
|
+ dblocksMonitoringThreshold: attrs['nsslapd-db-locks-monitoring-threshold'],
|
||
|
+ dblocksMonitoringPause: attrs['nsslapd-db-locks-monitoring-pause'],
|
||
|
chxpoint: attrs['nsslapd-db-checkpoint-interval'],
|
||
|
compactinterval: attrs['nsslapd-db-compactdb-interval'],
|
||
|
importcacheauto: attrs['nsslapd-import-cache-autosize'],
|
||
|
diff --git a/src/cockpit/389-console/src/index.html b/src/cockpit/389-console/src/index.html
|
||
|
index 1278844fc..fd0eeb669 100644
|
||
|
--- a/src/cockpit/389-console/src/index.html
|
||
|
+++ b/src/cockpit/389-console/src/index.html
|
||
|
@@ -12,7 +12,7 @@
|
||
|
</head>
|
||
|
|
||
|
|
||
|
-<body>
|
||
|
+<body class="ds-vertical-scroll-auto">
|
||
|
<div id="dsinstance"></div>
|
||
|
<script src="index.js"></script>
|
||
|
</body>
|
||
|
diff --git a/src/cockpit/389-console/src/lib/database/databaseConfig.jsx b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
|
||
|
index f6e662bca..6a71c138d 100644
|
||
|
--- a/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
|
||
|
+++ b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
|
||
|
@@ -31,6 +31,9 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
txnlogdir: this.props.data.txnlogdir,
|
||
|
dbhomedir: this.props.data.dbhomedir,
|
||
|
dblocks: this.props.data.dblocks,
|
||
|
+ dblocksMonitoring: this.props.data.dblocksMonitoring,
|
||
|
+ dblocksMonitoringThreshold: this.props.data.dblocksMonitoringThreshold,
|
||
|
+ dblocksMonitoringPause: this.props.data.dblocksMonitoringPause,
|
||
|
chxpoint: this.props.data.chxpoint,
|
||
|
compactinterval: this.props.data.compactinterval,
|
||
|
importcachesize: this.props.data.importcachesize,
|
||
|
@@ -47,6 +50,9 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
_txnlogdir: this.props.data.txnlogdir,
|
||
|
_dbhomedir: this.props.data.dbhomedir,
|
||
|
_dblocks: this.props.data.dblocks,
|
||
|
+ _dblocksMonitoring: this.props.data.dblocksMonitoring,
|
||
|
+ _dblocksMonitoringThreshold: this.props.data.dblocksMonitoringThreshold,
|
||
|
+ _dblocksMonitoringPause: this.props.data.dblocksMonitoringPause,
|
||
|
_chxpoint: this.props.data.chxpoint,
|
||
|
_compactinterval: this.props.data.compactinterval,
|
||
|
_importcachesize: this.props.data.importcachesize,
|
||
|
@@ -55,6 +61,7 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
_import_cache_auto: this.props.data.import_cache_auto,
|
||
|
};
|
||
|
this.handleChange = this.handleChange.bind(this);
|
||
|
+ this.select_db_locks_monitoring = this.select_db_locks_monitoring.bind(this);
|
||
|
this.select_auto_cache = this.select_auto_cache.bind(this);
|
||
|
this.select_auto_import_cache = this.select_auto_import_cache.bind(this);
|
||
|
this.save_db_config = this.save_db_config.bind(this);
|
||
|
@@ -76,6 +83,12 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
}, this.handleChange(e));
|
||
|
}
|
||
|
|
||
|
+ select_db_locks_monitoring (val, e) {
|
||
|
+ this.setState({
|
||
|
+ dblocksMonitoring: !this.state.dblocksMonitoring
|
||
|
+ }, this.handleChange(val, e));
|
||
|
+ }
|
||
|
+
|
||
|
handleChange(e) {
|
||
|
// Generic
|
||
|
const value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
|
||
|
@@ -150,6 +163,21 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
cmd.push("--locks=" + this.state.dblocks);
|
||
|
requireRestart = true;
|
||
|
}
|
||
|
+ if (this.state._dblocksMonitoring != this.state.dblocksMonitoring) {
|
||
|
+ if (this.state.dblocksMonitoring) {
|
||
|
+ cmd.push("--locks-monitoring-enabled=on");
|
||
|
+ } else {
|
||
|
+ cmd.push("--locks-monitoring-enabled=off");
|
||
|
+ }
|
||
|
+ requireRestart = true;
|
||
|
+ }
|
||
|
+ if (this.state._dblocksMonitoringThreshold != this.state.dblocksMonitoringThreshold) {
|
||
|
+ cmd.push("--locks-monitoring-threshold=" + this.state.dblocksMonitoringThreshold);
|
||
|
+ requireRestart = true;
|
||
|
+ }
|
||
|
+ if (this.state._dblocksMonitoringPause != this.state.dblocksMonitoringPause) {
|
||
|
+ cmd.push("--locks-monitoring-pause=" + this.state.dblocksMonitoringPause);
|
||
|
+ }
|
||
|
if (this.state._chxpoint != this.state.chxpoint) {
|
||
|
cmd.push("--checkpoint-interval=" + this.state.chxpoint);
|
||
|
requireRestart = true;
|
||
|
@@ -216,6 +244,28 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
let import_cache_form;
|
||
|
let db_auto_checked = false;
|
||
|
let import_auto_checked = false;
|
||
|
+ let dblocksMonitor = "";
|
||
|
+
|
||
|
+ if (this.state.dblocksMonitoring) {
|
||
|
+ dblocksMonitor = <div className="ds-margin-top">
|
||
|
+ <Row className="ds-margin-top" title="Sets the DB lock exhaustion value in percentage (valid range is 70-95). If too many locks are acquired, the server will abort the searches while the number of locks are not decreased. It helps to avoid DB corruption and long recovery. (nsslapd-db-locks-monitoring-threshold)">
|
||
|
+ <Col componentClass={ControlLabel} sm={4}>
|
||
|
+ DB Locks Threshold Percentage
|
||
|
+ </Col>
|
||
|
+ <Col sm={8}>
|
||
|
+ <input className="ds-input" type="number" id="dblocksMonitoringThreshold" size="10" onChange={this.handleChange} value={this.state.dblocksMonitoringThreshold} />
|
||
|
+ </Col>
|
||
|
+ </Row>
|
||
|
+ <Row className="ds-margin-top" title="Sets the amount of time (milliseconds) that the monitoring thread spends waiting between checks. (nsslapd-db-locks-monitoring-pause)">
|
||
|
+ <Col componentClass={ControlLabel} sm={4}>
|
||
|
+ DB Locks Pause Milliseconds
|
||
|
+ </Col>
|
||
|
+ <Col sm={8}>
|
||
|
+ <input className="ds-input" type="number" id="dblocksMonitoringPause" size="10" onChange={this.handleChange} value={this.state.dblocksMonitoringPause} />
|
||
|
+ </Col>
|
||
|
+ </Row>
|
||
|
+ </div>;
|
||
|
+ }
|
||
|
|
||
|
if (this.state.db_cache_auto) {
|
||
|
db_cache_form = <div id="auto-cache-form" className="ds-margin-left">
|
||
|
@@ -422,14 +472,6 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
<input id="dbhomedir" value={this.state.dbhomedir} onChange={this.handleChange} className="ds-input-auto" type="text" />
|
||
|
</Col>
|
||
|
</Row>
|
||
|
- <Row className="ds-margin-top" title="The number of database locks (nsslapd-db-locks).">
|
||
|
- <Col componentClass={ControlLabel} sm={4}>
|
||
|
- Database Locks
|
||
|
- </Col>
|
||
|
- <Col sm={8}>
|
||
|
- <input id="dblocks" value={this.state.dblocks} onChange={this.handleChange} className="ds-input-auto" type="text" />
|
||
|
- </Col>
|
||
|
- </Row>
|
||
|
<Row className="ds-margin-top" title="Amount of time in seconds after which the Directory Server sends a checkpoint entry to the database transaction log (nsslapd-db-checkpoint-interval).">
|
||
|
<Col componentClass={ControlLabel} sm={4}>
|
||
|
Database Checkpoint Interval
|
||
|
@@ -446,6 +488,36 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
<input id="compactinterval" value={this.state.compactinterval} onChange={this.handleChange} className="ds-input-auto" type="text" />
|
||
|
</Col>
|
||
|
</Row>
|
||
|
+ <Row className="ds-margin-top" title="The number of database locks (nsslapd-db-locks).">
|
||
|
+ <Col componentClass={ControlLabel} sm={4}>
|
||
|
+ Database Locks
|
||
|
+ </Col>
|
||
|
+ <Col sm={8}>
|
||
|
+ <input id="dblocks" value={this.state.dblocks} onChange={this.handleChange} className="ds-input-auto" type="text" />
|
||
|
+ </Col>
|
||
|
+ </Row>
|
||
|
+ <Row>
|
||
|
+ <Col sm={12}>
|
||
|
+ <h5 className="ds-sub-header">DB Locks Monitoring</h5>
|
||
|
+ <hr />
|
||
|
+ </Col>
|
||
|
+ </Row>
|
||
|
+ <Row>
|
||
|
+ <Col sm={12}>
|
||
|
+ <Checkbox title="Set input to be set automatically"
|
||
|
+ id="dblocksMonitoring"
|
||
|
+ checked={this.state.dblocksMonitoring}
|
||
|
+ onChange={this.select_db_locks_monitoring}
|
||
|
+ >
|
||
|
+ Enable Monitoring
|
||
|
+ </Checkbox>
|
||
|
+ </Col>
|
||
|
+ </Row>
|
||
|
+ <Row>
|
||
|
+ <Col sm={12}>
|
||
|
+ {dblocksMonitor}
|
||
|
+ </Col>
|
||
|
+ </Row>
|
||
|
</Form>
|
||
|
</div>
|
||
|
</div>
|
||
|
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
|
||
|
index bcd7b383f..13bb27842 100644
|
||
|
--- a/src/lib389/lib389/backend.py
|
||
|
+++ b/src/lib389/lib389/backend.py
|
||
|
@@ -1011,6 +1011,9 @@ class DatabaseConfig(DSLdapObject):
|
||
|
'nsslapd-db-transaction-batch-max-wait',
|
||
|
'nsslapd-db-logbuf-size',
|
||
|
'nsslapd-db-locks',
|
||
|
+ 'nsslapd-db-locks-monitoring-enabled',
|
||
|
+ 'nsslapd-db-locks-monitoring-threshold',
|
||
|
+ 'nsslapd-db-locks-monitoring-pause',
|
||
|
'nsslapd-db-private-import-mem',
|
||
|
'nsslapd-import-cache-autosize',
|
||
|
'nsslapd-cache-autosize',
|
||
|
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
|
||
|
index 6bfbcb036..722764d10 100644
|
||
|
--- a/src/lib389/lib389/cli_conf/backend.py
|
||
|
+++ b/src/lib389/lib389/cli_conf/backend.py
|
||
|
@@ -46,6 +46,9 @@ arg_to_attr = {
|
||
|
'txn_batch_max': 'nsslapd-db-transaction-batch-max-wait',
|
||
|
'logbufsize': 'nsslapd-db-logbuf-size',
|
||
|
'locks': 'nsslapd-db-locks',
|
||
|
+ 'locks_monitoring_enabled': 'nsslapd-db-locks-monitoring-enabled',
|
||
|
+ 'locks_monitoring_threshold': 'nsslapd-db-locks-monitoring-threshold',
|
||
|
+ 'locks_monitoring_pause': 'nsslapd-db-locks-monitoring-pause',
|
||
|
'import_cache_autosize': 'nsslapd-import-cache-autosize',
|
||
|
'cache_autosize': 'nsslapd-cache-autosize',
|
||
|
'cache_autosize_split': 'nsslapd-cache-autosize-split',
|
||
|
@@ -998,6 +1001,13 @@ def create_parser(subparsers):
|
||
|
'the batch count (only works when txn-batch-val is set)')
|
||
|
set_db_config_parser.add_argument('--logbufsize', help='Specifies the transaction log information buffer size')
|
||
|
set_db_config_parser.add_argument('--locks', help='Sets the maximum number of database locks')
|
||
|
+ set_db_config_parser.add_argument('--locks-monitoring-enabled', help='Set to "on" or "off" to monitor DB locks. When it crosses the percentage value '
|
||
|
+ 'set with "--locks-monitoring-threshold" ("on" by default)')
|
||
|
+ set_db_config_parser.add_argument('--locks-monitoring-threshold', help='Sets the DB lock exhaustion value in percentage (valid range is 70-95). If too many locks are '
|
||
|
+ 'acquired, the server will abort the searches while the number of locks '
|
||
|
+ 'are not decreased. It helps to avoid DB corruption and long recovery.')
|
||
|
+ set_db_config_parser.add_argument('--locks-monitoring-pause', help='Sets the DB lock monitoring value in milliseconds for the amount of time '
|
||
|
+ 'that the monitoring thread spends waiting between checks.')
|
||
|
set_db_config_parser.add_argument('--import-cache-autosize', help='Set to "on" or "off" to automatically set the size of the import '
|
||
|
'cache to be used during the the import process of LDIF files')
|
||
|
set_db_config_parser.add_argument('--cache-autosize', help='Sets the percentage of free memory that is used in total for the database '
|
||
|
--
|
||
|
2.26.3
|
||
|
|