diff --git a/0005-Issue-7096-During-replication-online-total-init-the-.patch b/0001-Issue-7096-During-replication-online-total-init-the-.patch similarity index 99% rename from 0005-Issue-7096-During-replication-online-total-init-the-.patch rename to 0001-Issue-7096-During-replication-online-total-init-the-.patch index fddca98..a5792b6 100644 --- a/0005-Issue-7096-During-replication-online-total-init-the-.patch +++ b/0001-Issue-7096-During-replication-online-total-init-the-.patch @@ -1,4 +1,4 @@ -From 5de98cdc10bd333d0695c00d57e137d699f90f1c Mon Sep 17 00:00:00 2001 +From 1c9c535888b9a850095794787d67900b04924a76 Mon Sep 17 00:00:00 2001 From: tbordaz Date: Wed, 7 Jan 2026 11:21:12 +0100 Subject: [PATCH] Issue 7096 - During replication online total init the diff --git a/0001-Issue-7150-Compressed-access-log-rotations-skipped-a.patch b/0001-Issue-7150-Compressed-access-log-rotations-skipped-a.patch deleted file mode 100644 index 7959885..0000000 --- a/0001-Issue-7150-Compressed-access-log-rotations-skipped-a.patch +++ /dev/null @@ -1,551 +0,0 @@ -From 045fe1a6899b7e4588be7101e81bb78995a713b1 Mon Sep 17 00:00:00 2001 -From: Simon Pichugin -Date: Tue, 16 Dec 2025 15:48:35 -0800 -Subject: [PATCH] Issue 7150 - Compressed access log rotations skipped, - accesslog-list out of sync (#7151) - -Description: Accept `.gz`-suffixed rotated log filenames when -rebuilding rotation info and checking previous logs, preventing -compressed rotations from being dropped from the internal list. - -Add regression tests to stress log rotation with compression, -verify `nsslapd-accesslog-list` stays in sync, and guard against -crashes when flushing buffered logs during rotation. -Minor doc fix in test. - -Fixes: https://github.com/389ds/389-ds-base/issues/7150 - -Reviewed by: @progier389 (Thanks!) ---- - .../suites/logging/log_flush_rotation_test.py | 341 +++++++++++++++++- - ldap/servers/slapd/log.c | 99 +++-- - 2 files changed, 402 insertions(+), 38 deletions(-) - -diff --git a/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py b/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py -index b33a622e1..864ba9c5d 100644 ---- a/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py -+++ b/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py -@@ -6,6 +6,7 @@ - # See LICENSE for details. - # --- END COPYRIGHT BLOCK --- - # -+import glob - import os - import logging - import time -@@ -13,14 +14,351 @@ import pytest - from lib389._constants import DEFAULT_SUFFIX, PW_DM - from lib389.tasks import ImportTask - from lib389.idm.user import UserAccounts -+from lib389.idm.domain import Domain -+from lib389.idm.directorymanager import DirectoryManager - from lib389.topologies import topology_st as topo - - - log = logging.getLogger(__name__) - - -+def remove_rotated_access_logs(inst): -+ """ -+ Remove all rotated access log files to start fresh for each test. -+ This prevents log files from previous tests affecting current test results. -+ """ -+ log_dir = inst.get_log_dir() -+ patterns = [ -+ f'{log_dir}/access.2*', # Uncompressed rotated logs -+ f'{log_dir}/access.*.gz', # Compressed rotated logs -+ ] -+ for pattern in patterns: -+ for log_file in glob.glob(pattern): -+ try: -+ os.remove(log_file) -+ log.info(f"Removed old log file: {log_file}") -+ except OSError as e: -+ log.warning(f"Could not remove {log_file}: {e}") -+ -+ -+def reset_access_log_config(inst): -+ """ -+ Reset access log configuration to default values. -+ """ -+ inst.config.set('nsslapd-accesslog-compress', 'off') -+ inst.config.set('nsslapd-accesslog-maxlogsize', '100') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', '10') -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'on') -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ inst.config.set('nsslapd-accesslog-logminfreediskspace', '5') -+ -+ -+def generate_heavy_load(inst, suffix, iterations=50): -+ """ -+ Generate heavy LDAP load to fill access log quickly. -+ Performs multiple operations: searches, modifies, binds to populate logs. -+ """ -+ for i in range(iterations): -+ suffix.replace('description', f'iteration_{i}') -+ suffix.get_attr_val('description') -+ -+ -+def count_access_logs(log_dir, compressed_only=False): -+ """ -+ Count access log files in the log directory. -+ Returns count of rotated access logs (not including the active 'access' file). -+ """ -+ if compressed_only: -+ pattern = f'{log_dir}/access.*.gz' -+ else: -+ pattern = f'{log_dir}/access.2*' -+ log_files = glob.glob(pattern) -+ return len(log_files) -+ -+ -+def test_log_pileup_with_compression(topo): -+ """Test that log rotation properly deletes old logs when compression is enabled. -+ -+ :id: fa1bfce8-b6d3-4520-a0a8-bead14fa5838 -+ :setup: Standalone Instance -+ :steps: -+ 1. Clean up existing rotated logs and reset configuration -+ 2. Enable access log compression -+ 3. Set strict log limits (small maxlogsperdir) -+ 4. Disable log expiration to test count-based deletion -+ 5. Generate heavy load to create many log rotations -+ 6. Verify log count does not exceed maxlogsperdir limit -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. Success -+ 5. Success -+ 6. Log count should be at or below maxlogsperdir + small buffer -+ """ -+ -+ inst = topo.standalone -+ suffix = Domain(inst, DEFAULT_SUFFIX) -+ log_dir = inst.get_log_dir() -+ -+ # Clean up before test -+ remove_rotated_access_logs(inst) -+ reset_access_log_config(inst) -+ inst.restart() -+ -+ max_logs = 5 -+ inst.config.set('nsslapd-accesslog-compress', 'on') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', str(max_logs)) -+ inst.config.set('nsslapd-accesslog-maxlogsize', '1') # 1MB to trigger rotation -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'off') -+ -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ -+ inst.config.set('nsslapd-accesslog-logminfreediskspace', '5') -+ -+ inst.restart() -+ time.sleep(2) -+ -+ target_logs = max_logs * 3 -+ for i in range(target_logs): -+ log.info(f"Generating load for log rotation {i+1}/{target_logs}") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) # Wait for rotation -+ -+ time.sleep(3) -+ -+ logs_on_disk = count_access_logs(log_dir) -+ log.info(f"Configured maxlogsperdir: {max_logs}") -+ log.info(f"Actual rotated logs on disk: {logs_on_disk}") -+ -+ all_access_logs = glob.glob(f'{log_dir}/access*') -+ log.info(f"All access log files: {all_access_logs}") -+ -+ max_allowed = max_logs + 2 -+ assert logs_on_disk <= max_allowed, ( -+ f"Log rotation failed to delete old files! " -+ f"Expected at most {max_allowed} rotated logs (maxlogsperdir={max_logs} + 2 buffer), " -+ f"but found {logs_on_disk}. The server has lost track of the file list." -+ ) -+ -+ -+@pytest.mark.parametrize("compress_enabled", ["on", "off"]) -+def test_accesslog_list_mismatch(topo, compress_enabled): -+ """Test that nsslapd-accesslog-list stays synchronized with actual log files. -+ -+ :id: 0a8a46a6-cae7-43bd-8b64-5e3481480cd3 -+ :parametrized: yes -+ :setup: Standalone Instance -+ :steps: -+ 1. Clean up existing rotated logs and reset configuration -+ 2. Configure log rotation with compression enabled/disabled -+ 3. Generate activity to trigger multiple rotations -+ 4. Get the nsslapd-accesslog-list attribute -+ 5. Compare with actual files on disk -+ 6. Verify they match (accounting for .gz extension when enabled) -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. Success -+ 5. Success -+ 6. The list attribute should match actual files on disk -+ """ -+ -+ inst = topo.standalone -+ suffix = Domain(inst, DEFAULT_SUFFIX) -+ log_dir = inst.get_log_dir() -+ compression_on = compress_enabled == "on" -+ -+ # Clean up before test -+ remove_rotated_access_logs(inst) -+ reset_access_log_config(inst) -+ inst.restart() -+ -+ inst.config.set('nsslapd-accesslog-compress', compress_enabled) -+ inst.config.set('nsslapd-accesslog-maxlogsize', '1') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', '10') -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'off') -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ -+ inst.restart() -+ time.sleep(2) -+ -+ for i in range(15): -+ suffix_note = "(no compression)" if not compression_on else "" -+ log.info(f"Generating load for rotation {i+1}/15 {suffix_note}") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) -+ -+ time.sleep(3) -+ -+ accesslog_list = inst.config.get_attr_vals_utf8('nsslapd-accesslog-list') -+ log.info(f"nsslapd-accesslog-list entries (compress={compress_enabled}): {len(accesslog_list)}") -+ log.info(f"nsslapd-accesslog-list (compress={compress_enabled}): {accesslog_list}") -+ -+ disk_files = glob.glob(f'{log_dir}/access.2*') -+ log.info(f"Actual files on disk (compress={compress_enabled}): {len(disk_files)}") -+ log.info(f"Disk files (compress={compress_enabled}): {disk_files}") -+ -+ disk_files_for_compare = set() -+ for fpath in disk_files: -+ if compression_on and fpath.endswith('.gz'): -+ disk_files_for_compare.add(fpath[:-3]) -+ else: -+ disk_files_for_compare.add(fpath) -+ -+ list_files_set = set(accesslog_list) -+ missing_from_disk = list_files_set - disk_files_for_compare -+ extra_on_disk = disk_files_for_compare - list_files_set -+ -+ if missing_from_disk: -+ log.error( -+ f"[compress={compress_enabled}] Files in list but NOT on disk: {missing_from_disk}" -+ ) -+ if extra_on_disk: -+ log.warning( -+ f"[compress={compress_enabled}] Files on disk but NOT in list: {extra_on_disk}" -+ ) -+ -+ assert not missing_from_disk, ( -+ f"nsslapd-accesslog-list mismatch (compress={compress_enabled})! " -+ f"Files listed but missing from disk: {missing_from_disk}. " -+ f"This indicates the server's internal list is out of sync with actual files." -+ ) -+ -+ if len(extra_on_disk) > 2: -+ log.warning( -+ f"Potential log tracking issue (compress={compress_enabled}): " -+ f"{len(extra_on_disk)} files on disk are not tracked in the accesslog-list: " -+ f"{extra_on_disk}" -+ ) -+ -+ -+def test_accesslog_list_mixed_compression(topo): -+ """Test that nsslapd-accesslog-list correctly tracks both compressed and uncompressed logs. -+ -+ :id: 11b088cd-23be-407d-ad16-4ce2e12da09e -+ :setup: Standalone Instance -+ :steps: -+ 1. Clean up existing rotated logs and reset configuration -+ 2. Create rotated logs with compression OFF -+ 3. Enable compression and create more rotated logs -+ 4. Get the nsslapd-accesslog-list attribute -+ 5. Compare with actual files on disk -+ 6. Verify all files are correctly tracked (uncompressed and compressed) -+ :expectedresults: -+ 1. Success -+ 2. Success - uncompressed rotated logs created -+ 3. Success - compressed rotated logs created -+ 4. Success -+ 5. Success -+ 6. The list should contain base filenames (without .gz) that -+ correspond to files on disk (either as-is or with .gz suffix) -+ """ -+ -+ inst = topo.standalone -+ suffix = Domain(inst, DEFAULT_SUFFIX) -+ log_dir = inst.get_log_dir() -+ -+ # Clean up before test -+ remove_rotated_access_logs(inst) -+ reset_access_log_config(inst) -+ inst.restart() -+ -+ inst.config.set('nsslapd-accesslog-compress', 'off') -+ inst.config.set('nsslapd-accesslog-maxlogsize', '1') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', '20') -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'off') -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ -+ inst.restart() -+ time.sleep(2) -+ -+ for i in range(15): -+ log.info(f"Generating load for uncompressed rotation {i+1}/15") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) -+ -+ time.sleep(2) -+ -+ # Check what we have so far -+ uncompressed_files = glob.glob(f'{log_dir}/access.2*') -+ log.info(f"Files on disk after uncompressed phase: {uncompressed_files}") -+ -+ inst.config.set('nsslapd-accesslog-compress', 'on') -+ inst.restart() -+ time.sleep(2) -+ -+ for i in range(15): -+ log.info(f"Generating load for compressed rotation {i+1}/15") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) -+ -+ time.sleep(3) -+ -+ accesslog_list = inst.config.get_attr_vals_utf8('nsslapd-accesslog-list') -+ -+ disk_files = glob.glob(f'{log_dir}/access.2*') -+ -+ log.info(f"nsslapd-accesslog-list entries: {len(accesslog_list)}") -+ log.info(f"nsslapd-accesslog-list: {sorted(accesslog_list)}") -+ log.info(f"Actual files on disk: {len(disk_files)}") -+ log.info(f"Disk files: {sorted(disk_files)}") -+ -+ compressed_on_disk = [f for f in disk_files if f.endswith('.gz')] -+ uncompressed_on_disk = [f for f in disk_files if not f.endswith('.gz')] -+ log.info(f"Compressed files on disk: {compressed_on_disk}") -+ log.info(f"Uncompressed files on disk: {uncompressed_on_disk}") -+ -+ list_files_set = set(accesslog_list) -+ -+ disk_files_base = set() -+ for fpath in disk_files: -+ if fpath.endswith('.gz'): -+ disk_files_base.add(fpath[:-3]) # Strip .gz -+ else: -+ disk_files_base.add(fpath) -+ -+ missing_from_disk = list_files_set - disk_files_base -+ -+ extra_on_disk = disk_files_base - list_files_set -+ -+ if missing_from_disk: -+ log.error(f"Files in list but NOT on disk: {missing_from_disk}") -+ if extra_on_disk: -+ log.warning(f"Files on disk but NOT in list: {extra_on_disk}") -+ -+ assert not missing_from_disk, ( -+ f"nsslapd-accesslog-list contains stale entries! " -+ f"Files in list but not on disk (as base or .gz): {missing_from_disk}" -+ ) -+ -+ for list_file in accesslog_list: -+ exists_uncompressed = os.path.exists(list_file) -+ exists_compressed = os.path.exists(list_file + '.gz') -+ assert exists_uncompressed or exists_compressed, ( -+ f"File in accesslog-list does not exist on disk: {list_file} " -+ f"(checked both {list_file} and {list_file}.gz)" -+ ) -+ if exists_compressed and not exists_uncompressed: -+ log.info(f" {list_file} -> exists as .gz (compressed)") -+ elif exists_uncompressed: -+ log.info(f" {list_file} -> exists (uncompressed)") -+ -+ if len(extra_on_disk) > 1: -+ log.warning( -+ f"Some files on disk are not tracked in accesslog-list: {extra_on_disk}" -+ ) -+ -+ log.info("Mixed compression test completed successfully") -+ -+ - def test_log_flush_and_rotation_crash(topo): -- """Make sure server does not crash whening flushing a buffer and rotating -+ """Make sure server does not crash when flushing a buffer and rotating - the log at the same time - - :id: d4b0af2f-48b2-45f5-ae8b-f06f692c3133 -@@ -36,6 +374,7 @@ def test_log_flush_and_rotation_crash(topo): - 3. Success - 4. Success - """ -+ # NOTE: This test is placed last as it may affect the suffix state. - - inst = topo.standalone - -diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c -index 27bb4bc15..ea744ac1e 100644 ---- a/ldap/servers/slapd/log.c -+++ b/ldap/servers/slapd/log.c -@@ -137,6 +137,7 @@ static void vslapd_log_emergency_error(LOGFD fp, const char *msg, int locked); - static int get_syslog_loglevel(int loglevel); - static void log_external_libs_debug_openldap_print(char *buffer); - static int log__fix_rotationinfof(char *pathname); -+static int log__validate_rotated_logname(const char *timestamp_str, PRBool *is_compressed); - - static int - get_syslog_loglevel(int loglevel) -@@ -375,7 +376,7 @@ g_log_init() - loginfo.log_security_fdes = NULL; - loginfo.log_security_file = NULL; - loginfo.log_securityinfo_file = NULL; -- loginfo.log_numof_access_logs = 1; -+ loginfo.log_numof_security_logs = 1; - loginfo.log_security_logchain = NULL; - loginfo.log_security_buffer = log_create_buffer(LOG_BUFFER_MAXSIZE); - loginfo.log_security_compress = cfg->securitylog_compress; -@@ -3422,7 +3423,7 @@ log__open_accesslogfile(int logfile_state, int locked) - } - } else if (loginfo.log_access_compress) { - if (compress_log_file(newfile, loginfo.log_access_mode) != 0) { -- slapi_log_err(SLAPI_LOG_ERR, "log__open_auditfaillogfile", -+ slapi_log_err(SLAPI_LOG_ERR, "log__open_accesslogfile", - "failed to compress rotated access log (%s)\n", - newfile); - } else { -@@ -4825,6 +4826,50 @@ log__delete_rotated_logs() - loginfo.log_error_logchain = NULL; - } - -+/* -+ * log__validate_rotated_logname -+ * -+ * Validates that a log filename timestamp suffix matches the expected format: -+ * YYYYMMDD-HHMMSS (15 chars) or YYYYMMDD-HHMMSS.gz (18 chars) for compressed files. -+ * Uses regex pattern: ^[0-9]{8}-[0-9]{6}(\.gz)?$ -+ * -+ * \param timestamp_str The timestamp portion of the log filename (after the first '.') -+ * \param is_compressed Output parameter set to PR_TRUE if the file has .gz suffix -+ * \return 1 if valid, 0 if invalid -+ */ -+static int -+log__validate_rotated_logname(const char *timestamp_str, PRBool *is_compressed) -+{ -+ Slapi_Regex *re = NULL; -+ char *re_error = NULL; -+ int rc = 0; -+ -+ /* Match YYYYMMDD-HHMMSS with optional .gz suffix */ -+ static const char *pattern = "^[0-9]{8}-[0-9]{6}(\\.gz)?$"; -+ -+ *is_compressed = PR_FALSE; -+ -+ re = slapi_re_comp(pattern, &re_error); -+ if (re == NULL) { -+ slapi_log_err(SLAPI_LOG_ERR, "log__validate_rotated_logname", -+ "Failed to compile regex: %s\n", re_error ? re_error : "unknown error"); -+ slapi_ch_free_string(&re_error); -+ return 0; -+ } -+ -+ rc = slapi_re_exec_nt(re, timestamp_str); -+ if (rc == 1) { -+ /* Check if compressed by looking for .gz suffix */ -+ size_t len = strlen(timestamp_str); -+ if (len >= 3 && strcmp(timestamp_str + len - 3, ".gz") == 0) { -+ *is_compressed = PR_TRUE; -+ } -+ } -+ -+ slapi_re_free(re); -+ return rc == 1 ? 1 : 0; -+} -+ - #define ERRORSLOG 1 - #define ACCESSLOG 2 - #define AUDITLOG 3 -@@ -4907,31 +4952,19 @@ log__fix_rotationinfof(char *pathname) - } - } else if (0 == strncmp(log_type, dirent->name, strlen(log_type)) && - (p = strchr(dirent->name, '.')) != NULL && -- NULL != strchr(p, '-')) /* e.g., errors.20051123-165135 */ -+ NULL != strchr(p, '-')) /* e.g., errors.20051123-165135 or errors.20051123-165135.gz */ - { - struct logfileinfo *logp; -- char *q; -- int ignoreit = 0; -- -- for (q = ++p; q && *q; q++) { -- if (*q != '-' && -- *q != '.' && /* .gz */ -- *q != 'g' && -- *q != 'z' && -- !isdigit(*q)) -- { -- ignoreit = 1; -- } -- } -- if (ignoreit || (q - p != 15)) { -+ PRBool is_compressed = PR_FALSE; -+ -+ /* Skip the '.' to get the timestamp portion */ -+ p++; -+ if (!log__validate_rotated_logname(p, &is_compressed)) { - continue; - } - logp = (struct logfileinfo *)slapi_ch_malloc(sizeof(struct logfileinfo)); - logp->l_ctime = log_reverse_convert_time(p); -- logp->l_compressed = PR_FALSE; -- if (strcmp(p + strlen(p) - 3, ".gz") == 0) { -- logp->l_compressed = PR_TRUE; -- } -+ logp->l_compressed = is_compressed; - PR_snprintf(rotated_log, rotated_log_len, "%s/%s", - logsdir, dirent->name); - -@@ -5098,23 +5131,15 @@ log__check_prevlogs(FILE *fp, char *pathname) - for (dirent = PR_ReadDir(dirptr, dirflags); dirent; - dirent = PR_ReadDir(dirptr, dirflags)) { - if (0 == strncmp(log_type, dirent->name, strlen(log_type)) && -- (p = strrchr(dirent->name, '.')) != NULL && -- NULL != strchr(p, '-')) { /* e.g., errors.20051123-165135 */ -- char *q; -- int ignoreit = 0; -- -- for (q = ++p; q && *q; q++) { -- if (*q != '-' && -- *q != '.' && /* .gz */ -- *q != 'g' && -- *q != 'z' && -- !isdigit(*q)) -- { -- ignoreit = 1; -- } -- } -- if (ignoreit || (q - p != 15)) -+ (p = strchr(dirent->name, '.')) != NULL && -+ NULL != strchr(p, '-')) { /* e.g., errors.20051123-165135 or errors.20051123-165135.gz */ -+ PRBool is_compressed = PR_FALSE; -+ -+ /* Skip the '.' to get the timestamp portion */ -+ p++; -+ if (!log__validate_rotated_logname(p, &is_compressed)) { - continue; -+ } - - fseek(fp, 0, SEEK_SET); - buf[BUFSIZ - 1] = '\0'; --- -2.52.0 - diff --git a/0006-Issue-Revise-paged-result-search-locking.patch b/0002-Issue-Revise-paged-result-search-locking.patch similarity index 99% rename from 0006-Issue-Revise-paged-result-search-locking.patch rename to 0002-Issue-Revise-paged-result-search-locking.patch index 10e7dd5..e27ced3 100644 --- a/0006-Issue-Revise-paged-result-search-locking.patch +++ b/0002-Issue-Revise-paged-result-search-locking.patch @@ -1,4 +1,4 @@ -From 6f3bf5a48d504646751be9e91293487eec972ed8 Mon Sep 17 00:00:00 2001 +From 446bc42e7b64a8496c2c3fe486f86bba318bed5e Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Wed, 7 Jan 2026 16:55:27 -0500 Subject: [PATCH] Issue - Revise paged result search locking @@ -684,10 +684,10 @@ index 941ab97e3..0d6c4a1aa 100644 int rc = -1; Connection *conn = NULL; diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h -index 6af6583a5..8445670d2 100644 +index 765c12bf5..455d6d718 100644 --- a/ldap/servers/slapd/proto-slap.h +++ b/ldap/servers/slapd/proto-slap.h -@@ -1611,20 +1611,22 @@ pthread_mutex_t *pageresult_lock_get_addr(Connection *conn); +@@ -1614,20 +1614,22 @@ pthread_mutex_t *pageresult_lock_get_addr(Connection *conn); int pagedresults_parse_control_value(Slapi_PBlock *pb, struct berval *psbvp, ber_int_t *pagesize, int *index, Slapi_Backend *be); void pagedresults_set_response_control(Slapi_PBlock *pb, int iscritical, ber_int_t estimate, int curr_search_count, int index); Slapi_Backend *pagedresults_get_current_be(Connection *conn, int index); @@ -717,7 +717,7 @@ index 6af6583a5..8445670d2 100644 int pagedresults_get_unindexed(Connection *conn, Operation *op, int index); int pagedresults_set_unindexed(Connection *conn, Operation *op, int index); int pagedresults_get_sort_result_code(Connection *conn, Operation *op, int index); -@@ -1636,15 +1638,13 @@ int pagedresults_cleanup(Connection *conn, int needlock); +@@ -1639,15 +1641,13 @@ int pagedresults_cleanup(Connection *conn, int needlock); int pagedresults_is_timedout_nolock(Connection *conn); int pagedresults_reset_timedout_nolock(Connection *conn); int pagedresults_in_use_nolock(Connection *conn); @@ -738,7 +738,7 @@ index 6af6583a5..8445670d2 100644 /* * sort.c diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index 49cfb4210..abb0d2e47 100644 +index 11c5602e3..d494931c2 100644 --- a/ldap/servers/slapd/slap.h +++ b/ldap/servers/slapd/slap.h @@ -89,6 +89,10 @@ static char ptokPBE[34] = "Internal (Software) Token "; diff --git a/0002-Sync-lib389-version-to-3.1.4-7161.patch b/0002-Sync-lib389-version-to-3.1.4-7161.patch deleted file mode 100644 index 08d7c94..0000000 --- a/0002-Sync-lib389-version-to-3.1.4-7161.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 3b133a5ed6fa89939a569fe6130b325726f4e50c Mon Sep 17 00:00:00 2001 -From: Stanislav Levin -Date: Fri, 19 Dec 2025 14:52:48 +0300 -Subject: [PATCH] Sync lib389 version to 3.1.4 (#7161) - -Prepared with: -$ python3 validate_version.py --update -ERROR: Version mismatch detected! -Main project version: 3.1.4 -lib389 version: 3.1.3 -SUCCESS: Updated lib389 version to 3.1.4 in pyproject.toml - -Fixes: https://github.com/389ds/389-ds-base/issues/7160 - -Reviewed by: @progier (Thanks!) - -Signed-off-by: Stanislav Levin ---- - src/lib389/pyproject.toml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib389/pyproject.toml b/src/lib389/pyproject.toml -index 1cd840713..85c0c5141 100644 ---- a/src/lib389/pyproject.toml -+++ b/src/lib389/pyproject.toml -@@ -16,7 +16,7 @@ build-backend = "setuptools.build_meta" - - [project] - name = "lib389" --version = "3.1.3" # Should match the main 389-ds-base version -+version = "3.1.4" # Should match the main 389-ds-base version - description = "A library for accessing, testing, and configuring the 389 Directory Server" - readme = "README.md" - license = {text = "GPL-3.0-or-later"} --- -2.52.0 - diff --git a/0007-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch b/0003-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch similarity index 99% rename from 0007-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch rename to 0003-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch index 3935e95..bb2127c 100644 --- a/0007-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch +++ b/0003-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch @@ -1,4 +1,4 @@ -From cde999edf7246d9dcec4a13950e2c0895165a16e Mon Sep 17 00:00:00 2001 +From 4936f953fa3b0726c2b178f135cd78dcac7463ba Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Thu, 8 Jan 2026 10:02:39 -0800 Subject: [PATCH] Issue 7108 - Fix shutdown crash in entry cache destruction diff --git a/0003-Issue-7166-db_config_set-asserts-because-of-dynamic-.patch b/0003-Issue-7166-db_config_set-asserts-because-of-dynamic-.patch deleted file mode 100644 index cf571ba..0000000 --- a/0003-Issue-7166-db_config_set-asserts-because-of-dynamic-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 9adaeba848a5b0fbe5d3a6148736f6c2ae940c35 Mon Sep 17 00:00:00 2001 -From: progier389 -Date: Mon, 5 Jan 2026 14:38:38 +0100 -Subject: [PATCH] Issue 7166 - db_config_set asserts because of dynamic list - (#7167) - -Avoid assertion in db_config_set when args does not contains dynamic list attributes - -Issue: #7166 - -Reviewed by: @tbordaz (Thanks!) - -(cherry picked from commit 5f15223280002803a932187c22b10beaeaa74bc2) ---- - src/lib389/lib389/cli_conf/backend.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py -index 677b37fcb..d0ec4bd9e 100644 ---- a/src/lib389/lib389/cli_conf/backend.py -+++ b/src/lib389/lib389/cli_conf/backend.py -@@ -544,7 +544,7 @@ def db_config_set(inst, basedn, log, args): - did_something = False - replace_list = [] - -- if args.enable_dynamic_lists and args.disable_dynamic_lists: -+ if getattr(args,'enable_dynamic_lists', None) and getattr(args, 'disable_dynamic_lists', None): - raise ValueError("You can not enable and disable dynamic lists at the same time") - - for attr, value in list(attrs.items()): --- -2.52.0 - diff --git a/0004-Issue-7160-Add-lib389-version-sync-check-to-configur.patch b/0004-Issue-7160-Add-lib389-version-sync-check-to-configur.patch deleted file mode 100644 index 2367d6a..0000000 --- a/0004-Issue-7160-Add-lib389-version-sync-check-to-configur.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 7693d5335c498de1dbb783042cc4acec0138e44d Mon Sep 17 00:00:00 2001 -From: Simon Pichugin -Date: Mon, 5 Jan 2026 18:32:52 -0800 -Subject: [PATCH] Issue 7160 - Add lib389 version sync check to configure - (#7165) - -Description: Add version validation during configure that ensures -lib389 version in pyproject.toml matches the main project version -in VERSION.sh. Configure fails with clear error message and fix -instructions when versions mismatch, preventing inconsistent releases. - -Fixes: https://github.com/389ds/389-ds-base/issues/7160 - -Reviewed by: @progier389 (Thanks!) ---- - configure.ac | 25 +++++++++++++++++++++++++ - 1 file changed, 25 insertions(+) - -diff --git a/configure.ac b/configure.ac -index e94f72647..7fd061a8c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -7,6 +7,31 @@ AC_CONFIG_HEADERS([config.h]) - # include the version information - . $srcdir/VERSION.sh - AC_MSG_NOTICE(This is configure for $PACKAGE_TARNAME $PACKAGE_VERSION) -+ -+# Validate lib389 version matches main project version -+AC_MSG_CHECKING([lib389 version sync]) -+lib389_pyproject="$srcdir/src/lib389/pyproject.toml" -+if test -f "$lib389_pyproject"; then -+ lib389_version=$(grep -E '^version\s*=' "$lib389_pyproject" | sed 's/.*"\(.*\)".*/\1/') -+ if test "x$lib389_version" != "x$RPM_VERSION"; then -+ AC_MSG_RESULT([MISMATCH]) -+ AC_MSG_ERROR([ -+lib389 version mismatch detected! -+ Main project version (VERSION.sh): $RPM_VERSION -+ lib389 version (pyproject.toml): $lib389_version -+ -+To fix this, run: -+ cd $srcdir/src/lib389 && python3 validate_version.py --update -+ -+lib389 version MUST match the main project version before release. -+]) -+ else -+ AC_MSG_RESULT([ok ($lib389_version)]) -+ fi -+else -+ AC_MSG_RESULT([MISSING]) -+ AC_MSG_ERROR([lib389 pyproject.toml not found at $lib389_pyproject - source tree is incomplete]) -+fi - AM_INIT_AUTOMAKE([1.9 foreign subdir-objects dist-bzip2 no-dist-gzip no-define tar-pax]) - AC_SUBST([RPM_VERSION]) - AC_SUBST([RPM_RELEASE]) --- -2.52.0 - diff --git a/0008-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch b/0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch similarity index 99% rename from 0008-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch rename to 0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch index 038c6c3..2ea800b 100644 --- a/0008-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch +++ b/0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch @@ -1,4 +1,4 @@ -From 062aa6eab12d00adffa4e46d58722f6c0e5eeac1 Mon Sep 17 00:00:00 2001 +From 742c12e0247ab64e87da000a4de2f3e5c99044ab Mon Sep 17 00:00:00 2001 From: Viktor Ashirov Date: Fri, 9 Jan 2026 11:39:50 +0100 Subject: [PATCH] Issue 7172 - Index ordering mismatch after upgrade (#7173) diff --git a/0009-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch b/0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch similarity index 95% rename from 0009-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch rename to 0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch index 442fb27..591d144 100644 --- a/0009-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch +++ b/0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch @@ -1,7 +1,7 @@ -From 6bce8f6e8c985289c4ac1a4f051c291283c0a1ec Mon Sep 17 00:00:00 2001 +From f5de84e309d5a4435198c9cc9b31b5722979f1ff Mon Sep 17 00:00:00 2001 From: Viktor Ashirov Date: Mon, 12 Jan 2026 10:58:02 +0100 -Subject: [PATCH 9/9] Issue 7172 - (2nd) Index ordering mismatch after upgrade +Subject: [PATCH 5/5] Issue 7172 - (2nd) Index ordering mismatch after upgrade (#7180) Commit 742c12e0247ab64e87da000a4de2f3e5c99044ab introduced a regression diff --git a/389-ds-base.spec b/389-ds-base.spec index 5e0b930..e864a88 100644 --- a/389-ds-base.spec +++ b/389-ds-base.spec @@ -75,7 +75,7 @@ ExcludeArch: i686 Summary: 389 Directory Server (%{variant}) Name: 389-ds-base -Version: 3.1.4 +Version: 3.2.0 Release: %{autorelease -n %{?with_asan:-e asan}}%{?dist} License: GPL-3.0-or-later WITH GPL-3.0-389-ds-base-exception AND (0BSD OR Apache-2.0 OR MIT) AND (Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT) AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR LGPL-2.1-or-later OR MIT) AND (Apache-2.0 OR MIT OR Zlib) AND (Apache-2.0 OR MIT) AND (CC-BY-4.0 AND MIT) AND (MIT OR Apache-2.0) AND Unicode-3.0 AND (MIT OR CC0-1.0) AND (MIT OR Unlicense) AND 0BSD AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND MIT AND MIT AND ISC AND MPL-2.0 AND PSF-2.0 AND Zlib URL: https://www.port389.org @@ -504,21 +504,18 @@ Source0: https://github.com/389ds/%{name}/releases/download/%{name}-%{v Source2: %{name}-devel.README %if %{with bundle_jemalloc} Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download/%{jemalloc_ver}/%{jemalloc_name}-%{jemalloc_ver}.tar.bz2 +Source6: jemalloc-5.3.0_throw_bad_alloc.patch %endif Source4: 389-ds-base.sysusers %if %{with bundle_libdb} Source5: https://fedorapeople.org/groups/389ds/libdb-5.3.28-59.tar.bz2 %endif -Patch: 0001-Issue-7150-Compressed-access-log-rotations-skipped-a.patch -Patch: 0002-Sync-lib389-version-to-3.1.4-7161.patch -Patch: 0003-Issue-7166-db_config_set-asserts-because-of-dynamic-.patch -Patch: 0004-Issue-7160-Add-lib389-version-sync-check-to-configur.patch -Patch: 0005-Issue-7096-During-replication-online-total-init-the-.patch -Patch: 0006-Issue-Revise-paged-result-search-locking.patch -Patch: 0007-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch -Patch: 0008-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch -Patch: 0009-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch +Patch: 0001-Issue-7096-During-replication-online-total-init-the-.patch +Patch: 0002-Issue-Revise-paged-result-search-locking.patch +Patch: 0003-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch +Patch: 0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch +Patch: 0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch %description 389 Directory Server is an LDAPv3 compliant server. The base package includes @@ -715,6 +712,7 @@ COCKPIT_FLAGS="--disable-cockpit" # Build jemalloc pushd ../%{jemalloc_name}-%{jemalloc_ver} +patch -p1 -F3 < %{SOURCE6} %configure \ --libdir=%{_libdir}/%{pkgname}/lib \ --bindir=%{_libdir}/%{pkgname}/bin \ diff --git a/jemalloc-5.3.0_throw_bad_alloc.patch b/jemalloc-5.3.0_throw_bad_alloc.patch new file mode 100644 index 0000000..94e4d36 --- /dev/null +++ b/jemalloc-5.3.0_throw_bad_alloc.patch @@ -0,0 +1,41 @@ +#commit 3de0c24859f4413bf03448249078169bb50bda0f +#Author: divanorama +#Date: Thu Sep 29 23:35:59 2022 +0200 +# +# Disable builtin malloc in tests +# +# With `--with-jemalloc-prefix=` and without `-fno-builtin` or `-O1` both clang and gcc may optimize out `malloc` calls +# whose result is unused. Comparing result to NULL also doesn't necessarily count as being used. +# +# This won't be a problem in most client programs as this only concerns really unused pointers, but in +# tests it's important to actually execute allocations. +# `-fno-builtin` should disable this optimization for both gcc and clang, and applying it only to tests code shouldn't hopefully be an issue. +# Another alternative is to force "use" of result but that'd require more changes and may miss some other optimization-related issues. +# +# This should resolve https://github.com/jemalloc/jemalloc/issues/2091 +# +#diff --git a/Makefile.in b/Makefile.in +#index 6809fb29..a964f07e 100644 +#--- a/Makefile.in +#+++ b/Makefile.in +#@@ -458,6 +458,8 @@ $(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c +# $(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp +# $(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include +# $(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include +#+$(TESTS_OBJS): CFLAGS += -fno-builtin +#+$(TESTS_CPP_OBJS): CPPFLAGS += -fno-builtin +# ifneq ($(IMPORTLIB),$(SO)) +# $(CPP_OBJS) $(C_SYM_OBJS) $(C_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT +# endif +diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp +index fffd6aee..5a682991 100644 +--- a/src/jemalloc_cpp.cpp ++++ b/src/jemalloc_cpp.cpp +@@ -93,7 +93,7 @@ handleOOM(std::size_t size, bool nothrow) { + } + + if (ptr == nullptr && !nothrow) +- std::__throw_bad_alloc(); ++ throw std::bad_alloc(); + return ptr; + } diff --git a/sources b/sources index d1563dc..7004305 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ SHA512 (jemalloc-5.3.0.tar.bz2) = 22907bb052096e2caffb6e4e23548aecc5cc9283dce476896a2b1127eee64170e3562fa2e7db9571298814a7a2c7df6e8d1fbe152bd3f3b0c1abec22a2de34b1 SHA512 (libdb-5.3.28-59.tar.bz2) = 731a434fa2e6487ebb05c458b0437456eb9f7991284beb08cb3e21931e23bdeddddbc95bfabe3a2f9f029fe69cd33a2d4f0f5ce6a9811e9c3b940cb6fde4bf79 -SHA512 (389-ds-base-3.1.4.tar.bz2) = 17de77a02c848dbb8d364e7bab529726b4c32e466f47d5c2a5bba8d8b55e2a56e2b743a2efa4f820c935b39f770a621146a42443e4f171f8b14c68968155ee2c +SHA512 (389-ds-base-3.2.0.tar.bz2) = 9ff6aa56b30863c619f4f324344dca72cc883236bfe8d94520e8469d9e306f54b373ee2504eda18dcb0ecda33f915a3e64a6f3cdaa93a69b74d901caa48545e1