1454 lines
68 KiB
Diff
1454 lines
68 KiB
Diff
|
From c79630de8012a893ed3d1c46b41bc7871a07a3e2 Mon Sep 17 00:00:00 2001
|
||
|
From: Mark Reynolds <mreynolds@redhat.com>
|
||
|
Date: Wed, 26 May 2021 13:32:13 -0400
|
||
|
Subject: [PATCH 11/12] Issue 4778 - RFE - Allow setting TOD for db compaction
|
||
|
and add task
|
||
|
|
||
|
Description: Since database compaction can be costly it should be allowed
|
||
|
to set a time to execute it during offpeak hours. Once the
|
||
|
compaction interval has been met, it will wait for the configured
|
||
|
time of day to do the compaction. The default is just before
|
||
|
midnight: 23:59
|
||
|
|
||
|
A task was also created that can run compaction on demand,
|
||
|
and can also just target the replication changelog. This could
|
||
|
be used in conjunction with a cronjob for more complex
|
||
|
execution patterns.
|
||
|
|
||
|
ASAN tested and approved.
|
||
|
|
||
|
relates: https://github.com/389ds/389-ds-base/issues/4778
|
||
|
|
||
|
Reviewed by: spichugi(Thanks!)
|
||
|
---
|
||
|
.../tests/suites/config/compact_test.py | 81 ++++++
|
||
|
ldap/schema/01core389.ldif | 3 +-
|
||
|
ldap/servers/plugins/replication/cl5.h | 1 +
|
||
|
ldap/servers/plugins/replication/cl5_api.c | 70 ++++-
|
||
|
ldap/servers/plugins/replication/cl5_api.h | 2 +-
|
||
|
.../servers/plugins/replication/cl5_clcache.c | 3 -
|
||
|
ldap/servers/plugins/replication/cl5_config.c | 102 ++++++-
|
||
|
ldap/servers/plugins/replication/cl5_init.c | 2 +-
|
||
|
.../servers/plugins/replication/repl_shared.h | 2 +
|
||
|
ldap/servers/plugins/retrocl/retrocl.c | 1 -
|
||
|
.../slapd/back-ldbm/db-bdb/bdb_config.c | 79 ++++++
|
||
|
.../slapd/back-ldbm/db-bdb/bdb_layer.c | 258 ++++++++++++------
|
||
|
.../slapd/back-ldbm/db-bdb/bdb_layer.h | 4 +-
|
||
|
ldap/servers/slapd/back-ldbm/init.c | 2 +
|
||
|
ldap/servers/slapd/back-ldbm/ldbm_config.h | 1 +
|
||
|
.../servers/slapd/back-ldbm/proto-back-ldbm.h | 1 +
|
||
|
ldap/servers/slapd/filtercmp.c | 5 +-
|
||
|
ldap/servers/slapd/pblock.c | 17 +-
|
||
|
ldap/servers/slapd/slap.h | 2 +
|
||
|
ldap/servers/slapd/slapi-private.h | 1 +
|
||
|
ldap/servers/slapd/task.c | 102 ++++++-
|
||
|
src/cockpit/389-console/src/database.jsx | 1 +
|
||
|
.../src/lib/database/databaseConfig.jsx | 16 +-
|
||
|
src/lib389/lib389/_constants.py | 1 +
|
||
|
src/lib389/lib389/backend.py | 1 +
|
||
|
src/lib389/lib389/cli_conf/backend.py | 24 +-
|
||
|
src/lib389/lib389/cli_conf/replication.py | 3 +
|
||
|
src/lib389/lib389/tasks.py | 14 +-
|
||
|
28 files changed, 689 insertions(+), 110 deletions(-)
|
||
|
create mode 100644 dirsrvtests/tests/suites/config/compact_test.py
|
||
|
|
||
|
diff --git a/dirsrvtests/tests/suites/config/compact_test.py b/dirsrvtests/tests/suites/config/compact_test.py
|
||
|
new file mode 100644
|
||
|
index 000000000..1f1c097e4
|
||
|
--- /dev/null
|
||
|
+++ b/dirsrvtests/tests/suites/config/compact_test.py
|
||
|
@@ -0,0 +1,81 @@
|
||
|
+import logging
|
||
|
+import pytest
|
||
|
+import os
|
||
|
+import time
|
||
|
+from lib389.tasks import DBCompactTask
|
||
|
+from lib389.backend import DatabaseConfig
|
||
|
+from lib389.replica import Changelog5
|
||
|
+from lib389.topologies import topology_m1 as topo
|
||
|
+
|
||
|
+log = logging.getLogger(__name__)
|
||
|
+
|
||
|
+
|
||
|
+def test_compact_db_task(topo):
|
||
|
+ """Specify a test case purpose or name here
|
||
|
+
|
||
|
+ :id: 1b3222ef-a336-4259-be21-6a52f76e1859
|
||
|
+ :setup: Standalone Instance
|
||
|
+ :steps:
|
||
|
+ 1. Create task
|
||
|
+ 2. Check task was successful
|
||
|
+ 3. Check errors log to show task was run
|
||
|
+ 3. Create task just for replication
|
||
|
+ :expectedresults:
|
||
|
+ 1. Success
|
||
|
+ 2. Success
|
||
|
+ 3. Success
|
||
|
+ 4. Success
|
||
|
+ """
|
||
|
+ inst = topo.ms["supplier1"]
|
||
|
+
|
||
|
+ task = DBCompactTask(inst)
|
||
|
+ task.create()
|
||
|
+ task.wait()
|
||
|
+ assert task.get_exit_code() == 0
|
||
|
+
|
||
|
+ # Check errors log to make sure task actually compacted db
|
||
|
+ assert inst.searchErrorsLog("Compacting databases")
|
||
|
+ inst.deleteErrorLogs(restart=False)
|
||
|
+
|
||
|
+
|
||
|
+def test_compaction_interval_and_time(topo):
|
||
|
+ """Specify a test case purpose or name here
|
||
|
+
|
||
|
+ :id: f361bee9-d7e7-4569-9255-d7b60dd9d92e
|
||
|
+ :setup: Supplier Instance
|
||
|
+ :steps:
|
||
|
+ 1. Configure compact interval and time for database and changelog
|
||
|
+ 2. Check compaction occurs as expected
|
||
|
+ :expectedresults:
|
||
|
+ 1. Success
|
||
|
+ 2. Success
|
||
|
+ """
|
||
|
+
|
||
|
+ inst = topo.ms["supplier1"]
|
||
|
+
|
||
|
+ # Configure DB compaction
|
||
|
+ config = DatabaseConfig(inst)
|
||
|
+ config.set([('nsslapd-db-compactdb-interval', '2'), ('nsslapd-db-compactdb-time', '00:01')])
|
||
|
+
|
||
|
+ # Configure changelog compaction
|
||
|
+ cl5 = Changelog5(inst)
|
||
|
+ cl5.replace_many(
|
||
|
+ ('nsslapd-changelogcompactdb-interval', '2'),
|
||
|
+ ('nsslapd-changelogcompactdb-time', '00:01'),
|
||
|
+ ('nsslapd-changelogtrim-interval', '2')
|
||
|
+ )
|
||
|
+ inst.deleteErrorLogs()
|
||
|
+
|
||
|
+ # Check is compaction occurred
|
||
|
+ time.sleep(6)
|
||
|
+ assert inst.searchErrorsLog("Compacting databases")
|
||
|
+ assert inst.searchErrorsLog("compacting replication changelogs")
|
||
|
+ inst.deleteErrorLogs(restart=False)
|
||
|
+
|
||
|
+
|
||
|
+if __name__ == '__main__':
|
||
|
+ # Run isolated
|
||
|
+ # -s for DEBUG mode
|
||
|
+ CURRENT_FILE = os.path.realpath(__file__)
|
||
|
+ pytest.main(["-s", CURRENT_FILE])
|
||
|
+
|
||
|
diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
|
||
|
index 9e9a26c21..0c73e5114 100644
|
||
|
--- a/ldap/schema/01core389.ldif
|
||
|
+++ b/ldap/schema/01core389.ldif
|
||
|
@@ -285,6 +285,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2310 NAME 'nsds5ReplicaFlowControlWindow
|
||
|
attributeTypes: ( 2.16.840.1.113730.3.1.2311 NAME 'nsds5ReplicaFlowControlPause' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
|
||
|
attributeTypes: ( 2.16.840.1.113730.3.1.2313 NAME 'nsslapd-changelogtrim-interval' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
|
||
|
attributeTypes: ( 2.16.840.1.113730.3.1.2314 NAME 'nsslapd-changelogcompactdb-interval' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
|
||
|
+attributeTypes: ( 2.16.840.1.113730.3.1.2385 NAME 'nsslapd-changelogcompactdb-time' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
|
||
|
attributeTypes: ( 2.16.840.1.113730.3.1.2315 NAME 'nsDS5ReplicaWaitForAsyncResults' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
|
||
|
attributeTypes: ( 2.16.840.1.113730.3.1.2316 NAME 'nsslapd-auditfaillog-maxlogsize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
|
||
|
attributeTypes: ( 2.16.840.1.113730.3.1.2317 NAME 'nsslapd-auditfaillog-logrotationsync-enabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
|
||
|
@@ -345,5 +346,5 @@ objectClasses: ( nsEncryptionConfig-oid NAME 'nsEncryptionConfig' DESC 'Netscape
|
||
|
objectClasses: ( nsEncryptionModule-oid NAME 'nsEncryptionModule' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsSSLToken $ nsSSLPersonalityssl $ nsSSLActivation $ ServerKeyExtractFile $ ServerCertExtractFile ) X-ORIGIN 'Netscape' )
|
||
|
objectClasses: ( 2.16.840.1.113730.3.2.327 NAME 'rootDNPluginConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( rootdn-open-time $ rootdn-close-time $ rootdn-days-allowed $ rootdn-allow-host $ rootdn-deny-host $ rootdn-allow-ip $ rootdn-deny-ip ) X-ORIGIN 'Netscape' )
|
||
|
objectClasses: ( 2.16.840.1.113730.3.2.328 NAME 'nsSchemaPolicy' DESC 'Netscape defined objectclass' SUP top MAY ( cn $ schemaUpdateObjectclassAccept $ schemaUpdateObjectclassReject $ schemaUpdateAttributeAccept $ schemaUpdateAttributeReject) X-ORIGIN 'Netscape Directory Server' )
|
||
|
-objectClasses: ( 2.16.840.1.113730.3.2.332 NAME 'nsChangelogConfig' DESC 'Configuration of the changelog5 object' SUP top MUST ( cn $ nsslapd-changelogdir ) MAY ( nsslapd-changelogmaxage $ nsslapd-changelogtrim-interval $ nsslapd-changelogmaxentries $ nsslapd-changelogsuffix $ nsslapd-changelogcompactdb-interval $ nsslapd-encryptionalgorithm $ nsSymmetricKey ) X-ORIGIN '389 Directory Server' )
|
||
|
+objectClasses: ( 2.16.840.1.113730.3.2.332 NAME 'nsChangelogConfig' DESC 'Configuration of the changelog5 object' SUP top MUST ( cn $ nsslapd-changelogdir ) MAY ( nsslapd-changelogmaxage $ nsslapd-changelogtrim-interval $ nsslapd-changelogmaxentries $ nsslapd-changelogsuffix $ nsslapd-changelogcompactdb-interval $ nsslapd-changelogcompactdb-time $ nsslapd-encryptionalgorithm $ nsSymmetricKey ) X-ORIGIN '389 Directory Server' )
|
||
|
objectClasses: ( 2.16.840.1.113730.3.2.337 NAME 'rewriterEntry' DESC '' SUP top MUST ( nsslapd-libPath ) MAY ( cn $ nsslapd-filterrewriter $ nsslapd-returnedAttrRewriter ) X-ORIGIN '389 Directory Server' )
|
||
|
diff --git a/ldap/servers/plugins/replication/cl5.h b/ldap/servers/plugins/replication/cl5.h
|
||
|
index 2af57e369..99ea1c6a2 100644
|
||
|
--- a/ldap/servers/plugins/replication/cl5.h
|
||
|
+++ b/ldap/servers/plugins/replication/cl5.h
|
||
|
@@ -29,6 +29,7 @@ typedef struct changelog5Config
|
||
|
char *symmetricKey;
|
||
|
long compactInterval;
|
||
|
long trimInterval;
|
||
|
+ char *compactTime;
|
||
|
} changelog5Config;
|
||
|
|
||
|
/* initializes changelog*/
|
||
|
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
|
||
|
index 403a6a666..75a2f46f5 100644
|
||
|
--- a/ldap/servers/plugins/replication/cl5_api.c
|
||
|
+++ b/ldap/servers/plugins/replication/cl5_api.c
|
||
|
@@ -158,6 +158,7 @@ typedef struct cl5trim
|
||
|
time_t maxAge; /* maximum entry age in seconds */
|
||
|
int maxEntries; /* maximum number of entries across all changelog files */
|
||
|
int compactInterval; /* interval to compact changelog db */
|
||
|
+ char *compactTime; /* time to compact changelog db */
|
||
|
int trimInterval; /* trimming interval */
|
||
|
PRLock *lock; /* controls access to trimming configuration */
|
||
|
} CL5Trim;
|
||
|
@@ -184,6 +185,7 @@ typedef struct cl5desc
|
||
|
PRLock *clLock; /* Lock associated to clVar, used to notify threads on close */
|
||
|
PRCondVar *clCvar; /* Condition Variable used to notify threads on close */
|
||
|
void *clcrypt_handle; /* for cl encryption */
|
||
|
+ char *compact_time; /* Time to execute changelog compaction */
|
||
|
} CL5Desc;
|
||
|
|
||
|
typedef void (*VFP)(void *);
|
||
|
@@ -1025,7 +1027,7 @@ cl5GetState()
|
||
|
CL5_BAD_STATE if changelog is not open
|
||
|
*/
|
||
|
int
|
||
|
-cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, int trimInterval)
|
||
|
+cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, char *compactTime, int trimInterval)
|
||
|
{
|
||
|
if (s_cl5Desc.dbState == CL5_STATE_NONE) {
|
||
|
slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
|
||
|
@@ -1061,6 +1063,10 @@ cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, int t
|
||
|
s_cl5Desc.dbTrim.compactInterval = compactInterval;
|
||
|
}
|
||
|
|
||
|
+ if (strcmp(compactTime, CL5_STR_IGNORE) != 0) {
|
||
|
+ s_cl5Desc.dbTrim.compactTime = slapi_ch_strdup(compactTime);
|
||
|
+ }
|
||
|
+
|
||
|
if (trimInterval != CL5_NUM_IGNORE) {
|
||
|
s_cl5Desc.dbTrim.trimInterval = trimInterval;
|
||
|
}
|
||
|
@@ -3077,16 +3083,48 @@ _cl5TrimCleanup(void)
|
||
|
{
|
||
|
if (s_cl5Desc.dbTrim.lock)
|
||
|
PR_DestroyLock(s_cl5Desc.dbTrim.lock);
|
||
|
+ slapi_ch_free_string(&s_cl5Desc.dbTrim.compactTime);
|
||
|
|
||
|
memset(&s_cl5Desc.dbTrim, 0, sizeof(s_cl5Desc.dbTrim));
|
||
|
}
|
||
|
|
||
|
+static time_t
|
||
|
+_cl5_get_tod_expiration(char *expire_time)
|
||
|
+{
|
||
|
+ time_t start_time, todays_elapsed_time, now = time(NULL);
|
||
|
+ struct tm *tm_struct = localtime(&now);
|
||
|
+ char hour_str[3] = {0};
|
||
|
+ char min_str[3] = {0};
|
||
|
+ char *s = expire_time;
|
||
|
+ char *endp = NULL;
|
||
|
+ int32_t hour, min, expiring_time;
|
||
|
+
|
||
|
+ /* Get today's start time */
|
||
|
+ todays_elapsed_time = (tm_struct->tm_hour * 3600) + (tm_struct->tm_min * 60) + (tm_struct->tm_sec);
|
||
|
+ start_time = slapi_current_utc_time() - todays_elapsed_time;
|
||
|
+
|
||
|
+ /* Get the hour and minute and calculate the expiring time. The time was
|
||
|
+ * already validated in bdb_config.c: HH:MM */
|
||
|
+ hour_str[0] = *s++;
|
||
|
+ hour_str[1] = *s++;
|
||
|
+ s++; /* skip colon */
|
||
|
+ min_str[0] = *s++;
|
||
|
+ min_str[1] = *s++;
|
||
|
+ hour = strtoll(hour_str, &endp, 10);
|
||
|
+ min = strtoll(min_str, &endp, 10);
|
||
|
+ expiring_time = (hour * 60 * 60) + (min * 60);
|
||
|
+
|
||
|
+ return start_time + expiring_time;
|
||
|
+}
|
||
|
+
|
||
|
static int
|
||
|
_cl5TrimMain(void *param __attribute__((unused)))
|
||
|
{
|
||
|
time_t timePrev = slapi_current_utc_time();
|
||
|
time_t timeCompactPrev = slapi_current_utc_time();
|
||
|
time_t timeNow;
|
||
|
+ PRBool compacting = PR_FALSE;
|
||
|
+ int32_t compactdb_time = 0;
|
||
|
|
||
|
PR_AtomicIncrement(&s_cl5Desc.threadCount);
|
||
|
|
||
|
@@ -3097,11 +3135,26 @@ _cl5TrimMain(void *param __attribute__((unused)))
|
||
|
timePrev = timeNow;
|
||
|
_cl5DoTrimming();
|
||
|
}
|
||
|
+
|
||
|
+ if (!compacting) {
|
||
|
+ /* Once we know we want to compact we need to stop refreshing the
|
||
|
+ * TOD expiration. Otherwise if the compact time is close to
|
||
|
+ * midnight we could roll over past midnight during the checkpoint
|
||
|
+ * sleep interval, and we'd never actually compact the databases.
|
||
|
+ * We also need to get this value before the sleep.
|
||
|
+ */
|
||
|
+ compactdb_time = _cl5_get_tod_expiration(s_cl5Desc.dbTrim.compactTime);
|
||
|
+ }
|
||
|
if ((s_cl5Desc.dbTrim.compactInterval > 0) &&
|
||
|
- (timeNow - timeCompactPrev >= s_cl5Desc.dbTrim.compactInterval)) {
|
||
|
- /* time to trim */
|
||
|
- timeCompactPrev = timeNow;
|
||
|
- _cl5CompactDBs();
|
||
|
+ (timeNow - timeCompactPrev >= s_cl5Desc.dbTrim.compactInterval))
|
||
|
+ {
|
||
|
+ compacting = PR_TRUE;
|
||
|
+ if (slapi_current_utc_time() > compactdb_time) {
|
||
|
+ /* time to trim */
|
||
|
+ timeCompactPrev = timeNow;
|
||
|
+ _cl5CompactDBs();
|
||
|
+ compacting = PR_FALSE;
|
||
|
+ }
|
||
|
}
|
||
|
if (NULL == s_cl5Desc.clLock) {
|
||
|
/* most likely, emergency */
|
||
|
@@ -3215,6 +3268,10 @@ _cl5CompactDBs(void)
|
||
|
rc, db_strerror(rc));
|
||
|
goto bail;
|
||
|
}
|
||
|
+
|
||
|
+
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name_cl,
|
||
|
+ "_cl5CompactDBs - compacting replication changelogs...\n");
|
||
|
for (fileObj = objset_first_obj(s_cl5Desc.dbFiles);
|
||
|
fileObj;
|
||
|
fileObj = objset_next_obj(s_cl5Desc.dbFiles, fileObj)) {
|
||
|
@@ -3235,6 +3292,9 @@ _cl5CompactDBs(void)
|
||
|
"_cl5CompactDBs - %s - %d pages freed\n",
|
||
|
dbFile->replName, c_data.compact_pages_free);
|
||
|
}
|
||
|
+
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name_cl,
|
||
|
+ "_cl5CompactDBs - compacting replication changelogs finished.\n");
|
||
|
bail:
|
||
|
if (fileObj) {
|
||
|
object_release(fileObj);
|
||
|
diff --git a/ldap/servers/plugins/replication/cl5_api.h b/ldap/servers/plugins/replication/cl5_api.h
|
||
|
index 302af97a0..4b0949fb3 100644
|
||
|
--- a/ldap/servers/plugins/replication/cl5_api.h
|
||
|
+++ b/ldap/servers/plugins/replication/cl5_api.h
|
||
|
@@ -236,7 +236,7 @@ int cl5GetState(void);
|
||
|
Return: CL5_SUCCESS if successful;
|
||
|
CL5_BAD_STATE if changelog has not been open
|
||
|
*/
|
||
|
-int cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, int trimInterval);
|
||
|
+int cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, char *compactTime, int trimInterval);
|
||
|
|
||
|
void cl5DestroyIterator(void *iterator);
|
||
|
|
||
|
diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
|
||
|
index 90dec4d54..e5a39c9c1 100644
|
||
|
--- a/ldap/servers/plugins/replication/cl5_clcache.c
|
||
|
+++ b/ldap/servers/plugins/replication/cl5_clcache.c
|
||
|
@@ -452,9 +452,6 @@ 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) {
|
||
|
diff --git a/ldap/servers/plugins/replication/cl5_config.c b/ldap/servers/plugins/replication/cl5_config.c
|
||
|
index e0530bed2..b32686788 100644
|
||
|
--- a/ldap/servers/plugins/replication/cl5_config.c
|
||
|
+++ b/ldap/servers/plugins/replication/cl5_config.c
|
||
|
@@ -131,6 +131,7 @@ changelog5_config_done(changelog5Config *config)
|
||
|
/* slapi_ch_free_string accepts NULL pointer */
|
||
|
slapi_ch_free_string(&config->maxAge);
|
||
|
slapi_ch_free_string(&config->dir);
|
||
|
+ slapi_ch_free_string(&config->compactTime);
|
||
|
slapi_ch_free_string(&config->symmetricKey);
|
||
|
slapi_ch_free_string(&config->dbconfig.encryptionAlgorithm);
|
||
|
slapi_ch_free_string(&config->dbconfig.symmetricKey);
|
||
|
@@ -211,7 +212,7 @@ changelog5_config_add(Slapi_PBlock *pb __attribute__((unused)),
|
||
|
}
|
||
|
|
||
|
/* set trimming parameters */
|
||
|
- rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.trimInterval);
|
||
|
+ rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.compactTime, config.trimInterval);
|
||
|
if (rc != CL5_SUCCESS) {
|
||
|
*returncode = 1;
|
||
|
if (returntext) {
|
||
|
@@ -302,6 +303,7 @@ changelog5_config_modify(Slapi_PBlock *pb,
|
||
|
config.compactInterval = CL5_NUM_IGNORE;
|
||
|
slapi_ch_free_string(&config.maxAge);
|
||
|
config.maxAge = slapi_ch_strdup(CL5_STR_IGNORE);
|
||
|
+ config.compactTime = slapi_ch_strdup(CHANGELOGDB_COMPACT_TIME);
|
||
|
config.trimInterval = CL5_NUM_IGNORE;
|
||
|
|
||
|
slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
|
||
|
@@ -375,6 +377,55 @@ changelog5_config_modify(Slapi_PBlock *pb,
|
||
|
*returncode = LDAP_UNWILLING_TO_PERFORM;
|
||
|
goto done;
|
||
|
}
|
||
|
+ } else if (strcasecmp(config_attr, CONFIG_CHANGELOG_COMPACTTIME_ATTRIBUTE) == 0) {
|
||
|
+ if (config_attr_value && config_attr_value[0] != '\0') {
|
||
|
+ char *val = slapi_ch_strdup(config_attr_value);
|
||
|
+ char *endp = NULL;
|
||
|
+ char *hour_str = NULL;
|
||
|
+ char *min_str = NULL;
|
||
|
+ int32_t hour, min;
|
||
|
+ errno = 0;
|
||
|
+
|
||
|
+ slapi_ch_free_string(&config.compactTime);
|
||
|
+
|
||
|
+ if (strstr(val, ":")) {
|
||
|
+ /* Get the hour and minute */
|
||
|
+ hour_str = ldap_utf8strtok_r(val, ":", &min_str);
|
||
|
+ /* Validate hour */
|
||
|
+ hour = strtoll(hour_str, &endp, 10);
|
||
|
+ if (*endp != '\0' || errno == ERANGE || hour < 0 || hour > 23 || strlen(hour_str) != 2) {
|
||
|
+ slapi_create_errormsg(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
|
||
|
+ "Invalid hour set (%s), must be a two digit number between 00 and 23",
|
||
|
+ hour_str);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "changelog5_extract_config",
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59. "
|
||
|
+ "Using default of 23:59\n", hour_str);
|
||
|
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ /* Validate minute */
|
||
|
+ min = strtoll(min_str, &endp, 10);
|
||
|
+ if (*endp != '\0' || errno == ERANGE || min < 0 || min > 59 || strlen(min_str) != 2) {
|
||
|
+ slapi_create_errormsg(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59",
|
||
|
+ hour_str);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "changelog5_extract_config",
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59. "
|
||
|
+ "Using default of 23:59\n", min_str);
|
||
|
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ /* Wrong format */
|
||
|
+ slapi_create_errormsg(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
|
||
|
+ "Invalid setting (%s), must have a time format of HH:MM", val);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "changelog5_extract_config",
|
||
|
+ "Invalid setting (%s), must have a time format of HH:MM\n", val);
|
||
|
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ config.compactTime = slapi_ch_strdup(config_attr_value);
|
||
|
+ }
|
||
|
} else if (strcasecmp(config_attr, CONFIG_CHANGELOG_TRIM_ATTRIBUTE) == 0) {
|
||
|
if (slapi_is_duration_valid(config_attr_value)) {
|
||
|
config.trimInterval = (long)slapi_parse_duration(config_attr_value);
|
||
|
@@ -419,6 +470,11 @@ changelog5_config_modify(Slapi_PBlock *pb,
|
||
|
if (originalConfig->maxAge)
|
||
|
config.maxAge = slapi_ch_strdup(originalConfig->maxAge);
|
||
|
}
|
||
|
+ if (strcmp(config.compactTime, CL5_STR_IGNORE) == 0) {
|
||
|
+ slapi_ch_free_string(&config.compactTime);
|
||
|
+ if (originalConfig->compactTime)
|
||
|
+ config.compactTime = slapi_ch_strdup(originalConfig->compactTime);
|
||
|
+ }
|
||
|
|
||
|
/* attempt to change chagelog dir */
|
||
|
if (config.dir) {
|
||
|
@@ -519,7 +575,7 @@ changelog5_config_modify(Slapi_PBlock *pb,
|
||
|
if (config.maxEntries != CL5_NUM_IGNORE ||
|
||
|
config.trimInterval != CL5_NUM_IGNORE ||
|
||
|
strcmp(config.maxAge, CL5_STR_IGNORE) != 0) {
|
||
|
- rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.trimInterval);
|
||
|
+ rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.compactTime, config.trimInterval);
|
||
|
if (rc != CL5_SUCCESS) {
|
||
|
*returncode = 1;
|
||
|
if (returntext) {
|
||
|
@@ -689,6 +745,7 @@ changelog5_extract_config(Slapi_Entry *entry, changelog5Config *config)
|
||
|
{
|
||
|
const char *arg;
|
||
|
char *max_age = NULL;
|
||
|
+ char *val = NULL;
|
||
|
|
||
|
memset(config, 0, sizeof(*config));
|
||
|
config->dir = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DIR_ATTRIBUTE);
|
||
|
@@ -711,6 +768,47 @@ changelog5_extract_config(Slapi_Entry *entry, changelog5Config *config)
|
||
|
config->compactInterval = CHANGELOGDB_COMPACT_INTERVAL;
|
||
|
}
|
||
|
|
||
|
+ arg = slapi_entry_attr_get_ref(entry, CONFIG_CHANGELOG_COMPACTTIME_ATTRIBUTE);
|
||
|
+ if (arg) {
|
||
|
+ char *endp = NULL;
|
||
|
+ char *hour_str = NULL;
|
||
|
+ char *min_str = NULL;
|
||
|
+ int32_t hour, min;
|
||
|
+ errno = 0;
|
||
|
+
|
||
|
+ val = slapi_ch_strdup((char *)arg);
|
||
|
+ if (strstr(val, ":")) {
|
||
|
+ /* Get the hour and minute */
|
||
|
+ hour_str = ldap_utf8strtok_r(val, ":", &min_str);
|
||
|
+ /* Validate hour */
|
||
|
+ hour = strtoll(hour_str, &endp, 10);
|
||
|
+ if (*endp != '\0' || errno == ERANGE || hour < 0 || hour > 23 || strlen(hour_str) != 2) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "changelog5_extract_config",
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59. "
|
||
|
+ "Using default of 23:59\n", hour_str);
|
||
|
+ goto set_default;
|
||
|
+ }
|
||
|
+ /* Validate minute */
|
||
|
+ min = strtoll(min_str, &endp, 10);
|
||
|
+ if (*endp != '\0' || errno == ERANGE || min < 0 || min > 59 || strlen(min_str) != 2) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "changelog5_extract_config",
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59. "
|
||
|
+ "Using default of 23:59\n", min_str);
|
||
|
+ goto set_default;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ /* Wrong format */
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "changelog5_extract_config",
|
||
|
+ "Invalid setting (%s), must have a time format of HH:MM\n", val);
|
||
|
+ goto set_default;
|
||
|
+ }
|
||
|
+ config->compactTime = slapi_ch_strdup(arg);
|
||
|
+ } else {
|
||
|
+ set_default:
|
||
|
+ config->compactTime = slapi_ch_strdup(CHANGELOGDB_COMPACT_TIME);
|
||
|
+ }
|
||
|
+ slapi_ch_free_string(&val);
|
||
|
+
|
||
|
arg = slapi_entry_attr_get_ref(entry, CONFIG_CHANGELOG_TRIM_ATTRIBUTE);
|
||
|
if (arg) {
|
||
|
if (slapi_is_duration_valid(arg)) {
|
||
|
diff --git a/ldap/servers/plugins/replication/cl5_init.c b/ldap/servers/plugins/replication/cl5_init.c
|
||
|
index 112c4ece4..251859714 100644
|
||
|
--- a/ldap/servers/plugins/replication/cl5_init.c
|
||
|
+++ b/ldap/servers/plugins/replication/cl5_init.c
|
||
|
@@ -57,7 +57,7 @@ changelog5_init()
|
||
|
}
|
||
|
|
||
|
/* set trimming parameters */
|
||
|
- rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.trimInterval);
|
||
|
+ rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.compactTime, config.trimInterval);
|
||
|
if (rc != CL5_SUCCESS) {
|
||
|
slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
|
||
|
"changelog5_init: failed to configure changelog trimming\n");
|
||
|
diff --git a/ldap/servers/plugins/replication/repl_shared.h b/ldap/servers/plugins/replication/repl_shared.h
|
||
|
index b1ed86934..6708e12f7 100644
|
||
|
--- a/ldap/servers/plugins/replication/repl_shared.h
|
||
|
+++ b/ldap/servers/plugins/replication/repl_shared.h
|
||
|
@@ -26,11 +26,13 @@
|
||
|
|
||
|
#define CHANGELOGDB_TRIM_INTERVAL 300 /* 5 minutes */
|
||
|
#define CHANGELOGDB_COMPACT_INTERVAL 2592000 /* 30 days */
|
||
|
+#define CHANGELOGDB_COMPACT_TIME "23:55" /* 30 days */
|
||
|
|
||
|
#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir"
|
||
|
#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries"
|
||
|
#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
|
||
|
#define CONFIG_CHANGELOG_COMPACTDB_ATTRIBUTE "nsslapd-changelogcompactdb-interval"
|
||
|
+#define CONFIG_CHANGELOG_COMPACTTIME_ATTRIBUTE "nsslapd-changelogcompactdb-time"
|
||
|
#define CONFIG_CHANGELOG_TRIM_ATTRIBUTE "nsslapd-changelogtrim-interval"
|
||
|
/* Changelog Internal Configuration Parameters -> Changelog Cache related */
|
||
|
#define CONFIG_CHANGELOG_ENCRYPTION_ALGORITHM "nsslapd-encryptionalgorithm"
|
||
|
diff --git a/ldap/servers/plugins/retrocl/retrocl.c b/ldap/servers/plugins/retrocl/retrocl.c
|
||
|
index 2a620301c..f73c81528 100644
|
||
|
--- a/ldap/servers/plugins/retrocl/retrocl.c
|
||
|
+++ b/ldap/servers/plugins/retrocl/retrocl.c
|
||
|
@@ -400,7 +400,6 @@ retrocl_start(Slapi_PBlock *pb)
|
||
|
|
||
|
for (size_t i = 0; i < num_vals; i++) {
|
||
|
char *value = values[i];
|
||
|
- size_t length = strlen(value);
|
||
|
|
||
|
char *pos = strchr(value, ':');
|
||
|
if (pos == NULL) {
|
||
|
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 167644943..4261c6ce2 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_config.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_config.c
|
||
|
@@ -678,6 +678,84 @@ bdb_config_db_compactdb_interval_set(void *arg,
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
+static void *
|
||
|
+bdb_config_db_compactdb_time_get(void *arg)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+ return (void *)slapi_ch_strdup(BDB_CONFIG(li)->bdb_compactdb_time);
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+bdb_config_db_compactdb_time_set(void *arg,
|
||
|
+ void *value,
|
||
|
+ char *errorbuf __attribute__((unused)),
|
||
|
+ int phase __attribute__((unused)),
|
||
|
+ int apply)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||
|
+ char *val = slapi_ch_strdup((char *)value);
|
||
|
+ char *endp = NULL;
|
||
|
+ char *hour_str = NULL;
|
||
|
+ char *min_str = NULL;
|
||
|
+ char *default_time = "23:59";
|
||
|
+ int32_t hour, min;
|
||
|
+ int retval = LDAP_SUCCESS;
|
||
|
+ errno = 0;
|
||
|
+
|
||
|
+ if (strstr(val, ":")) {
|
||
|
+ /* Get the hour and minute */
|
||
|
+ hour_str = ldap_utf8strtok_r(val, ":", &min_str);
|
||
|
+
|
||
|
+ /* Validate hour */
|
||
|
+ hour = strtoll(hour_str, &endp, 10);
|
||
|
+ if (*endp != '\0' || errno == ERANGE || hour < 0 || hour > 23 || strlen(hour_str) != 2) {
|
||
|
+ slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
|
||
|
+ "Invalid hour set (%s), must be a two digit number between 00 and 23",
|
||
|
+ hour_str);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_config_db_compactdb_interval_set",
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59. "
|
||
|
+ "Using default of 23:59\n", hour_str);
|
||
|
+ retval = LDAP_OPERATIONS_ERROR;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Validate minute */
|
||
|
+ min = strtoll(min_str, &endp, 10);
|
||
|
+ if (*endp != '\0' || errno == ERANGE || min < 0 || min > 59 || strlen(min_str) != 2) {
|
||
|
+ slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59",
|
||
|
+ hour_str);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_config_db_compactdb_interval_set",
|
||
|
+ "Invalid minute set (%s), must be a two digit number between 00 and 59. "
|
||
|
+ "Using default of 23:59\n", min_str);
|
||
|
+ retval = LDAP_OPERATIONS_ERROR;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ /* Wrong format */
|
||
|
+ slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
|
||
|
+ "Invalid setting (%s), must have a time format of HH:MM", val);
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_config_db_compactdb_interval_set",
|
||
|
+ "Invalid setting (%s), must have a time format of HH:MM\n", val);
|
||
|
+ retval = LDAP_OPERATIONS_ERROR;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+done:
|
||
|
+ if (apply) {
|
||
|
+ slapi_ch_free((void **)&(BDB_CONFIG(li)->bdb_compactdb_time));
|
||
|
+ if (retval) {
|
||
|
+ /* Something went wrong, use the default */
|
||
|
+ BDB_CONFIG(li)->bdb_compactdb_time = slapi_ch_strdup(default_time);
|
||
|
+ } else {
|
||
|
+ BDB_CONFIG(li)->bdb_compactdb_time = slapi_ch_strdup((char *)value);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ slapi_ch_free_string(&val);
|
||
|
+
|
||
|
+ return retval;
|
||
|
+}
|
||
|
+
|
||
|
static void *
|
||
|
bdb_config_db_page_size_get(void *arg)
|
||
|
{
|
||
|
@@ -1473,6 +1551,7 @@ static config_info bdb_config_param[] = {
|
||
|
{CONFIG_DB_TRANSACTION_WAIT, CONFIG_TYPE_ONOFF, "off", &bdb_config_db_transaction_wait_get, &bdb_config_db_transaction_wait_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
{CONFIG_DB_CHECKPOINT_INTERVAL, CONFIG_TYPE_INT, "60", &bdb_config_db_checkpoint_interval_get, &bdb_config_db_checkpoint_interval_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
{CONFIG_DB_COMPACTDB_INTERVAL, CONFIG_TYPE_INT, "2592000" /*30days*/, &bdb_config_db_compactdb_interval_get, &bdb_config_db_compactdb_interval_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
+ {CONFIG_DB_COMPACTDB_TIME, CONFIG_TYPE_STRING, "23:59", &bdb_config_db_compactdb_time_get, &bdb_config_db_compactdb_time_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
{CONFIG_DB_TRANSACTION_BATCH, CONFIG_TYPE_INT, "0", &bdb_get_batch_transactions, &bdb_set_batch_transactions, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
{CONFIG_DB_TRANSACTION_BATCH_MIN_SLEEP, CONFIG_TYPE_INT, "50", &bdb_get_batch_txn_min_sleep, &bdb_set_batch_txn_min_sleep, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
{CONFIG_DB_TRANSACTION_BATCH_MAX_SLEEP, CONFIG_TYPE_INT, "50", &bdb_get_batch_txn_max_sleep, &bdb_set_batch_txn_max_sleep, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||
|
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 2f25f67a2..ec1976d38 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||
|
@@ -2126,6 +2126,7 @@ bdb_post_close(struct ldbminfo *li, int dbmode)
|
||
|
*/
|
||
|
slapi_ch_free_string(&conf->bdb_dbhome_directory);
|
||
|
slapi_ch_free_string(&conf->bdb_home_directory);
|
||
|
+ slapi_ch_free_string(&conf->bdb_compactdb_time);
|
||
|
}
|
||
|
|
||
|
return return_value;
|
||
|
@@ -3644,6 +3645,39 @@ log_flush_threadmain(void *param)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * This refreshes the TOD expiration. So live changes to the configuration
|
||
|
+ * will take effect immediately.
|
||
|
+ */
|
||
|
+static time_t
|
||
|
+bdb_get_tod_expiration(char *expire_time)
|
||
|
+{
|
||
|
+ time_t start_time, todays_elapsed_time, now = time(NULL);
|
||
|
+ struct tm *tm_struct = localtime(&now);
|
||
|
+ char hour_str[3] = {0};
|
||
|
+ char min_str[3] = {0};
|
||
|
+ char *s = expire_time;
|
||
|
+ char *endp = NULL;
|
||
|
+ int32_t hour, min, expiring_time;
|
||
|
+
|
||
|
+ /* Get today's start time */
|
||
|
+ todays_elapsed_time = (tm_struct->tm_hour * 3600) + (tm_struct->tm_min * 60) + (tm_struct->tm_sec);
|
||
|
+ start_time = slapi_current_utc_time() - todays_elapsed_time;
|
||
|
+
|
||
|
+ /* Get the hour and minute and calculate the expiring time. The time was
|
||
|
+ * already validated in bdb_config.c: HH:MM */
|
||
|
+ hour_str[0] = *s++;
|
||
|
+ hour_str[1] = *s++;
|
||
|
+ s++; /* skip colon */
|
||
|
+ min_str[0] = *s++;
|
||
|
+ min_str[1] = *s++;
|
||
|
+ hour = strtoll(hour_str, &endp, 10);
|
||
|
+ min = strtoll(min_str, &endp, 10);
|
||
|
+ expiring_time = (hour * 60 * 60) + (min * 60);
|
||
|
+
|
||
|
+ return start_time + expiring_time;
|
||
|
+}
|
||
|
+
|
||
|
/*
|
||
|
* create a thread for checkpoint_threadmain
|
||
|
*/
|
||
|
@@ -3685,7 +3719,9 @@ checkpoint_threadmain(void *param)
|
||
|
time_t checkpoint_interval_update = 0;
|
||
|
time_t compactdb_interval = 0;
|
||
|
time_t checkpoint_interval = 0;
|
||
|
- back_txn txn;
|
||
|
+ int32_t compactdb_time = 0;
|
||
|
+ PRBool compacting = PR_FALSE;
|
||
|
+
|
||
|
|
||
|
PR_ASSERT(NULL != param);
|
||
|
li = (struct ldbminfo *)param;
|
||
|
@@ -3724,22 +3760,35 @@ checkpoint_threadmain(void *param)
|
||
|
slapi_timespec_expire_at(checkpoint_interval, &checkpoint_expire);
|
||
|
|
||
|
while (!BDB_CONFIG(li)->bdb_stop_threads) {
|
||
|
- /* sleep for a while */
|
||
|
- /* why aren't we sleeping exactly the right amount of time ? */
|
||
|
- /* answer---because the interval might be changed after the server
|
||
|
- * starts up */
|
||
|
+ PR_Lock(li->li_config_mutex);
|
||
|
+ checkpoint_interval_update = (time_t)BDB_CONFIG(li)->bdb_checkpoint_interval;
|
||
|
+ compactdb_interval_update = (time_t)BDB_CONFIG(li)->bdb_compactdb_interval;
|
||
|
+ if (!compacting) {
|
||
|
+ /* Once we know we want to compact we need to stop refreshing the
|
||
|
+ * TOD expiration. Otherwise if the compact time is close to
|
||
|
+ * midnight we could roll over past midnight during the checkpoint
|
||
|
+ * sleep interval, and we'd never actually compact the databases.
|
||
|
+ * We also need to get this value before the sleep.
|
||
|
+ */
|
||
|
+ compactdb_time = bdb_get_tod_expiration((char *)BDB_CONFIG(li)->bdb_compactdb_time);
|
||
|
+ }
|
||
|
+ PR_Unlock(li->li_config_mutex);
|
||
|
+
|
||
|
+ if (compactdb_interval_update != compactdb_interval) {
|
||
|
+ /* Compact interval was changed, so reset the timer */
|
||
|
+ slapi_timespec_expire_at(compactdb_interval_update, &compactdb_expire);
|
||
|
+ }
|
||
|
|
||
|
+ /* Sleep for a while ...
|
||
|
+ * Why aren't we sleeping exactly the right amount of time ?
|
||
|
+ * Answer---because the interval might be changed after the server
|
||
|
+ * starts up */
|
||
|
DS_Sleep(interval);
|
||
|
|
||
|
if (0 == BDB_CONFIG(li)->bdb_enable_transactions) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
- PR_Lock(li->li_config_mutex);
|
||
|
- checkpoint_interval_update = (time_t)BDB_CONFIG(li)->bdb_checkpoint_interval;
|
||
|
- compactdb_interval_update = (time_t)BDB_CONFIG(li)->bdb_compactdb_interval;
|
||
|
- PR_Unlock(li->li_config_mutex);
|
||
|
-
|
||
|
/* If the checkpoint has been updated OR we have expired */
|
||
|
if (checkpoint_interval != checkpoint_interval_update ||
|
||
|
slapi_timespec_expire_check(&checkpoint_expire) == TIMER_EXPIRED) {
|
||
|
@@ -3807,94 +3856,37 @@ checkpoint_threadmain(void *param)
|
||
|
|
||
|
/*
|
||
|
* Remember that if compactdb_interval is 0, timer_expired can
|
||
|
- * never occur unless the value in compctdb_interval changes.
|
||
|
+ * never occur unless the value in compactdb_interval changes.
|
||
|
*
|
||
|
- * this could have been a bug infact, where compactdb_interval
|
||
|
+ * this could have been a bug in fact, where compactdb_interval
|
||
|
* was 0, if you change while running it would never take effect ....
|
||
|
*/
|
||
|
- if (compactdb_interval_update != compactdb_interval ||
|
||
|
- slapi_timespec_expire_check(&compactdb_expire) == TIMER_EXPIRED) {
|
||
|
- int rc = 0;
|
||
|
- Object *inst_obj;
|
||
|
- ldbm_instance *inst;
|
||
|
- DB *db = NULL;
|
||
|
- DB_COMPACT c_data = {0};
|
||
|
-
|
||
|
- for (inst_obj = objset_first_obj(li->li_instance_set);
|
||
|
- inst_obj;
|
||
|
- inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
|
||
|
- inst = (ldbm_instance *)object_get_data(inst_obj);
|
||
|
- rc = dblayer_get_id2entry(inst->inst_be, &db);
|
||
|
- if (!db || rc) {
|
||
|
- continue;
|
||
|
- }
|
||
|
- slapi_log_err(SLAPI_LOG_NOTICE, "checkpoint_threadmain", "Compacting DB start: %s\n",
|
||
|
- inst->inst_name);
|
||
|
-
|
||
|
- /*
|
||
|
- * It's possible for this to heap us after free because when we access db
|
||
|
- * *just* as the server shut's down, we don't know it. So we should probably
|
||
|
- * do something like wrapping access to the db var in a rwlock, and have "read"
|
||
|
- * to access, and take writes to change the state. This would prevent the issue.
|
||
|
- */
|
||
|
- DBTYPE type;
|
||
|
- rc = db->get_type(db, &type);
|
||
|
- if (rc) {
|
||
|
- slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain",
|
||
|
- "compactdb: failed to determine db type for %s: db error - %d %s\n",
|
||
|
- inst->inst_name, rc, db_strerror(rc));
|
||
|
- continue;
|
||
|
- }
|
||
|
+ if (slapi_timespec_expire_check(&compactdb_expire) == TIMER_EXPIRED) {
|
||
|
+ compacting = PR_TRUE;
|
||
|
+ if (slapi_current_utc_time() < compactdb_time) {
|
||
|
+ /* We have passed the interval, but we need to wait for a
|
||
|
+ * particular TOD to pass before compacting */
|
||
|
+ continue;
|
||
|
+ }
|
||
|
|
||
|
- rc = dblayer_txn_begin(inst->inst_be, NULL, &txn);
|
||
|
- if (rc) {
|
||
|
- slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain", "compactdb: transaction begin failed: %d\n", rc);
|
||
|
- break;
|
||
|
- }
|
||
|
- /*
|
||
|
- * https://docs.oracle.com/cd/E17275_01/html/api_reference/C/BDB-C_APIReference.pdf
|
||
|
- * "DB_FREELIST_ONLY
|
||
|
- * Do no page compaction, only returning pages to the filesystem that are already free and at the end
|
||
|
- * of the file. This flag must be set if the database is a Hash access method database."
|
||
|
- *
|
||
|
- */
|
||
|
+ /* Time to compact the DB's */
|
||
|
+ dblayer_force_checkpoint(li);
|
||
|
+ bdb_compact(li);
|
||
|
+ dblayer_force_checkpoint(li);
|
||
|
|
||
|
- uint32_t compact_flags = DB_FREE_SPACE;
|
||
|
- if (type == DB_HASH) {
|
||
|
- compact_flags |= DB_FREELIST_ONLY;
|
||
|
- }
|
||
|
- rc = db->compact(db, txn.back_txn_txn, NULL /*start*/, NULL /*stop*/,
|
||
|
- &c_data, compact_flags, NULL /*end*/);
|
||
|
- if (rc) {
|
||
|
- slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain",
|
||
|
- "compactdb: failed to compact %s; db error - %d %s\n",
|
||
|
- inst->inst_name, rc, db_strerror(rc));
|
||
|
- if ((rc = dblayer_txn_abort(inst->inst_be, &txn))) {
|
||
|
- slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain", "compactdb: failed to abort txn (%s) db error - %d %s\n",
|
||
|
- inst->inst_name, rc, db_strerror(rc));
|
||
|
- break;
|
||
|
- }
|
||
|
- } else {
|
||
|
- slapi_log_err(SLAPI_LOG_NOTICE, "checkpoint_threadmain",
|
||
|
- "compactdb: compact %s - %d pages freed\n",
|
||
|
- inst->inst_name, c_data.compact_pages_free);
|
||
|
- if ((rc = dblayer_txn_commit(inst->inst_be, &txn))) {
|
||
|
- slapi_log_err(SLAPI_LOG_ERR, "checkpoint_threadmain", "compactdb: failed to commit txn (%s) db error - %d %s\n",
|
||
|
- inst->inst_name, rc, db_strerror(rc));
|
||
|
- break;
|
||
|
- }
|
||
|
- }
|
||
|
- }
|
||
|
+ /* Now reset the timer and compacting flag */
|
||
|
compactdb_interval = compactdb_interval_update;
|
||
|
slapi_timespec_expire_at(compactdb_interval, &compactdb_expire);
|
||
|
+ compacting = PR_FALSE;
|
||
|
}
|
||
|
}
|
||
|
- slapi_log_err(SLAPI_LOG_TRACE, "checkpoint_threadmain", "Check point before leaving\n");
|
||
|
+ slapi_log_err(SLAPI_LOG_HOUSE, "checkpoint_threadmain", "Check point before leaving\n");
|
||
|
rval = dblayer_force_checkpoint(li);
|
||
|
+
|
||
|
error_return:
|
||
|
|
||
|
DECR_THREAD_COUNT(pEnv);
|
||
|
- slapi_log_err(SLAPI_LOG_TRACE, "checkpoint_threadmain", "Leaving checkpoint_threadmain\n");
|
||
|
+ slapi_log_err(SLAPI_LOG_HOUSE, "checkpoint_threadmain", "Leaving checkpoint_threadmain\n");
|
||
|
return rval;
|
||
|
}
|
||
|
|
||
|
@@ -6209,3 +6201,99 @@ bdb_back_ctrl(Slapi_Backend *be, int cmd, void *info)
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
+
|
||
|
+int32_t
|
||
|
+ldbm_back_compact(Slapi_Backend *be)
|
||
|
+{
|
||
|
+ struct ldbminfo *li = NULL;
|
||
|
+ int32_t rc = -1;
|
||
|
+
|
||
|
+ li = (struct ldbminfo *)be->be_database->plg_private;
|
||
|
+ dblayer_force_checkpoint(li);
|
||
|
+ rc = bdb_compact(li);
|
||
|
+ dblayer_force_checkpoint(li);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+int32_t
|
||
|
+bdb_compact(struct ldbminfo *li)
|
||
|
+{
|
||
|
+ Object *inst_obj;
|
||
|
+ ldbm_instance *inst;
|
||
|
+ DB *db = NULL;
|
||
|
+ back_txn txn = {0};
|
||
|
+ int rc = 0;
|
||
|
+ DB_COMPACT c_data = {0};
|
||
|
+
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_compact",
|
||
|
+ "Compacting databases ...\n");
|
||
|
+ for (inst_obj = objset_first_obj(li->li_instance_set);
|
||
|
+ inst_obj;
|
||
|
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj))
|
||
|
+ {
|
||
|
+ inst = (ldbm_instance *)object_get_data(inst_obj);
|
||
|
+ rc = dblayer_get_id2entry(inst->inst_be, &db);
|
||
|
+ if (!db || rc) {
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_compact", "Compacting DB start: %s\n",
|
||
|
+ inst->inst_name);
|
||
|
+
|
||
|
+ /*
|
||
|
+ * It's possible for this to heap us after free because when we access db
|
||
|
+ * *just* as the server shut's down, we don't know it. So we should probably
|
||
|
+ * do something like wrapping access to the db var in a rwlock, and have "read"
|
||
|
+ * to access, and take writes to change the state. This would prevent the issue.
|
||
|
+ */
|
||
|
+ DBTYPE type;
|
||
|
+ rc = db->get_type(db, &type);
|
||
|
+ if (rc) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_compact",
|
||
|
+ "compactdb: failed to determine db type for %s: db error - %d %s\n",
|
||
|
+ inst->inst_name, rc, db_strerror(rc));
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ rc = dblayer_txn_begin(inst->inst_be, NULL, &txn);
|
||
|
+ if (rc) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_compact", "compactdb: transaction begin failed: %d\n", rc);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ /*
|
||
|
+ * https://docs.oracle.com/cd/E17275_01/html/api_reference/C/BDB-C_APIReference.pdf
|
||
|
+ * "DB_FREELIST_ONLY
|
||
|
+ * Do no page compaction, only returning pages to the filesystem that are already free and at the end
|
||
|
+ * of the file. This flag must be set if the database is a Hash access method database."
|
||
|
+ *
|
||
|
+ */
|
||
|
+ uint32_t compact_flags = DB_FREE_SPACE;
|
||
|
+ if (type == DB_HASH) {
|
||
|
+ compact_flags |= DB_FREELIST_ONLY;
|
||
|
+ }
|
||
|
+ rc = db->compact(db, txn.back_txn_txn, NULL /*start*/, NULL /*stop*/,
|
||
|
+ &c_data, compact_flags, NULL /*end*/);
|
||
|
+ if (rc) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_compact",
|
||
|
+ "compactdb: failed to compact %s; db error - %d %s\n",
|
||
|
+ inst->inst_name, rc, db_strerror(rc));
|
||
|
+ if ((rc = dblayer_txn_abort(inst->inst_be, &txn))) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_compact", "compactdb: failed to abort txn (%s) db error - %d %s\n",
|
||
|
+ inst->inst_name, rc, db_strerror(rc));
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_compact",
|
||
|
+ "compactdb: compact %s - %d pages freed\n",
|
||
|
+ inst->inst_name, c_data.compact_pages_free);
|
||
|
+ if ((rc = dblayer_txn_commit(inst->inst_be, &txn))) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "bdb_compact", "compactdb: failed to commit txn (%s) db error - %d %s\n",
|
||
|
+ inst->inst_name, rc, db_strerror(rc));
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_compact", "Compacting databases finished.\n");
|
||
|
+
|
||
|
+ return rc;
|
||
|
+}
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.h b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.h
|
||
|
index 6bb04d21a..e3a49dbac 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.h
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.h
|
||
|
@@ -79,7 +79,8 @@ typedef struct bdb_config
|
||
|
int bdb_previous_lock_config; /* Max lock count when we last shut down--
|
||
|
* used to determine if we delete the mpool */
|
||
|
u_int32_t bdb_deadlock_policy; /* i.e. the atype to DB_ENV->lock_detect in deadlock_threadmain */
|
||
|
- int bdb_compactdb_interval; /* interval to execute compact id2entry dbs */
|
||
|
+ int32_t bdb_compactdb_interval; /* interval to execute compact id2entry dbs */
|
||
|
+ char *bdb_compactdb_time; /* time of day to execute compact id2entry dbs */
|
||
|
} bdb_config;
|
||
|
|
||
|
int bdb_init(struct ldbminfo *li, config_info *config_array);
|
||
|
@@ -96,6 +97,7 @@ int bdb_db_size(Slapi_PBlock *pb);
|
||
|
int bdb_upgradedb(Slapi_PBlock *pb);
|
||
|
int bdb_upgradednformat(Slapi_PBlock *pb);
|
||
|
int bdb_upgradeddformat(Slapi_PBlock *pb);
|
||
|
+int32_t bdb_compact(struct ldbminfo *li);
|
||
|
int bdb_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task);
|
||
|
int bdb_cleanup(struct ldbminfo *li);
|
||
|
int bdb_txn_begin(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock);
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/init.c b/ldap/servers/slapd/back-ldbm/init.c
|
||
|
index 4165c8fad..42c9bd00a 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/init.c
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/init.c
|
||
|
@@ -180,6 +180,8 @@ ldbm_back_init(Slapi_PBlock *pb)
|
||
|
(void *)ldbm_back_set_info);
|
||
|
rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DB_CTRL_INFO_FN,
|
||
|
(void *)ldbm_back_ctrl_info);
|
||
|
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DB_COMPACT_FN,
|
||
|
+ (void *)ldbm_back_compact);
|
||
|
|
||
|
if (rc != 0) {
|
||
|
slapi_log_err(SLAPI_LOG_CRIT, "ldbm_back_init", "Failed %d\n", rc);
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.h b/ldap/servers/slapd/back-ldbm/ldbm_config.h
|
||
|
index 6fa8292eb..48446193e 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/ldbm_config.h
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.h
|
||
|
@@ -84,6 +84,7 @@ struct config_info
|
||
|
#define CONFIG_DB_TRANSACTION_WAIT "nsslapd-db-transaction-wait"
|
||
|
#define CONFIG_DB_CHECKPOINT_INTERVAL "nsslapd-db-checkpoint-interval"
|
||
|
#define CONFIG_DB_COMPACTDB_INTERVAL "nsslapd-db-compactdb-interval"
|
||
|
+#define CONFIG_DB_COMPACTDB_TIME "nsslapd-db-compactdb-time"
|
||
|
#define CONFIG_DB_TRANSACTION_BATCH "nsslapd-db-transaction-batch-val"
|
||
|
#define CONFIG_DB_TRANSACTION_BATCH_MIN_SLEEP "nsslapd-db-transaction-batch-min-wait"
|
||
|
#define CONFIG_DB_TRANSACTION_BATCH_MAX_SLEEP "nsslapd-db-transaction-batch-max-wait"
|
||
|
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||
|
index 5d618a89c..30c9003bf 100644
|
||
|
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||
|
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||
|
@@ -478,6 +478,7 @@ void ldbm_back_search_results_release(void **search_results);
|
||
|
int ldbm_back_init(Slapi_PBlock *pb);
|
||
|
void ldbm_back_prev_search_results(Slapi_PBlock *pb);
|
||
|
int ldbm_back_isinitialized(void);
|
||
|
+int32_t ldbm_back_compact(Slapi_Backend *be);
|
||
|
|
||
|
/*
|
||
|
* vlv.c
|
||
|
diff --git a/ldap/servers/slapd/filtercmp.c b/ldap/servers/slapd/filtercmp.c
|
||
|
index f7e3ed4d5..c886267bd 100644
|
||
|
--- a/ldap/servers/slapd/filtercmp.c
|
||
|
+++ b/ldap/servers/slapd/filtercmp.c
|
||
|
@@ -344,7 +344,6 @@ slapi_filter_compare(struct slapi_filter *f1, struct slapi_filter *f2)
|
||
|
struct berval *inval1[2], *inval2[2], **outval1, **outval2;
|
||
|
int ret;
|
||
|
Slapi_Attr sattr;
|
||
|
- int cmplen;
|
||
|
|
||
|
slapi_log_err(SLAPI_LOG_TRACE, "slapi_filter_compare", "=>\n");
|
||
|
|
||
|
@@ -379,11 +378,11 @@ slapi_filter_compare(struct slapi_filter *f1, struct slapi_filter *f2)
|
||
|
if (key1 && key2) {
|
||
|
struct berval bvkey1 = {
|
||
|
slapi_value_get_length(key1[0]),
|
||
|
- slapi_value_get_string(key1[0])
|
||
|
+ (char *)slapi_value_get_string(key1[0])
|
||
|
};
|
||
|
struct berval bvkey2 = {
|
||
|
slapi_value_get_length(key2[0]),
|
||
|
- slapi_value_get_string(key2[0])
|
||
|
+ (char *)slapi_value_get_string(key2[0])
|
||
|
};
|
||
|
ret = slapi_berval_cmp(&bvkey1, &bvkey2);
|
||
|
}
|
||
|
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
|
||
|
index f7d1f8885..fcac53839 100644
|
||
|
--- a/ldap/servers/slapd/pblock.c
|
||
|
+++ b/ldap/servers/slapd/pblock.c
|
||
|
@@ -925,6 +925,12 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value)
|
||
|
}
|
||
|
(*(IFP *)value) = pblock->pb_plugin->plg_db2ldif;
|
||
|
break;
|
||
|
+ case SLAPI_PLUGIN_DB_COMPACT_FN:
|
||
|
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) {
|
||
|
+ return (-1);
|
||
|
+ }
|
||
|
+ (*(IFP *)value) = pblock->pb_plugin->plg_dbcompact;
|
||
|
+ break;
|
||
|
case SLAPI_PLUGIN_DB_DB2INDEX_FN:
|
||
|
if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) {
|
||
|
return (-1);
|
||
|
@@ -2925,7 +2931,12 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
|
||
|
}
|
||
|
pblock->pb_backend->be_noacl = *((int *)value);
|
||
|
break;
|
||
|
-
|
||
|
+ case SLAPI_PLUGIN_DB_COMPACT_FN:
|
||
|
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) {
|
||
|
+ return (-1);
|
||
|
+ }
|
||
|
+ pblock->pb_plugin->plg_dbcompact = (IFP)value;
|
||
|
+ break;
|
||
|
|
||
|
/* extendedop plugin functions */
|
||
|
case SLAPI_PLUGIN_EXT_OP_FN:
|
||
|
@@ -4137,8 +4148,8 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
|
||
|
break;
|
||
|
|
||
|
case SLAPI_URP_TOMBSTONE_CONFLICT_DN:
|
||
|
- pblock->pb_intop->pb_urp_tombstone_conflict_dn = (char *)value;
|
||
|
- break;
|
||
|
+ pblock->pb_intop->pb_urp_tombstone_conflict_dn = (char *)value;
|
||
|
+ break;
|
||
|
|
||
|
case SLAPI_URP_TOMBSTONE_UNIQUEID:
|
||
|
_pblock_assert_pb_intop(pblock);
|
||
|
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
|
||
|
index 3126a65f3..c48516157 100644
|
||
|
--- a/ldap/servers/slapd/slap.h
|
||
|
+++ b/ldap/servers/slapd/slap.h
|
||
|
@@ -1041,6 +1041,7 @@ struct slapdplugin
|
||
|
IFP plg_un_db_ldif2db; /* ldif 2 database */
|
||
|
IFP plg_un_db_db2ldif; /* database 2 ldif */
|
||
|
IFP plg_un_db_db2index; /* database 2 index */
|
||
|
+ IFP plg_un_db_dbcompact; /* compact database */
|
||
|
IFP plg_un_db_archive2db; /* ldif 2 database */
|
||
|
IFP plg_un_db_db2archive; /* database 2 ldif */
|
||
|
IFP plg_un_db_upgradedb; /* convert old idl to new */
|
||
|
@@ -1082,6 +1083,7 @@ struct slapdplugin
|
||
|
#define plg_result plg_un.plg_un_db.plg_un_db_result
|
||
|
#define plg_ldif2db plg_un.plg_un_db.plg_un_db_ldif2db
|
||
|
#define plg_db2ldif plg_un.plg_un_db.plg_un_db_db2ldif
|
||
|
+#define plg_dbcompact plg_un.plg_un_db.plg_un_db_dbcompact
|
||
|
#define plg_db2index plg_un.plg_un_db.plg_un_db_db2index
|
||
|
#define plg_archive2db plg_un.plg_un_db.plg_un_db_archive2db
|
||
|
#define plg_db2archive plg_un.plg_un_db.plg_un_db_db2archive
|
||
|
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
|
||
|
index b956ebe63..570765e47 100644
|
||
|
--- a/ldap/servers/slapd/slapi-private.h
|
||
|
+++ b/ldap/servers/slapd/slapi-private.h
|
||
|
@@ -928,6 +928,7 @@ int proxyauth_get_dn(Slapi_PBlock *pb, char **proxydnp, char **errtextp);
|
||
|
#define SLAPI_PLUGIN_DB_GET_INFO_FN 290
|
||
|
#define SLAPI_PLUGIN_DB_SET_INFO_FN 291
|
||
|
#define SLAPI_PLUGIN_DB_CTRL_INFO_FN 292
|
||
|
+#define SLAPI_PLUGIN_DB_COMPACT_FN 294
|
||
|
|
||
|
/**** End of database plugin interface. **************************************/
|
||
|
|
||
|
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
|
||
|
index 93d31b806..4c7262ab3 100644
|
||
|
--- a/ldap/servers/slapd/task.c
|
||
|
+++ b/ldap/servers/slapd/task.c
|
||
|
@@ -1,6 +1,6 @@
|
||
|
/** BEGIN COPYRIGHT BLOCK
|
||
|
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||
|
- * Copyright (C) 2005 Red Hat, Inc.
|
||
|
+ * Copyright (C) 2021 Red Hat, Inc.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* License: GPL (version 3 or any later version).
|
||
|
@@ -2928,6 +2928,105 @@ des2aes_task_destructor(Slapi_Task *task)
|
||
|
"des2aes_task_destructor <--\n");
|
||
|
}
|
||
|
|
||
|
+struct task_compact_data
|
||
|
+{
|
||
|
+ char *suffix;
|
||
|
+ Slapi_Task *task;
|
||
|
+};
|
||
|
+
|
||
|
+static void
|
||
|
+compact_db_task_destructor(Slapi_Task *task)
|
||
|
+{
|
||
|
+ slapi_log_err(SLAPI_LOG_PLUGIN, "compact db task",
|
||
|
+ "compact_db_task_destructor -->\n");
|
||
|
+ if (task) {
|
||
|
+ struct task_compact_data *mydata = (struct task_compact_data *)slapi_task_get_data(task);
|
||
|
+ while (slapi_task_get_refcount(task) > 0) {
|
||
|
+ /* Yield to wait for the task to finish */
|
||
|
+ DS_Sleep(PR_MillisecondsToInterval(100));
|
||
|
+ }
|
||
|
+ if (mydata) {
|
||
|
+ slapi_ch_free((void **)&mydata);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ slapi_log_err(SLAPI_LOG_PLUGIN, "compact db task",
|
||
|
+ "compact_db_task_destructor <--\n");
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+task_compact_thread(void *arg)
|
||
|
+{
|
||
|
+ struct task_compact_data *task_data = arg;
|
||
|
+ Slapi_Task *task = task_data->task;
|
||
|
+ Slapi_Backend *be = NULL;
|
||
|
+ char *cookie = NULL;
|
||
|
+ int32_t rc = -1;
|
||
|
+
|
||
|
+ slapi_task_inc_refcount(task);
|
||
|
+ slapi_task_begin(task, 1);
|
||
|
+
|
||
|
+ be = slapi_get_first_backend(&cookie);
|
||
|
+ while (be) {
|
||
|
+ if (be->be_private == 0) {
|
||
|
+ /* Found a non-private backend, start compacting */
|
||
|
+ rc = (be->be_database->plg_dbcompact)(be);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ be = (backend *)slapi_get_next_backend(cookie);
|
||
|
+ }
|
||
|
+ slapi_ch_free_string(&cookie);
|
||
|
+
|
||
|
+ slapi_task_finish(task, rc);
|
||
|
+ slapi_task_dec_refcount(task);
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * compact the BDB database
|
||
|
+ *
|
||
|
+ * dn: cn=compact_it,cn=compact db,cn=tasks,cn=config
|
||
|
+ * objectclass: top
|
||
|
+ * objectclass: extensibleObject
|
||
|
+ * cn: compact_it
|
||
|
+ */
|
||
|
+static int
|
||
|
+task_compact_db_add(Slapi_PBlock *pb,
|
||
|
+ Slapi_Entry *e,
|
||
|
+ Slapi_Entry *eAfter __attribute__((unused)),
|
||
|
+ int *returncode,
|
||
|
+ char *returntext,
|
||
|
+ void *arg __attribute__((unused)))
|
||
|
+{
|
||
|
+ Slapi_Task *task = slapi_new_task(slapi_entry_get_ndn(e));
|
||
|
+ struct task_compact_data *task_data = NULL;
|
||
|
+ PRThread *thread = NULL;
|
||
|
+
|
||
|
+ slapi_task_log_notice(task, "Beginning database compaction task...\n");
|
||
|
+
|
||
|
+ /* Register our destructor for cleaning up our private data */
|
||
|
+ slapi_task_set_destructor_fn(task, compact_db_task_destructor);
|
||
|
+
|
||
|
+ task_data = (struct task_compact_data *)slapi_ch_calloc(1, sizeof(struct task_compact_data));
|
||
|
+ task_data->task = task;
|
||
|
+ slapi_task_set_data(task, task_data);
|
||
|
+
|
||
|
+ /* Start the compaction as a separate thread */
|
||
|
+ thread = PR_CreateThread(PR_USER_THREAD, task_compact_thread,
|
||
|
+ (void *)task_data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||
|
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
|
||
|
+ if (thread == NULL) {
|
||
|
+ slapi_log_err(SLAPI_LOG_ERR, "task_compact_db_add", "Unable to create db compact thread!\n");
|
||
|
+ *returncode = LDAP_OPERATIONS_ERROR;
|
||
|
+ slapi_ch_free((void **)&task_data);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (*returncode != LDAP_SUCCESS) {
|
||
|
+ slapi_task_finish(task, *returncode);
|
||
|
+ return SLAPI_DSE_CALLBACK_ERROR;
|
||
|
+ }
|
||
|
+
|
||
|
+ return SLAPI_DSE_CALLBACK_OK;
|
||
|
+}
|
||
|
+
|
||
|
/* cleanup old tasks that may still be in the DSE from a previous session
|
||
|
* (this can happen if the server crashes [no matter how unlikely we like
|
||
|
* to think that is].)
|
||
|
@@ -3010,6 +3109,7 @@ task_init(void)
|
||
|
slapi_task_register_handler("sysconfig reload", task_sysconfig_reload_add);
|
||
|
slapi_task_register_handler("fixup tombstones", task_fixup_tombstones_add);
|
||
|
slapi_task_register_handler("des2aes", task_des2aes);
|
||
|
+ slapi_task_register_handler("compact db", task_compact_db_add);
|
||
|
}
|
||
|
|
||
|
/* called when the server is shutting down -- abort all existing tasks */
|
||
|
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
|
||
|
index 11cae972c..b73dc8460 100644
|
||
|
--- a/src/cockpit/389-console/src/database.jsx
|
||
|
+++ b/src/cockpit/389-console/src/database.jsx
|
||
|
@@ -196,6 +196,7 @@ export class Database extends React.Component {
|
||
|
dblocksMonitoringPause: attrs['nsslapd-db-locks-monitoring-pause'],
|
||
|
chxpoint: attrs['nsslapd-db-checkpoint-interval'],
|
||
|
compactinterval: attrs['nsslapd-db-compactdb-interval'],
|
||
|
+ compacttime: attrs['nsslapd-db-compactdb-time'],
|
||
|
importcacheauto: attrs['nsslapd-import-cache-autosize'],
|
||
|
importcachesize: attrs['nsslapd-import-cachesize'],
|
||
|
},
|
||
|
diff --git a/src/cockpit/389-console/src/lib/database/databaseConfig.jsx b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
|
||
|
index 6a71c138d..1fa9f2cc2 100644
|
||
|
--- a/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
|
||
|
+++ b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
|
||
|
@@ -36,6 +36,7 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
dblocksMonitoringPause: this.props.data.dblocksMonitoringPause,
|
||
|
chxpoint: this.props.data.chxpoint,
|
||
|
compactinterval: this.props.data.compactinterval,
|
||
|
+ compacttime: this.props.data.compacttime,
|
||
|
importcachesize: this.props.data.importcachesize,
|
||
|
importcacheauto: this.props.data.importcacheauto,
|
||
|
// These variables store the original value (used for saving config)
|
||
|
@@ -55,6 +56,7 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
_dblocksMonitoringPause: this.props.data.dblocksMonitoringPause,
|
||
|
_chxpoint: this.props.data.chxpoint,
|
||
|
_compactinterval: this.props.data.compactinterval,
|
||
|
+ _compacttime: this.props.data.compacttime,
|
||
|
_importcachesize: this.props.data.importcachesize,
|
||
|
_importcacheauto: this.props.data.importcacheauto,
|
||
|
_db_cache_auto: this.props.data.db_cache_auto,
|
||
|
@@ -186,6 +188,10 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
cmd.push("--compactdb-interval=" + this.state.compactinterval);
|
||
|
requireRestart = true;
|
||
|
}
|
||
|
+ if (this.state._compacttime != this.state.compacttime) {
|
||
|
+ cmd.push("--compactdb-time=" + this.state.compacttime);
|
||
|
+ requireRestart = true;
|
||
|
+ }
|
||
|
if (this.state.import_cache_auto) {
|
||
|
// Auto cache is selected
|
||
|
if (this.state._import_cache_auto != this.state.import_cache_auto) {
|
||
|
@@ -485,7 +491,15 @@ export class GlobalDatabaseConfig extends React.Component {
|
||
|
Database Compact Interval
|
||
|
</Col>
|
||
|
<Col sm={8}>
|
||
|
- <input id="compactinterval" value={this.state.compactinterval} onChange={this.handleChange} className="ds-input-auto" type="text" />
|
||
|
+ <input id="compactinterval" value={this.state.compactinterval} onChange={this.handleChange} className="ds-input-auto" type="number" />
|
||
|
+ </Col>
|
||
|
+ </Row>
|
||
|
+ <Row className="ds-margin-top" title="The Time Of Day to perform the database compaction after the compact interval has been met. Uses the format: 'HH:MM' and defaults to '23:59'. (nsslapd-db-compactdb-time)">
|
||
|
+ <Col componentClass={ControlLabel} sm={4}>
|
||
|
+ Database Compact Time
|
||
|
+ </Col>
|
||
|
+ <Col sm={8}>
|
||
|
+ <input id="compacttime" value={this.state.compacttime} onChange={this.handleChange} className="ds-input-auto" type="number" />
|
||
|
</Col>
|
||
|
</Row>
|
||
|
<Row className="ds-margin-top" title="The number of database locks (nsslapd-db-locks).">
|
||
|
diff --git a/src/lib389/lib389/_constants.py b/src/lib389/lib389/_constants.py
|
||
|
index c184c8d4f..d6161cebb 100644
|
||
|
--- a/src/lib389/lib389/_constants.py
|
||
|
+++ b/src/lib389/lib389/_constants.py
|
||
|
@@ -154,6 +154,7 @@ DN_EUUID_TASK = "cn=entryuuid task,%s" % DN_TASKS
|
||
|
DN_TOMB_FIXUP_TASK = "cn=fixup tombstones,%s" % DN_TASKS
|
||
|
DN_FIXUP_LINKED_ATTIBUTES = "cn=fixup linked attributes,%s" % DN_TASKS
|
||
|
DN_AUTOMEMBER_REBUILD_TASK = "cn=automember rebuild membership,%s" % DN_TASKS
|
||
|
+DN_COMPACTDB_TASK = "cn=compact db,%s" % DN_TASKS
|
||
|
|
||
|
# Script Constants
|
||
|
LDIF2DB = 'ldif2db'
|
||
|
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
|
||
|
index 13bb27842..ad78a6ffe 100644
|
||
|
--- a/src/lib389/lib389/backend.py
|
||
|
+++ b/src/lib389/lib389/backend.py
|
||
|
@@ -1005,6 +1005,7 @@ class DatabaseConfig(DSLdapObject):
|
||
|
'nsslapd-db-transaction-wait',
|
||
|
'nsslapd-db-checkpoint-interval',
|
||
|
'nsslapd-db-compactdb-interval',
|
||
|
+ 'nsslapd-db-compactdb-time',
|
||
|
'nsslapd-db-page-size',
|
||
|
'nsslapd-db-transaction-batch-val',
|
||
|
'nsslapd-db-transaction-batch-min-wait',
|
||
|
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
|
||
|
index 722764d10..7b2f32c23 100644
|
||
|
--- a/src/lib389/lib389/cli_conf/backend.py
|
||
|
+++ b/src/lib389/lib389/cli_conf/backend.py
|
||
|
@@ -1,5 +1,5 @@
|
||
|
# --- BEGIN COPYRIGHT BLOCK ---
|
||
|
-# Copyright (C) 2020 Red Hat, Inc.
|
||
|
+# Copyright (C) 2021 Red Hat, Inc.
|
||
|
# Copyright (C) 2019 William Brown <william@blackhats.net.au>
|
||
|
# All rights reserved.
|
||
|
#
|
||
|
@@ -19,6 +19,7 @@ from lib389.chaining import (ChainingLinks)
|
||
|
from lib389.monitor import MonitorLDBM
|
||
|
from lib389.replica import Replicas
|
||
|
from lib389.utils import ensure_str, is_a_dn, is_dn_parent
|
||
|
+from lib389.tasks import DBCompactTask
|
||
|
from lib389._constants import *
|
||
|
from lib389.cli_base import (
|
||
|
_format_status,
|
||
|
@@ -41,6 +42,7 @@ arg_to_attr = {
|
||
|
'txn_wait': 'nsslapd-db-transaction-wait',
|
||
|
'checkpoint_interval': 'nsslapd-db-checkpoint-interval',
|
||
|
'compactdb_interval': 'nsslapd-db-compactdb-interval',
|
||
|
+ 'compactdb_time': 'nsslapd-db-compactdb-time',
|
||
|
'txn_batch_val': 'nsslapd-db-transaction-batch-val',
|
||
|
'txn_batch_min': 'nsslapd-db-transaction-batch-min-wait',
|
||
|
'txn_batch_max': 'nsslapd-db-transaction-batch-max-wait',
|
||
|
@@ -789,6 +791,18 @@ def backend_reindex_vlv(inst, basedn, log, args):
|
||
|
log.info("Successfully reindexed VLV indexes")
|
||
|
|
||
|
|
||
|
+def backend_compact(inst, basedn, log, args):
|
||
|
+ task = DBCompactTask(inst)
|
||
|
+ task_properties = {}
|
||
|
+ if args.only_changelog:
|
||
|
+ task_properties = {'justChangelog': 'yes'}
|
||
|
+ task.create(properties=task_properties)
|
||
|
+ task.wait()
|
||
|
+ if task.get_exit_code() != 0:
|
||
|
+ raise ValueError("Failed to create Database Compaction Task")
|
||
|
+ log.info("Successfully started Database Compaction Task")
|
||
|
+
|
||
|
+
|
||
|
def create_parser(subparsers):
|
||
|
backend_parser = subparsers.add_parser('backend', help="Manage database suffixes and backends")
|
||
|
subcommands = backend_parser.add_subparsers(help="action")
|
||
|
@@ -994,6 +1008,7 @@ def create_parser(subparsers):
|
||
|
set_db_config_parser.add_argument('--checkpoint-interval', help='Sets the amount of time in seconds after which the Directory Server sends a '
|
||
|
'checkpoint entry to the database transaction log')
|
||
|
set_db_config_parser.add_argument('--compactdb-interval', help='Sets the interval in seconds when the database is compacted')
|
||
|
+ set_db_config_parser.add_argument('--compactdb-time', help='Sets the Time Of Day to compact the database after the "compactdb interval" has been reached: Use this format to set the hour and minute: HH:MM')
|
||
|
set_db_config_parser.add_argument('--txn-batch-val', help='Specifies how many transactions will be batched before being committed')
|
||
|
set_db_config_parser.add_argument('--txn-batch-min', help='Controls when transactions should be flushed earliest, independently of '
|
||
|
'the batch count (only works when txn-batch-val is set)')
|
||
|
@@ -1121,3 +1136,10 @@ def create_parser(subparsers):
|
||
|
#######################################################
|
||
|
get_tree_parser = subcommands.add_parser('get-tree', help='Get a representation of the suffix tree')
|
||
|
get_tree_parser.set_defaults(func=backend_get_tree)
|
||
|
+
|
||
|
+ #######################################################
|
||
|
+ # Run the db compaction task
|
||
|
+ #######################################################
|
||
|
+ compact_parser = subcommands.add_parser('compact-db', help='Compact the database and the replication changelog')
|
||
|
+ compact_parser.set_defaults(func=backend_compact)
|
||
|
+ compact_parser.add_argument('--only-changelog', action='store_true', help='Only compact the Replication Change Log')
|
||
|
diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py
|
||
|
index 04886f632..3478a0a1f 100644
|
||
|
--- a/src/lib389/lib389/cli_conf/replication.py
|
||
|
+++ b/src/lib389/lib389/cli_conf/replication.py
|
||
|
@@ -37,6 +37,7 @@ arg_to_attr = {
|
||
|
'max_entries': 'nsslapd-changelogmaxentries',
|
||
|
'max_age': 'nsslapd-changelogmaxage',
|
||
|
'compact_interval': 'nsslapd-changelogcompactdb-interval',
|
||
|
+ 'compact_time': 'nsslapd-changelogcompactdb-time',
|
||
|
'trim_interval': 'nsslapd-changelogtrim-interval',
|
||
|
'encrypt_algo': 'nsslapd-encryptionalgorithm',
|
||
|
'encrypt_key': 'nssymmetrickey',
|
||
|
@@ -1216,6 +1217,8 @@ def create_parser(subparsers):
|
||
|
repl_set_cl.add_argument('--max-entries', help="The maximum number of entries to get in the replication changelog")
|
||
|
repl_set_cl.add_argument('--max-age', help="The maximum age of a replication changelog entry")
|
||
|
repl_set_cl.add_argument('--compact-interval', help="The replication changelog compaction interval")
|
||
|
+ repl_set_cl.add_argument('--compact-time', help='Sets the Time Of Day to compact the database after the changelog "compact interval" '
|
||
|
+ 'has been reached: Use this format to set the hour and minute: HH:MM')
|
||
|
repl_set_cl.add_argument('--trim-interval', help="The interval to check if the replication changelog can be trimmed")
|
||
|
|
||
|
repl_get_cl = repl_subcommands.add_parser('get-changelog', help='Display replication changelog attributes.')
|
||
|
diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py
|
||
|
index 590c6ee79..b64bc6ce5 100644
|
||
|
--- a/src/lib389/lib389/tasks.py
|
||
|
+++ b/src/lib389/lib389/tasks.py
|
||
|
@@ -217,6 +217,19 @@ class EntryUUIDFixupTask(Task):
|
||
|
self._must_attributes.extend(['basedn'])
|
||
|
|
||
|
|
||
|
+class DBCompactTask(Task):
|
||
|
+ """A single instance of compactdb task entry
|
||
|
+
|
||
|
+ :param instance: An instance
|
||
|
+ :type instance: lib389.DirSrv
|
||
|
+ """
|
||
|
+
|
||
|
+ def __init__(self, instance, dn=None):
|
||
|
+ self.cn = 'compact_db_' + Task._get_task_date()
|
||
|
+ dn = "cn=" + self.cn + "," + DN_COMPACTDB_TASK
|
||
|
+ super(DBCompactTask, self).__init__(instance, dn)
|
||
|
+
|
||
|
+
|
||
|
class SchemaReloadTask(Task):
|
||
|
"""A single instance of schema reload task entry
|
||
|
|
||
|
@@ -227,7 +240,6 @@ class SchemaReloadTask(Task):
|
||
|
def __init__(self, instance, dn=None):
|
||
|
self.cn = 'schema_reload_' + Task._get_task_date()
|
||
|
dn = "cn=" + self.cn + ",cn=schema reload task," + DN_TASKS
|
||
|
-
|
||
|
super(SchemaReloadTask, self).__init__(instance, dn)
|
||
|
|
||
|
|
||
|
--
|
||
|
2.26.3
|
||
|
|