|
|
a26cad |
From 3b3faee01e645577ad77ff4f38429a9e0806231b Mon Sep 17 00:00:00 2001
|
|
|
a26cad |
From: Simon Pichugin <simon.pichugin@gmail.com>
|
|
|
a26cad |
Date: Tue, 16 Jun 2020 20:35:05 +0200
|
|
|
a26cad |
Subject: [PATCH] Issue 51157 - Reindex task may create abandoned index file
|
|
|
a26cad |
|
|
|
a26cad |
Bug Description: Recreating an index for the same attribute but changing
|
|
|
a26cad |
the case of for example 1 letter, results in abandoned indexfile.
|
|
|
a26cad |
|
|
|
a26cad |
Fix Decsription: Add a test case to a newly created 'indexes' test suite.
|
|
|
a26cad |
When we remove the index config from the backend, - remove the attribute
|
|
|
a26cad |
info from LDBM instance attributes.
|
|
|
a26cad |
|
|
|
a26cad |
https://pagure.io/389-ds-base/issue/51157
|
|
|
a26cad |
|
|
|
a26cad |
Reviewed by: firstyear, mreynolds (Thanks!)
|
|
|
a26cad |
---
|
|
|
a26cad |
dirsrvtests/tests/suites/indexes/__init__.py | 3 +
|
|
|
a26cad |
.../tests/suites/indexes/regression_test.py | 125 ++++++++++++++++++
|
|
|
a26cad |
ldap/servers/slapd/back-ldbm/ldbm_attr.c | 7 +
|
|
|
a26cad |
.../slapd/back-ldbm/ldbm_index_config.c | 3 +
|
|
|
a26cad |
.../servers/slapd/back-ldbm/proto-back-ldbm.h | 1 +
|
|
|
a26cad |
5 files changed, 139 insertions(+)
|
|
|
a26cad |
create mode 100644 dirsrvtests/tests/suites/indexes/__init__.py
|
|
|
a26cad |
create mode 100644 dirsrvtests/tests/suites/indexes/regression_test.py
|
|
|
a26cad |
|
|
|
a26cad |
diff --git a/dirsrvtests/tests/suites/indexes/__init__.py b/dirsrvtests/tests/suites/indexes/__init__.py
|
|
|
a26cad |
new file mode 100644
|
|
|
a26cad |
index 000000000..04441667e
|
|
|
a26cad |
--- /dev/null
|
|
|
a26cad |
+++ b/dirsrvtests/tests/suites/indexes/__init__.py
|
|
|
a26cad |
@@ -0,0 +1,3 @@
|
|
|
a26cad |
+"""
|
|
|
a26cad |
+ :Requirement: 389-ds-base: Indexes
|
|
|
a26cad |
+"""
|
|
|
a26cad |
diff --git a/dirsrvtests/tests/suites/indexes/regression_test.py b/dirsrvtests/tests/suites/indexes/regression_test.py
|
|
|
a26cad |
new file mode 100644
|
|
|
a26cad |
index 000000000..1a71f16e9
|
|
|
a26cad |
--- /dev/null
|
|
|
a26cad |
+++ b/dirsrvtests/tests/suites/indexes/regression_test.py
|
|
|
a26cad |
@@ -0,0 +1,125 @@
|
|
|
a26cad |
+# --- BEGIN COPYRIGHT BLOCK ---
|
|
|
a26cad |
+# Copyright (C) 2020 Red Hat, Inc.
|
|
|
a26cad |
+# All rights reserved.
|
|
|
a26cad |
+#
|
|
|
a26cad |
+# License: GPL (version 3 or any later version).
|
|
|
a26cad |
+# See LICENSE for details.
|
|
|
a26cad |
+# --- END COPYRIGHT BLOCK ---
|
|
|
a26cad |
+#
|
|
|
a26cad |
+import time
|
|
|
a26cad |
+import os
|
|
|
a26cad |
+import pytest
|
|
|
a26cad |
+import ldap
|
|
|
a26cad |
+from lib389._constants import DEFAULT_BENAME, DEFAULT_SUFFIX
|
|
|
a26cad |
+from lib389.index import Indexes
|
|
|
a26cad |
+from lib389.backend import Backends
|
|
|
a26cad |
+from lib389.idm.user import UserAccounts
|
|
|
a26cad |
+from lib389.topologies import topology_st as topo
|
|
|
a26cad |
+
|
|
|
a26cad |
+pytestmark = pytest.mark.tier1
|
|
|
a26cad |
+
|
|
|
a26cad |
+
|
|
|
a26cad |
+def test_reindex_task_creates_abandoned_index_file(topo):
|
|
|
a26cad |
+ """
|
|
|
a26cad |
+ Recreating an index for the same attribute but changing
|
|
|
a26cad |
+ the case of for example 1 letter, results in abandoned indexfile
|
|
|
a26cad |
+
|
|
|
a26cad |
+ :id: 07ae5274-481a-4fa8-8074-e0de50d89ac6
|
|
|
a26cad |
+ :setup: Standalone instance
|
|
|
a26cad |
+ :steps:
|
|
|
a26cad |
+ 1. Create a user object with additional attributes:
|
|
|
a26cad |
+ objectClass: mozillaabpersonalpha
|
|
|
a26cad |
+ mozillaCustom1: xyz
|
|
|
a26cad |
+ 2. Add an index entry mozillacustom1
|
|
|
a26cad |
+ 3. Reindex the backend
|
|
|
a26cad |
+ 4. Check the content of the index (after it has been flushed to disk) mozillacustom1.db
|
|
|
a26cad |
+ 5. Remove the index
|
|
|
a26cad |
+ 6. Notice the mozillacustom1.db is removed
|
|
|
a26cad |
+ 7. Recreate the index but now use the exact case as mentioned in the schema
|
|
|
a26cad |
+ 8. Reindex the backend
|
|
|
a26cad |
+ 9. Check the content of the index (after it has been flushed to disk) mozillaCustom1.db
|
|
|
a26cad |
+ 10. Check that an ldapsearch does not return a result (mozillacustom1=xyz)
|
|
|
a26cad |
+ 11. Check that an ldapsearch returns the results (mozillaCustom1=xyz)
|
|
|
a26cad |
+ 12. Restart the instance
|
|
|
a26cad |
+ 13. Notice that an ldapsearch does not return a result(mozillacustom1=xyz)
|
|
|
a26cad |
+ 15. Check that an ldapsearch does not return a result (mozillacustom1=xyz)
|
|
|
a26cad |
+ 16. Check that an ldapsearch returns the results (mozillaCustom1=xyz)
|
|
|
a26cad |
+ 17. Reindex the backend
|
|
|
a26cad |
+ 18. Notice the second indexfile for this attribute
|
|
|
a26cad |
+ 19. Check the content of the index (after it has been flushed to disk) no mozillacustom1.db
|
|
|
a26cad |
+ 20. Check the content of the index (after it has been flushed to disk) mozillaCustom1.db
|
|
|
a26cad |
+ :expectedresults:
|
|
|
a26cad |
+ 1. Should Success.
|
|
|
a26cad |
+ 2. Should Success.
|
|
|
a26cad |
+ 3. Should Success.
|
|
|
a26cad |
+ 4. Should Success.
|
|
|
a26cad |
+ 5. Should Success.
|
|
|
a26cad |
+ 6. Should Success.
|
|
|
a26cad |
+ 7. Should Success.
|
|
|
a26cad |
+ 8. Should Success.
|
|
|
a26cad |
+ 9. Should Success.
|
|
|
a26cad |
+ 10. Should Success.
|
|
|
a26cad |
+ 11. Should Success.
|
|
|
a26cad |
+ 12. Should Success.
|
|
|
a26cad |
+ 13. Should Success.
|
|
|
a26cad |
+ 14. Should Success.
|
|
|
a26cad |
+ 15. Should Success.
|
|
|
a26cad |
+ 16. Should Success.
|
|
|
a26cad |
+ 17. Should Success.
|
|
|
a26cad |
+ 18. Should Success.
|
|
|
a26cad |
+ 19. Should Success.
|
|
|
a26cad |
+ 20. Should Success.
|
|
|
a26cad |
+ """
|
|
|
a26cad |
+
|
|
|
a26cad |
+ inst = topo.standalone
|
|
|
a26cad |
+ attr_name = "mozillaCustom1"
|
|
|
a26cad |
+ attr_value = "xyz"
|
|
|
a26cad |
+
|
|
|
a26cad |
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
|
|
a26cad |
+ user = users.create_test_user()
|
|
|
a26cad |
+ user.add("objectClass", "mozillaabpersonalpha")
|
|
|
a26cad |
+ user.add(attr_name, attr_value)
|
|
|
a26cad |
+
|
|
|
a26cad |
+ backends = Backends(inst)
|
|
|
a26cad |
+ backend = backends.get(DEFAULT_BENAME)
|
|
|
a26cad |
+ indexes = backend.get_indexes()
|
|
|
a26cad |
+ index = indexes.create(properties={
|
|
|
a26cad |
+ 'cn': attr_name.lower(),
|
|
|
a26cad |
+ 'nsSystemIndex': 'false',
|
|
|
a26cad |
+ 'nsIndexType': ['eq', 'pres']
|
|
|
a26cad |
+ })
|
|
|
a26cad |
+
|
|
|
a26cad |
+ backend.reindex()
|
|
|
a26cad |
+ time.sleep(3)
|
|
|
a26cad |
+ assert os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db")
|
|
|
a26cad |
+ index.delete()
|
|
|
a26cad |
+ assert not os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db")
|
|
|
a26cad |
+
|
|
|
a26cad |
+ index = indexes.create(properties={
|
|
|
a26cad |
+ 'cn': attr_name,
|
|
|
a26cad |
+ 'nsSystemIndex': 'false',
|
|
|
a26cad |
+ 'nsIndexType': ['eq', 'pres']
|
|
|
a26cad |
+ })
|
|
|
a26cad |
+
|
|
|
a26cad |
+ backend.reindex()
|
|
|
a26cad |
+ time.sleep(3)
|
|
|
a26cad |
+ assert not os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db")
|
|
|
a26cad |
+ assert os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name}.db")
|
|
|
a26cad |
+
|
|
|
a26cad |
+ entries = inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f"{attr_name}={attr_value}")
|
|
|
a26cad |
+ assert len(entries) > 0
|
|
|
a26cad |
+ inst.restart()
|
|
|
a26cad |
+ entries = inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f"{attr_name}={attr_value}")
|
|
|
a26cad |
+ assert len(entries) > 0
|
|
|
a26cad |
+
|
|
|
a26cad |
+ backend.reindex()
|
|
|
a26cad |
+ time.sleep(3)
|
|
|
a26cad |
+ assert not os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db")
|
|
|
a26cad |
+ assert os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name}.db")
|
|
|
a26cad |
+
|
|
|
a26cad |
+
|
|
|
a26cad |
+if __name__ == "__main__":
|
|
|
a26cad |
+ # Run isolated
|
|
|
a26cad |
+ # -s for DEBUG mode
|
|
|
a26cad |
+ CURRENT_FILE = os.path.realpath(__file__)
|
|
|
a26cad |
+ pytest.main("-s %s" % CURRENT_FILE)
|
|
|
a26cad |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
|
|
|
a26cad |
index f0d418572..688c4f137 100644
|
|
|
a26cad |
--- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c
|
|
|
a26cad |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
|
|
|
a26cad |
@@ -98,6 +98,13 @@ ainfo_cmp(
|
|
|
a26cad |
return (strcasecmp(a->ai_type, b->ai_type));
|
|
|
a26cad |
}
|
|
|
a26cad |
|
|
|
a26cad |
+void
|
|
|
a26cad |
+attrinfo_delete_from_tree(backend *be, struct attrinfo *ai)
|
|
|
a26cad |
+{
|
|
|
a26cad |
+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
|
|
|
a26cad |
+ avl_delete(&inst->inst_attrs, ai, ainfo_cmp);
|
|
|
a26cad |
+}
|
|
|
a26cad |
+
|
|
|
a26cad |
/*
|
|
|
a26cad |
* Called when a duplicate "index" line is encountered.
|
|
|
a26cad |
*
|
|
|
a26cad |
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
|
|
|
a26cad |
index 720f93036..9722d0ce7 100644
|
|
|
a26cad |
--- a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
|
|
|
a26cad |
+++ b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
|
|
|
a26cad |
@@ -201,7 +201,10 @@ ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb,
|
|
|
a26cad |
*returncode = LDAP_UNWILLING_TO_PERFORM;
|
|
|
a26cad |
rc = SLAPI_DSE_CALLBACK_ERROR;
|
|
|
a26cad |
}
|
|
|
a26cad |
+ attrinfo_delete_from_tree(inst->inst_be, ainfo);
|
|
|
a26cad |
}
|
|
|
a26cad |
+ /* Free attrinfo structure */
|
|
|
a26cad |
+ attrinfo_delete(&ainfo);
|
|
|
a26cad |
bail:
|
|
|
a26cad |
return rc;
|
|
|
a26cad |
}
|
|
|
a26cad |
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
|
|
a26cad |
index a07acee5e..4d2524fd9 100644
|
|
|
a26cad |
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
|
|
a26cad |
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
|
|
a26cad |
@@ -21,6 +21,7 @@
|
|
|
a26cad |
*/
|
|
|
a26cad |
struct attrinfo *attrinfo_new(void);
|
|
|
a26cad |
void attrinfo_delete(struct attrinfo **pp);
|
|
|
a26cad |
+void attrinfo_delete_from_tree(backend *be, struct attrinfo *ai);
|
|
|
a26cad |
void ainfo_get(backend *be, char *type, struct attrinfo **at);
|
|
|
a26cad |
void attr_masks(backend *be, char *type, int *indexmask, int *syntaxmask);
|
|
|
a26cad |
void attr_masks_ex(backend *be, char *type, int *indexmask, int *syntaxmask, struct attrinfo **at);
|
|
|
a26cad |
--
|
|
|
a26cad |
2.26.2
|
|
|
a26cad |
|