From 0e7f59d6c22e02a0604e028b878003ac0baf5a1c Mon Sep 17 00:00:00 2001 From: Noriko Hosoi Date: Jan 28 2014 22:20:23 +0000 Subject: Ticket #47463 - IDL-style can become mismatched during partial restoration The commit to 389-ds-base-1.3.2 and newer is back ported to 389-ds- 1.2.11 trough 1.3.1 by Thomas E Lackey. commit b43145218dccc8c9c16ecadad80f94bf58c73d57 Author: Noriko Hosoi Date: Fri Sep 27 17:58:03 2013 -0700 Description by telackey: When doing a partial/FRI restoration the database files are copied key-by-key. This is necessary to reset the LSNs so the restored files can merge into the existing DB environment (cf. dblayer_copy_ file_resetlsns()) in a recoverable way. However, dblayer_copy_file_keybykey() does not set the comparison function before calling DB->put(), which means that the restored files will not necessarily be using the proper function. While all the keys are technically present, indexed searches can still fail to return relevant results because the key order is significant when intersecting the results with the other indices. Note: The bug was reported and the patch was provided by telackey. (Thank you, Thomas!) Additional fix by nhosoi: The entryrdn index uses its special dup compare function. The dup compare function is set when the restoring index file is entryrdn. https://fedorahosted.org/389/ticket/47463 Reviewed by rmeggins (Thank you, Rich!) (cherry picked from commit abe5c894686f46b60f069f8cbd8aa909b34d81a1) (cherry picked from commit 9ebe2e80d090537e8f905ef54990bfdec088e267) --- diff --git a/ldap/servers/slapd/back-ldbm/dbhelp.c b/ldap/servers/slapd/back-ldbm/dbhelp.c index 1165831..b0d17d3 100644 --- a/ldap/servers/slapd/back-ldbm/dbhelp.c +++ b/ldap/servers/slapd/back-ldbm/dbhelp.c @@ -49,7 +49,13 @@ #include "back-ldbm.h" #include "dblayer.h" -static int dblayer_copy_file_keybykey(DB_ENV *env, char *source_file_name, char *destination_file_name, int overwrite, dblayer_private *priv) +static int +dblayer_copy_file_keybykey(DB_ENV *env, + char *source_file_name, + char *destination_file_name, + int overwrite, + dblayer_private *priv, + ldbm_instance *inst) { int retval = 0; int retval_cleanup = 0; @@ -62,6 +68,7 @@ static int dblayer_copy_file_keybykey(DB_ENV *env, char *source_file_name, char int cursor_flag = 0; int finished = 0; int mode = 0; + char *p = NULL; LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_copy_file_keybykey\n", 0, 0, 0 ); @@ -119,6 +126,40 @@ static int dblayer_copy_file_keybykey(DB_ENV *env, char *source_file_name, char LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, set_pagesize error %d: %s\n", retval, db_strerror(retval), 0); goto error; } + + /* TEL 20130412: Make sure to set the dup comparison function if needed. + * We key our decision off of the presence of new IDL and dup flags on + * the source database. This is similar dblayer_open_file, except that + * we don't have the attribute info index mask for VLV. That should be OK + * since the DB_DUP and DB_DUPSORT flags wouldn't have been toggled on + * unless they passed the check on the source. + */ + /* Entryrdn index has its own dup compare function */ + if ((p = PL_strcasestr(source_file_name, LDBM_ENTRYRDN_STR)) && + (*(p + sizeof(LDBM_ENTRYRDN_STR) - 1) == '.')) { + /* entryrdn.db */ + struct attrinfo *ai = NULL; + ainfo_get(inst->inst_be, LDBM_ENTRYRDN_STR, &ai); + if (ai->ai_dup_cmp_fn) { + /* If set, use the special dup compare callback */ + retval = destination_file->set_dup_compare(destination_file, ai->ai_dup_cmp_fn); + if (retval) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "dblayer_copy_file_keybykey(entryrdn), set_dup_compare error %d: %s\n", + retval, db_strerror(retval)); + goto error; + } + } + } else if (idl_get_idl_new() && (dbflags & DB_DUP) && (dbflags & DB_DUPSORT)) { + retval = destination_file->set_dup_compare(destination_file, idl_new_compare_dups); + if (retval) { + LDAPDebug2Args(LDAP_DEBUG_ANY, + "dblayer_copy_file_keybykey, set_dup_compare error %d: %s\n", + retval, db_strerror(retval)); + goto error; + } + } + retval = (destination_file->open)(destination_file, NULL, destination_file_name, NULL, dbtype, DB_CREATE | DB_EXCL, mode); if (retval) { LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Open error %d: %s\n", retval, db_strerror(retval), 0); @@ -190,7 +231,13 @@ error: return retval; } -int dblayer_copy_file_resetlsns(char *home_dir ,char *source_file_name, char *destination_file_name, int overwrite, dblayer_private *priv) +int +dblayer_copy_file_resetlsns(char *home_dir, + char *source_file_name, + char *destination_file_name, + int overwrite, + dblayer_private *priv, + ldbm_instance *inst) { int retval = 0; DB_ENV *env = NULL; @@ -205,7 +252,7 @@ int dblayer_copy_file_resetlsns(char *home_dir ,char *source_file_name, char *de goto out; } /* Do the copy */ - retval = dblayer_copy_file_keybykey(env, source_file_name, destination_file_name, overwrite, priv); + retval = dblayer_copy_file_keybykey(env, source_file_name, destination_file_name, overwrite, priv, inst); if (retval) { LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_resetlsns: Copy not completed successfully.", 0, 0, 0); } diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c index 46334bd..844b3b7 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.c +++ b/ldap/servers/slapd/back-ldbm/dblayer.c @@ -5653,6 +5653,7 @@ dblayer_copy_directory(struct ldbminfo *li, char inst_dir[MAXPATHLEN]; char sep; int suffix_len = 0; + ldbm_instance *inst = NULL; if (!src_dir || '\0' == *src_dir) { @@ -5676,6 +5677,14 @@ dblayer_copy_directory(struct ldbminfo *li, else relative_instance_name++; + inst = ldbm_instance_find_by_name(li, relative_instance_name); + if (NULL == inst) { + LDAPDebug(LDAP_DEBUG_ANY, "Backend instance \"%s\" does not exist; " + "Instance path %s could be invalid.\n", + relative_instance_name, src_dir, 0); + return return_value; + } + if (is_fullpath(src_dir)) { new_src_dir = src_dir; @@ -5683,15 +5692,6 @@ dblayer_copy_directory(struct ldbminfo *li, else { int len; - ldbm_instance *inst = - ldbm_instance_find_by_name(li, relative_instance_name); - if (NULL == inst) - { - LDAPDebug(LDAP_DEBUG_ANY, "Backend instance \"%s\" does not exist; " - "Instance path %s could be invalid.\n", - relative_instance_name, src_dir, 0); - return return_value; - } inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst, inst_dir, MAXPATHLEN); @@ -5811,13 +5811,12 @@ dblayer_copy_directory(struct ldbminfo *li, /* If the file is a database file, and resetlsns is set, then we need to do a key by key copy */ /* PL_strcmp takes NULL arg */ if (resetlsns && - (PL_strcmp(LDBM_FILENAME_SUFFIX, strrchr(filename1, '.')) - == 0)) { + (PL_strcmp(LDBM_FILENAME_SUFFIX, strrchr(filename1, '.')) == 0)) { return_value = dblayer_copy_file_resetlsns(src_dir, filename1, filename2, - 0, priv); + 0, priv, inst); } else { return_value = dblayer_copyfile(filename1, filename2, - 0, priv->dblayer_file_mode); + 0, priv->dblayer_file_mode); } slapi_ch_free((void**)&filename1); slapi_ch_free((void**)&filename2); diff --git a/ldap/servers/slapd/back-ldbm/dblayer.h b/ldap/servers/slapd/back-ldbm/dblayer.h index 7f3200c..4ff9d53 100644 --- a/ldap/servers/slapd/back-ldbm/dblayer.h +++ b/ldap/servers/slapd/back-ldbm/dblayer.h @@ -201,7 +201,7 @@ int dblayer_make_private_simple_env(char *db_home_dir, DB_ENV **env); /* Copy a database file, preserving all its contents (used to reset the LSNs in the file in order to move * it from one transacted environment to another. */ -int dblayer_copy_file_resetlsns(char *home_dir, char *source_file_name, char *destination_file_name, int overwrite, dblayer_private *priv); +int dblayer_copy_file_resetlsns(char *home_dir, char *source_file_name, char *destination_file_name, int overwrite, dblayer_private *priv, ldbm_instance *inst); /* Turn on the various logging and debug options for DB */ void dblayer_set_env_debugging(DB_ENV *pEnv, dblayer_private *priv); diff --git a/ldap/servers/slapd/control.c b/ldap/servers/slapd/control.c index e614d50..e7b7562 100644 --- a/ldap/servers/slapd/control.c +++ b/ldap/servers/slapd/control.c @@ -361,7 +361,7 @@ get_ldapmessage_controls_ext( slapi_pblock_set(pb, SLAPI_MANAGEDSAIT, &ctrl_not_found); slapi_pblock_set(pb, SLAPI_PWPOLICY, &ctrl_not_found); slapi_log_error(SLAPI_LOG_CONNS, "connection", "Warning: conn=%d op=%d contains an empty list of controls\n", - pb->pb_conn->c_connid, pb->pb_op->o_opid); + (int)pb->pb_conn->c_connid, pb->pb_op->o_opid); } else { if ((tag != LBER_END_OF_SEQORSET) && (len != -1)) { goto free_and_return;