summaryrefslogtreecommitdiffstats
path: root/ldap
diff options
context:
space:
mode:
authorDavid Boreham <dboreham@redhat.com>2005-01-28 20:36:06 +0000
committerDavid Boreham <dboreham@redhat.com>2005-01-28 20:36:06 +0000
commitb323e287076458e646831a3b5cec0262ac60c5fd (patch)
treeebce2520494204a3feef95e859b896fa3e8627a6 /ldap
parentd70d772e768245c06466a68fc3f32739692c20cc (diff)
downloadds-b323e287076458e646831a3b5cec0262ac60c5fd.tar.gz
ds-b323e287076458e646831a3b5cec0262ac60c5fd.tar.xz
ds-b323e287076458e646831a3b5cec0262ac60c5fd.zip
Add support for filesystem-based replica initialization.
Diffstat (limited to 'ldap')
-rw-r--r--ldap/admin/src/create_instance.c69
-rw-r--r--ldap/admin/src/scripts/template-bak2db.pl14
-rw-r--r--ldap/servers/slapd/back-ldbm/Makefile3
-rw-r--r--ldap/servers/slapd/back-ldbm/archive.c4
-rw-r--r--ldap/servers/slapd/back-ldbm/dbhelp.c271
-rw-r--r--ldap/servers/slapd/back-ldbm/dblayer.c426
-rw-r--r--ldap/servers/slapd/back-ldbm/dblayer.h18
-rw-r--r--ldap/servers/slapd/back-ldbm/dbversion.c13
-rw-r--r--ldap/servers/slapd/back-ldbm/import-threads.c62
-rw-r--r--ldap/servers/slapd/back-ldbm/ldif2ldbm.c4
-rw-r--r--ldap/servers/slapd/back-ldbm/proto-back-ldbm.h6
-rw-r--r--ldap/servers/slapd/task.c7
12 files changed, 796 insertions, 101 deletions
diff --git a/ldap/admin/src/create_instance.c b/ldap/admin/src/create_instance.c
index 12188128..26b276b6 100644
--- a/ldap/admin/src/create_instance.c
+++ b/ldap/admin/src/create_instance.c
@@ -2398,18 +2398,31 @@ char *ds_gen_scripts(char *sroot, server_config_s *cf, char *cs_path)
if(t) return t;
t = gen_script(cs_path, "bak2db",
- "if [ \"$#\" -ne 1 ]\nthen\n"
- " echo \"Usage: bak2db archivedir\"\n"
- " exit 1\nfi\n\n"
- "if [ 1 = `expr $1 : \"\\/\"` ]\nthen\n"
- " archivedir=$1\n"
+ "if [ $# -lt 1 ] || [ $# -gt 3 ]\nthen\n"
+ " echo \"Usage: bak2db archivedir [-n backendname]\"\n"
+ " exit 1\n"
+ "else\n"
+ " archivedir=$1\n"
+ " shift\n"
+ "fi\n"
+ "while getopts \"n:\" flag\ndo\n"
+ " case $flag in\n"
+ " n) bename=$OPTARG;;\n"
+ " *) echo \"Usage: bak2db archivedir [-n backendname]\"; exit 2;;\n"
+ " esac\n"
+ "done\n\n"
+ "if [ 1 = `expr $archivedir : \"\\/\"` ]\nthen\n"
+ " archivedir=$archivedir\n"
"else\n"
" # relative\n"
- " cwd=`pwd`\n"
- " archivedir=`echo $cwd/$1`\nfi\n\n"
+ " archivedir=`pwd`/$archivedir\nfi\n\n"
"cd %s\n"
- "./ns-slapd archive2db -D %s -a $archivedir\n",
- server, cs_path);
+ "if [ \"$#\" -eq 2 ]\nthen\n"
+ " ./ns-slapd archive2db -D %s -a $archivedir -n $bename\n"
+ "else\n"
+ " ./ns-slapd archive2db -D %s -a $archivedir\n"
+ "fi\n",
+ server, cs_path, cs_path);
if(t) return t;
t = CREATE_BAK2DB();
@@ -2941,20 +2954,38 @@ char *ds_gen_scripts(char *sroot, server_config_s *cf, char *cs_path)
if(t) return t;
t = gen_script(cs_path, "bak2db.bat",
- "@echo off\n"
- "setlocal\n\n"
- "set rc=0\n"
- "if [%%1] == [] goto usage\n\n"
- "\"%s\\slapd\" archive2db -D \"%s\" -a %%1\n"
- "set rc=%%errorlevel%%\n"
- "goto done\n\n"
+ "@echo off\n"
+ "pushd & setlocal\n\n"
+ "if [%%1] == [] (goto :usage)\n"
+ "if not [%%4] == [] (goto :usage)\n\n"
+ "set archivedir=%%1\n"
+ "set rc=0\n\n"
+ ":getopts\n"
+ "shift\n"
+ "if [%%1]==[] (goto :main)\n"
+ "if [%%1]==[-n] (if not [%%2]==[] (set bename=%%2) else (goto :usage)) else (goto :getopts)\n\n"
+ ":main\n"
+ "call :relative %%archivedir%%\n"
+ "if defined bename (\n"
+ "\"%s\\slapd\" archive2db -D \"%s\" -a %%archivedir%% -n %%bename%%\n"
+ ") else (\n"
+ "\"%s\\slapd\" archive2db -D \"%s\" -a %%archivedir%%\n"
+ ")\n"
+ "set rc=%%ERRORLEVEL%%\n"
+ "popd\n"
+ "goto :done\n\n"
+ "goto :EOF\n"
":usage\n"
- "echo \"Usage: bak2db -a archivedir\"\n\n"
- "set rc=1\n"
+ "echo %%0 archivedir [-n backendname]\n"
+ "goto :done\n\n"
+ "goto :EOF\n"
+ ":relative\n"
+ "set archivedir=%%~f1\n\n"
+ "goto :EOF\n"
":done\n"
"if defined MKSARGS exit %%rc%%\n"
"exit /b %%rc%%\n",
- server, cs_path);
+ server, cs_path, server, cs_path);
if(t) return t;
#if defined(UPGRADEDB)
diff --git a/ldap/admin/src/scripts/template-bak2db.pl b/ldap/admin/src/scripts/template-bak2db.pl
index 10cb99bc..cdb51c74 100644
--- a/ldap/admin/src/scripts/template-bak2db.pl
+++ b/ldap/admin/src/scripts/template-bak2db.pl
@@ -16,11 +16,13 @@ sub usage {
print(STDERR " : -j filename - Read Directory Manager's password from file\n");
print(STDERR " : -a dirname - backup directory\n");
print(STDERR " : -t dbtype - database type (default: ldbm database)\n");
+ print(STDERR " : -n backend - name of backend instance to restore\n");
print(STDERR " : -v - verbose\n");
}
$taskname = "";
$archivedir = "";
$dbtype = "ldbm database";
+$instance = "";
$dsroot = "{{DS-ROOT}}";
$mydsroot = "{{MY-DS-ROOT}}";
$verbose = 0;
@@ -39,6 +41,8 @@ while ($i <= $#ARGV) {
$i++; $passwdfile = $ARGV[$i];
} elsif ("$ARGV[$i]" eq "-t") { # database type
$i++; $dbtype = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-n") { # backend instance name
+ $i++; $instance = $ARGV[$i];
} elsif ("$ARGV[$i]" eq "-v") { # verbose
$verbose = 1;
} else {
@@ -75,12 +79,20 @@ $taskname = "restore_${yr}_${mn}_${dy}_${h}_${m}_${s}";
if ($archivedir eq "") {
&usage; exit(1);
}
+use File::Spec;
+$isabs = File::Spec->file_name_is_absolute( $archivedir );
+if (!$isabs) {
+ $archivedir = File::Spec->rel2abs( $archivedir );
+}
$dn = "dn: cn=$taskname, cn=restore, cn=tasks, cn=config\n";
$misc = "changetype: add\nobjectclass: top\nobjectclass: extensibleObject\n";
$cn = "cn: $taskname\n";
+if ($instance ne "") {
+ $nsinstance = "nsInstance: ${instance}\n";
+}
$nsarchivedir = "nsArchiveDir: $archivedir\n";
$nsdbtype = "nsDatabaseType: $dbtype\n";
-$entry = "${dn}${misc}${cn}${nsarchivedir}${nsdbtype}";
+$entry = "${dn}${misc}${cn}${nsinstance}${nsarchivedir}${nsdbtype}";
$vstr = "";
if ($verbose != 0) { $vstr = "-v"; }
chdir("$dsroot{{SEP}}shared{{SEP}}bin");
diff --git a/ldap/servers/slapd/back-ldbm/Makefile b/ldap/servers/slapd/back-ldbm/Makefile
index c86ec0b3..f570d7e3 100644
--- a/ldap/servers/slapd/back-ldbm/Makefile
+++ b/ldap/servers/slapd/back-ldbm/Makefile
@@ -55,7 +55,8 @@ LIBBACK_LDBM_OBJS= idl.o idl_shim.o idl_new.o idl_common.o cache.o dn2entry.o \
ldbm_bind.o \
ldbm_unbind.o \
ancestorid.o \
- ldbm_attrcrypt.o
+ ldbm_attrcrypt.o \
+ dbhelp.o
OBJS = $(addprefix $(OBJDEST)/, $(LIBBACK_LDBM_OBJS))
diff --git a/ldap/servers/slapd/back-ldbm/archive.c b/ldap/servers/slapd/back-ldbm/archive.c
index 2daee2c5..10f79cfc 100644
--- a/ldap/servers/slapd/back-ldbm/archive.c
+++ b/ldap/servers/slapd/back-ldbm/archive.c
@@ -11,6 +11,7 @@ int ldbm_back_archive2ldbm( Slapi_PBlock *pb )
{
struct ldbminfo *li;
char *directory = NULL;
+ char *backendname = NULL;
int return_value = -1;
int task_flags = 0;
int run_from_cmdline = 0;
@@ -19,6 +20,7 @@ int ldbm_back_archive2ldbm( Slapi_PBlock *pb )
slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
slapi_pblock_get( pb, SLAPI_SEQ_VAL, &directory );
+ slapi_pblock_get( pb, SLAPI_BACKEND_INSTANCE_NAME, &backendname);
slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task );
slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags );
li->li_flags = run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE);
@@ -122,7 +124,7 @@ int ldbm_back_archive2ldbm( Slapi_PBlock *pb )
}
/* tell the database to restore */
- return_value = dblayer_restore(li, directory, task);
+ return_value = dblayer_restore(li, directory, task, backendname);
if (0 != return_value) {
LDAPDebug( LDAP_DEBUG_ANY,
"archive2db: Failed to read backup file set. "
diff --git a/ldap/servers/slapd/back-ldbm/dbhelp.c b/ldap/servers/slapd/back-ldbm/dbhelp.c
new file mode 100644
index 00000000..df4ae1d0
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dbhelp.c
@@ -0,0 +1,271 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2005 Red Hat Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * File for helper functions related to BerkeleyDB.
+ * This exists because dblayer.c is 5k+ lines long,
+ * so it seems time to move code to a new file.
+ */
+
+#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)
+{
+ int retval = 0;
+ int retval_cleanup = 0;
+ DB *source_file = NULL;
+ DB *destination_file = NULL;
+ DBC *source_cursor = NULL;
+ int dbtype = 0;
+ int dbflags = 0;
+ int dbpagesize = 0;
+ int cursor_flag = 0;
+ int finished = 0;
+ int mode = 0;
+
+ if (priv->dblayer_file_mode)
+ mode = priv->dblayer_file_mode;
+ dblayer_set_env_debugging(env, priv);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_copy_file_keybykey\n", 0, 0, 0 );
+ /* Open the source file */
+ retval = db_create(&source_file, env, 0);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Create error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ retval = source_file->open(source_file, NULL, source_file_name, NULL, DB_UNKNOWN, DB_RDONLY, 0);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Open error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ /* Get the info we need from the source file */
+ retval = source_file->get_flags(source_file, &dbflags);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, get_flags error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ retval = source_file->get_type(source_file, &dbtype);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, get_type error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ retval = source_file->get_pagesize(source_file, &dbpagesize);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, get_pagesize error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ /* Open the destination file
+ * and make sure that it has the correct page size, the correct access method, and the correct flags (dup etc)
+ */
+ retval = db_create(&destination_file, env, 0);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Create error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ retval = destination_file->set_flags(destination_file,dbflags);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, set_flags error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ retval = destination_file->set_pagesize(destination_file,dbpagesize);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, set_pagesize error %d: %s\n", retval, db_strerror(retval), 0);
+ 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);
+ goto error;
+ }
+ /* Open a cursor on the source file */
+ retval = source_file->cursor(source_file,NULL,&source_cursor,0);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Create cursor error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ /* Seek to the first key */
+ cursor_flag = DB_FIRST;
+ /* Loop seeking to the next key until they're all done */
+ while (!finished) {
+ DBT key = {0};
+ DBT data = {0};
+ retval = source_cursor->c_get(source_cursor, &key, &data, cursor_flag);
+ if (retval) {
+ /* DB_NOTFOUND is expected when we find the end, log a message for any other error.
+ * In either case, set finished=1 so we can hop down and close the cursor. */
+ if ( DB_NOTFOUND != retval )
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, c_get error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ retval = 0; /* DB_NOTFOUND was OK... */
+ finished = 1;
+ } else {
+ /* For each key, insert into the destination file */
+ retval = destination_file->put(destination_file, NULL, &key, &data, 0);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, put error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ cursor_flag = DB_NEXT;
+ }
+ }
+
+error:
+ /* Close the cursor */
+ if (source_cursor) {
+ retval_cleanup = source_cursor->c_close(source_cursor);
+ if (retval_cleanup) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Close cursor error %d: %s\n", retval_cleanup, db_strerror(retval_cleanup), 0);
+ retval += retval_cleanup;
+ }
+ }
+ /* Close the source file */
+ if (source_file) {
+ retval_cleanup = source_file->close(source_file,0);
+ source_file = NULL;
+ if (retval_cleanup) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Close error %d: %s\n", retval_cleanup, db_strerror(retval_cleanup), 0);
+ retval += retval_cleanup;
+ }
+ }
+ /* Close the destination file */
+ if (destination_file) {
+ retval_cleanup = destination_file->close(destination_file,0);
+ destination_file = NULL;
+ if (retval_cleanup) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_keybykey, Close error %d: %s\n", retval_cleanup, db_strerror(retval_cleanup), 0);
+ retval += retval_cleanup;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_copy_file_keybykey\n", 0, 0, 0 );
+ return retval;
+}
+
+int dblayer_copy_file_resetlsns(char *home_dir ,char *source_file_name, char *destination_file_name, int overwrite, dblayer_private *priv)
+{
+ int retval = 0;
+ int mode = 0;
+ DB_ENV *env = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_copy_file_resetlsns\n", 0, 0, 0 );
+ /* Make the environment */
+
+ if (priv->dblayer_file_mode)
+ mode = priv->dblayer_file_mode;
+ retval = dblayer_make_private_simple_env(home_dir,&env);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_resetlsns: Call to dblayer_make_private_simple_env failed!\n"
+ "Unable to open an environment.", 0, 0, 0);
+ }
+ /* Do the copy */
+ retval = dblayer_copy_file_keybykey(env, source_file_name, destination_file_name, overwrite, priv);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_resetlsns: Copy not completed successfully.", 0, 0, 0);
+ }
+ /* Close the environment */
+ if (env) {
+ int retval2 = 0;
+ retval2 = env->close(env,0);
+ if (retval2) {
+ if (0 == retval) {
+ retval = retval2;
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_copy_file_resetlsns, error %d: %s\n", retval, db_strerror(retval), 0);
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_copy_file_resetlsns\n", 0, 0, 0 );
+ return retval;
+}
+
+void dblayer_set_env_debugging(DB_ENV *pEnv, dblayer_private *priv)
+{
+ pEnv->set_errpfx(pEnv, "ns-slapd");
+ if (priv->dblayer_verbose) {
+ pEnv->set_verbose(pEnv, DB_VERB_CHKPOINT, 1); /* 1 means on */
+ pEnv->set_verbose(pEnv, DB_VERB_DEADLOCK, 1); /* 1 means on */
+ pEnv->set_verbose(pEnv, DB_VERB_RECOVERY, 1); /* 1 means on */
+ pEnv->set_verbose(pEnv, DB_VERB_WAITSFOR, 1); /* 1 means on */
+ }
+ if (priv->dblayer_debug) {
+ pEnv->set_errcall(pEnv, dblayer_log_print);
+ }
+
+}
+
+/* Make an environment to be used for isolated recovery (e.g. during a partial restore operation) */
+int dblayer_make_private_recovery_env(char *db_home_dir, dblayer_private *priv, DB_ENV **env)
+{
+ int retval = 0;
+ DB_ENV *ret_env = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_make_private_recovery_env\n", 0, 0, 0 );
+ if (NULL == env) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_recovery_env: Null environment. Cannot continue.", 0, 0, 0);
+ return -1;
+ }
+ *env = NULL;
+
+ retval = db_env_create(&ret_env,0);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_recovery_env, Create error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+ dblayer_set_env_debugging(ret_env, priv);
+
+ retval = ret_env->open(ret_env,db_home_dir, DB_INIT_TXN | DB_RECOVER_FATAL | DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE,0);
+ if (0 == retval) {
+ *env = ret_env;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_recovery_env, Open error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+
+error:
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_make_private_recovery_env\n", 0, 0, 0 );
+ return retval;
+}
+
+/* Make an environment to be used for simple non-transacted database operations, e.g. fixup during upgrade */
+int dblayer_make_private_simple_env(char *db_home_dir, DB_ENV **env)
+{
+ int retval = 0;
+ DB_ENV *ret_env = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> dblayer_make_private_simple_env\n", 0, 0, 0 );
+ if (NULL == env) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_simple_env: Null environment. Cannot continue.", 0, 0, 0);
+ return -1;
+ }
+ *env = NULL;
+
+ retval = db_env_create(&ret_env,0);
+ if (retval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_simple_env, error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+
+ retval = ret_env->open(ret_env,db_home_dir,DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE,0);
+ if (0 == retval) {
+ *env = ret_env;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_make_private_simple_env, error %d: %s\n", retval, db_strerror(retval), 0);
+ goto error;
+ }
+
+error:
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= dblayer_make_private_simple_env\n", 0, 0, 0 );
+ return retval;
+}
+
+char* last_four_chars(const char* s)
+{
+ size_t l = strlen(s);
+ return ((char*)s + (l - 4));
+}
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
index c852b475..41c2f4c1 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
@@ -131,6 +131,9 @@
#endif
#endif
+#define NEWDIR_MODE 0755
+
+
static int perf_threadmain(void *param);
static int checkpoint_threadmain(void *param);
static int trickle_threadmain(void *param);
@@ -142,6 +145,7 @@ static int dblayer_override_libdb_functions(DB_ENV *pEnv, dblayer_private *priv)
static int dblayer_force_checkpoint(struct ldbminfo *li);
static int log_flush_threadmain(void *param);
static int dblayer_delete_transaction_logs(const char * log_dir);
+static int dblayer_is_logfilename(const char* path);
static int dblayer_start_log_flush_thread(dblayer_private *priv);
static int dblayer_start_deadlock_thread(struct ldbminfo *li);
@@ -152,7 +156,6 @@ static int trans_batch_count=1;
static int trans_batch_limit=0;
static PRBool log_flush_thread=PR_FALSE;
static int dblayer_db_remove_ex(dblayer_private_env *env, char const path[], char const dbName[], PRBool use_lock);
-static char* last_four_chars(const char* s);
#define MEGABYTE (1024 * 1024)
#define GIGABYTE (1024 * MEGABYTE)
@@ -285,7 +288,7 @@ static void dblayer_reset_env(struct ldbminfo *li)
}
/* Callback function for libdb to spit error info into our log */
-static void dblayer_log_print(const char* prefix, char *buffer)
+void dblayer_log_print(const char* prefix, char *buffer)
{
/* We ignore the prefix since we know who we are anyway */
LDAPDebug(LDAP_DEBUG_ANY,"libdb: %s\n", buffer, 0, 0);
@@ -605,21 +608,13 @@ static void dblayer_init_dbenv(DB_ENV *pEnv, dblayer_private *priv)
dblayer_select_ncache(mysize, &myncache);
priv->dblayer_ncache = myncache;
- pEnv->set_errpfx(pEnv, "ns-slapd");
+ dblayer_set_env_debugging(pEnv,priv);
+
pEnv->set_lg_max(pEnv, priv->dblayer_logfile_size);
pEnv->set_cachesize(pEnv, mysize / GIGABYTE, mysize % GIGABYTE, myncache);
pEnv->set_lk_max_locks(pEnv, priv->dblayer_lock_config);
pEnv->set_lk_max_objects(pEnv, priv->dblayer_lock_config);
pEnv->set_lk_max_lockers(pEnv, priv->dblayer_lock_config);
- if (priv->dblayer_verbose) {
- pEnv->set_verbose(pEnv, DB_VERB_CHKPOINT, 1); /* 1 means on */
- pEnv->set_verbose(pEnv, DB_VERB_DEADLOCK, 1); /* 1 means on */
- pEnv->set_verbose(pEnv, DB_VERB_RECOVERY, 1); /* 1 means on */
- pEnv->set_verbose(pEnv, DB_VERB_WAITSFOR, 1); /* 1 means on */
- }
- if (priv->dblayer_debug) {
- pEnv->set_errcall(pEnv, dblayer_log_print);
- }
/* shm_key required for named_regions (DB_SYSTEM_MEM) */
pEnv->set_shm_key(pEnv, priv->dblayer_shm_key);
@@ -3972,8 +3967,12 @@ static int dblayer_force_checkpoint(struct ldbminfo *li)
return ret;
}
-
-static int _dblayer_delete_instance_dir(ldbm_instance *inst)
+/* TEL: Added startdb flag. If set (1), the DB environment will be started so
+ * that dblayer_db_remove_ex will be used to remove the database files instead
+ * of simply deleting them. That is important when doing a selective restoration
+ * of a single backend (FRI). If not set (0), the traditional remove is used.
+ */
+static int _dblayer_delete_instance_dir(ldbm_instance *inst, int startdb)
{
PRDir *dirhandle = NULL;
PRDirEntry *direntry = NULL;
@@ -3987,6 +3986,16 @@ static int _dblayer_delete_instance_dir(ldbm_instance *inst)
if (NULL != li)
{
+ if (startdb)
+ {
+ rval = dblayer_start(li, DBLAYER_NORMAL_MODE);
+ if (rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "_dblayer_delete_instance_dir: dblayer_start failed! %s (%d)\n",
+ dblayer_strerror(rval), rval, 0);
+ goto done;
+ }
+ }
priv = (dblayer_private*)li->li_dblayer_private;
if (NULL != priv)
{
@@ -4045,6 +4054,15 @@ static int _dblayer_delete_instance_dir(ldbm_instance *inst)
}
}
PR_CloseDir(dirhandle);
+ if (pEnv && startdb)
+ {
+ rval = dblayer_close(li, DBLAYER_NORMAL_MODE);
+ if (rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "_dblayer_delete_instance_dir: dblayer_close failed! %s (%d)\n",
+ dblayer_strerror(rval), rval, 0);
+ }
+ }
done:
/* remove the directory itself too */
if (0 == rval)
@@ -4067,20 +4085,23 @@ int dblayer_delete_instance_dir(backend *be)
return ret;
} else {
ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
- return _dblayer_delete_instance_dir(inst);
+ return _dblayer_delete_instance_dir(inst, 0);
}
}
-/* delete an entire db/ directory, including all instances under it!
+
+/* delete an entire db/ directory, including either all instances, or
+ * just a single instance (leaving the others intact), if the instance param is non-NULL !
* this is used mostly for restores.
* dblayer is assumed to be closed.
*/
-int dblayer_delete_database(struct ldbminfo *li)
+int dblayer_delete_database_ex(struct ldbminfo *li, char *instance)
{
dblayer_private *priv = NULL;
Object *inst_obj;
PRDir *dirhandle = NULL;
PRDirEntry *direntry = NULL;
+ PRFileInfo fileinfo;
char filename[MAXPATHLEN];
char *log_dir;
int ret;
@@ -4095,13 +4116,25 @@ int dblayer_delete_database(struct ldbminfo *li)
ldbm_instance *inst = (ldbm_instance *)object_get_data(inst_obj);
if (inst->inst_be->be_instance_info != NULL) {
- ret = _dblayer_delete_instance_dir(inst);
- if (ret != 0)
- {
- LDAPDebug(LDAP_DEBUG_ANY,
- "dblayer_delete_database: WARNING _dblayer_delete_instance_dir failed (%d)\n", ret, 0, 0);
- return ret;
- }
+ if ((NULL != instance) && (strcmp(inst->inst_name,instance) != 0))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_delete_database: skipping instance %s\n",inst->inst_name , 0, 0);
+ } else
+ {
+ if (NULL == instance)
+ {
+ ret = _dblayer_delete_instance_dir(inst, 0 /* Do not start DB environment: traditional */);
+ } else {
+ ret = _dblayer_delete_instance_dir(inst, 1 /* Start DB environment: for FRI */);
+ }
+ if (ret != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_delete_database: WARNING _dblayer_delete_instance_dir failed (%d)\n", ret, 0, 0);
+ return ret;
+ }
+ }
}
}
@@ -4116,11 +4149,26 @@ int dblayer_delete_database(struct ldbminfo *li)
}
while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT |
PR_SKIP_DOT_DOT))) {
+ int rval_tmp = 0;
if (! direntry->name)
break;
- sprintf(filename, "%s/%s", priv->dblayer_home_directory,
- direntry->name);
- PR_Delete(filename);
+
+ sprintf(filename, "%s/%s", priv->dblayer_home_directory,
+ direntry->name);
+
+ /* Do not call PR_Delete on the instance directories if they exist.
+ * It would not work, but we still should not do it. */
+ rval_tmp = PR_GetFileInfo(filename, &fileinfo);
+ if (rval_tmp == PR_SUCCESS && fileinfo.type != PR_FILE_DIRECTORY)
+ {
+ /* Skip deleting log files; that should be handled below.
+ * (Note, we don't want to use "filename," because that is qualified and would
+ * not be compatibile with what dblayer_is_logfilename expects.) */
+ if (!dblayer_is_logfilename(direntry->name))
+ {
+ PR_Delete(filename);
+ }
+ }
}
PR_CloseDir(dirhandle);
@@ -4134,16 +4182,28 @@ int dblayer_delete_database(struct ldbminfo *li)
{
log_dir = dblayer_get_home_dir(li, NULL);
}
- ret = dblayer_delete_transaction_logs(log_dir);
- if(ret) {
- LDAPDebug(LDAP_DEBUG_ANY,
- "dblayer_delete_database: dblayer_delete_transaction_logs failed (%d)\n",
- ret, 0, 0);
- return -1;
- }
+ if (instance == NULL)
+ {
+ ret = dblayer_delete_transaction_logs(log_dir);
+ if(ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_delete_database: dblayer_delete_transaction_logs failed (%d)\n",
+ ret, 0, 0);
+ return -1;
+ }
+ }
return 0;
}
+/* delete an entire db/ directory, including all instances under it!
+ * this is used mostly for restores.
+ * dblayer is assumed to be closed.
+ */
+int dblayer_delete_database(struct ldbminfo *li)
+{
+ return dblayer_delete_database_ex(li, NULL);
+}
+
/*
* Return the size of the database (in kilobytes). XXXggood returning
@@ -4207,11 +4267,6 @@ int dblayer_database_size(struct ldbminfo *li, unsigned int *size)
return return_value;
}
-static char* last_four_chars(const char* s)
-{
- size_t l = strlen(s);
- return ((char*)s + (l - 4));
-}
static int count_dbfiles_in_dir(char *directory, int *count, int recurse)
{
@@ -4365,6 +4420,8 @@ error:
* The argument cnt is used to count the number of files that were copied.
*
* This function is used during db2bak and bak2db.
+ * DBDB added resetlsns arg which is used in partial restore (because the LSNs need to be reset to avoid
+ * confusing transaction logging code).
*/
int dblayer_copy_directory(struct ldbminfo *li,
Slapi_Task *task,
@@ -4373,7 +4430,8 @@ int dblayer_copy_directory(struct ldbminfo *li,
int restore,
int *cnt,
int instance_dir_flag,
- int indexonly)
+ int indexonly,
+ int resetlsns)
{
dblayer_private *priv = NULL;
char *new_src_dir = NULL;
@@ -4523,8 +4581,14 @@ int dblayer_copy_directory(struct ldbminfo *li,
}
/* copy filename1 to filename2 */
- return_value = dblayer_copyfile(filename1, filename2,
+ /* If the file is a database file, and resetlsns is set, then we need to do a key by key copy */
+ if (strcmp(LDBM_FILENAME_SUFFIX, last_four_chars(filename1)) == 0 && resetlsns) {
+ return_value = dblayer_copy_file_resetlsns(src_dir, filename1, filename2,
+ 0, priv);
+ } else {
+ return_value = dblayer_copyfile(filename1, filename2,
0, priv->dblayer_file_mode);
+ }
slapi_ch_free((void**)&filename1);
slapi_ch_free((void**)&filename2);
if (0 > return_value)
@@ -4640,7 +4704,7 @@ int dblayer_backup(struct ldbminfo *li, char *dest_dir, Slapi_Task *task)
inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
inst_dir, MAXPATHLEN);
return_value = dblayer_copy_directory(li, task, inst_dirp,
- dest_dir, 0 /* backup */, &cnt, 0, 0);
+ dest_dir, 0 /* backup */, &cnt, 0, 0, 0);
if (return_value != 0) {
LDAPDebug(LDAP_DEBUG_ANY,
"ERROR: error copying directory (%s -> %s): err=%d\n",
@@ -4895,9 +4959,198 @@ static int doskip(const char *filename)
return 0;
}
+static int dblayer_copy_dirand_contents(char* src_dir, char* dst_dir, int mode, Slapi_Task *task)
+{
+ int return_value = 0;
+ int tmp_rval;
+ char filename1[MAXPATHLEN];
+ char filename2[MAXPATHLEN];
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ PRFileInfo info;
+
+ dirhandle = PR_OpenDir(src_dir);
+ if (NULL != dirhandle)
+ {
+
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == direntry->name) {
+ /* NSPR doesn't behave like the docs say it should */
+ break;
+ }
+
+
+ sprintf(filename1, "%s/%s", src_dir, direntry->name);
+ sprintf(filename2, "%s/%s", dst_dir, direntry->name);
+ LDAPDebug(LDAP_DEBUG_ANY, "Moving file %s\n",
+ filename2, 0, 0);
+ /* Is this entry a directory? */
+ tmp_rval = PR_GetFileInfo(filename1, &info);
+ if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type)
+ {
+ PR_MkDir(filename2,NEWDIR_MODE);
+ return_value = dblayer_copy_dirand_contents(filename1, filename2,
+ mode,task);
+ if (return_value)
+ {
+ if (task)
+ {
+ slapi_task_log_notice(task,
+ "Failed to copy directory %s", filename1);
+ }
+ break;
+ }
+ } else {
+ if (task)
+ {
+ slapi_task_log_notice(task, "Moving file %s",
+ filename2);
+ slapi_task_log_status(task, "Moving file %s",
+ filename2);
+ }
+ return_value = dblayer_copyfile(filename1, filename2, 0,
+ mode);
+ }
+ if (0 > return_value)
+ break;
+
+ }
+ }
+ return return_value;
+}
+
+static int dblayer_fri_trim(char *fri_dir_path, char* bename)
+{
+ int retval = 0;
+ int tmp_rval;
+ char filename[MAXPATHLEN];
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ PRFileInfo info;
+
+ dirhandle = PR_OpenDir(fri_dir_path);
+ if (NULL != dirhandle)
+ {
+
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == direntry->name) {
+ /* NSPR doesn't behave like the docs say it should */
+ break;
+ }
+
+ sprintf(filename, "%s/%s", fri_dir_path, direntry->name);
+
+ /* Is this entry a directory? */
+ tmp_rval = PR_GetFileInfo(filename, &info);
+ if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type)
+ {
+ if(strcmp(direntry->name,bename)!=0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Removing file %s from staging area\n",
+ filename, 0, 0);
+ ldbm_delete_dirs(filename);
+ }
+ continue;
+ }
+
+ if ((strcmp(direntry->name,"DBVERSION") == 0)||
+ (strncmp(direntry->name,"__",2) == 0)||
+ (strncmp(direntry->name,"log",3) == 0)){
+ LDAPDebug(LDAP_DEBUG_ANY, "Removing file %s from staging area\n",
+ filename, 0, 0);
+ PR_Delete(filename);
+ }
+
+ }
+ }
+ PR_CloseDir(dirhandle);
+ return retval;
+}
+
+/* Recover a stand-alone environment , used in filesystem replica intialization restore */
+static int dblayer_recover_environment_path(char *dbhome_dir, dblayer_private *priv)
+{
+ int retval = 0;
+ DB_ENV *env = NULL;
+ /* Make an environment for recovery */
+ retval = dblayer_make_private_recovery_env(dbhome_dir, priv, &env);
+ if (retval) {
+ goto error;
+ }
+ if (env) {
+ retval = env->close(env,0);
+ if (retval) {
+ }
+ }
+error:
+ return retval;
+}
+
+
+static int dblayer_fri_restore(char *home_dir, char *src_dir, dblayer_private *priv, Slapi_Task *task, char** new_src_dir, char* bename)
+{
+ int retval = 0;
+ size_t fribak_dir_length = 0;
+ char *fribak_dir_path = NULL;
+ char *fribak_dir_name = "fribak";
+ int mode = priv->dblayer_file_mode;
+
+ *new_src_dir = NULL;
+
+
+ /* First create the recovery directory */
+ fribak_dir_length = strlen(home_dir) + strlen(fribak_dir_name) + 4; /* 4 for the '/../' */
+ fribak_dir_path = (char *) slapi_ch_malloc(fribak_dir_length + 1); /* add one for the terminator */
+ sprintf(fribak_dir_path,"%s/../%s",home_dir,fribak_dir_name);
+ if((-1 == PR_MkDir(fribak_dir_path,NEWDIR_MODE)))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_fri_restore: %s exists\n",fribak_dir_path, 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_fri_restore: Removing %s.\n",fribak_dir_path, 0, 0);
+ retval = ldbm_delete_dirs(fribak_dir_path);
+ if (retval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_fri_restore: Removal of %s failed!\n", fribak_dir_path, 0, 0);
+ goto error;
+ }
+ PR_MkDir(fribak_dir_path,NEWDIR_MODE);
+ if (retval != PR_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_fri_restore: Creation of %s failed!\n", fribak_dir_path, 0, 0);
+ goto error;
+ }
+ }
+ /* Next copy over the entire backup file set to the recovery directory */
+ /* We do this because we want to run recovery there, and we need all the files for that */
+ retval = dblayer_copy_dirand_contents(src_dir, fribak_dir_path, mode, task);
+ if (retval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_fri_restore: Copy contents to %s failed!\n", fribak_dir_path, 0, 0);
+ goto error;
+ }
+ /* Next, run recovery on the files */
+ retval = dblayer_recover_environment_path(fribak_dir_path, priv);
+ if (retval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_fri_restore: Recovery failed!\n", 0, 0, 0);
+ goto error;
+ }
+ /* Files nicely recovered, next we stip out what we don't need from the backup set */
+ retval = dblayer_fri_trim(fribak_dir_path,bename);
+ if (retval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_fri_restore: Trim failed!\n", 0, 0, 0);
+ goto error;
+ }
+ *new_src_dir = fribak_dir_path;
+ error:
+ return retval;
+}
+
/* Destination Directory is an absolute pathname */
-int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
+int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bename)
{
dblayer_private *priv = NULL;
int return_value = 0;
@@ -4913,6 +5166,8 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
int dbmode;
int action = 0;
char *home_dir = NULL;
+ char *real_src_dir = NULL;
+ int frirestore = 0; /* Is a an FRI/single instance restore. 0 for no, 1 for yes */
PR_ASSERT(NULL != li);
priv = (dblayer_private*)li->li_dblayer_private;
@@ -4927,6 +5182,7 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
PR_Unlock(li->li_config_mutex);
home_dir = dblayer_get_home_dir(li, NULL);
+
if (NULL == home_dir)
{
LDAPDebug(LDAP_DEBUG_ANY,
@@ -4949,6 +5205,10 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
}
}
+ /* If this is a FRI restore, the bename will be non-NULL */
+ if (bename != NULL)
+ frirestore = 1;
+
/*
* Check if the target is a superset of the backup.
* If not don't restore any db at all, otherwise
@@ -4961,19 +5221,22 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
&& direntry->name)
{
sprintf(filename1, "%s/%s", src_dir, direntry->name);
- tmp_rval = PR_GetFileInfo(filename1, &info);
- if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
- inst = ldbm_instance_find_by_name(li, (char *)direntry->name);
- if ( inst == NULL)
- {
- LDAPDebug(LDAP_DEBUG_ANY,
- "ERROR: target server has no %s configured\n", direntry->name, 0, 0);
- if (task) {
- slapi_task_log_notice(task,
- "ERROR: target server has no %s configured\n", direntry->name);
- }
- PR_CloseDir(dirhandle);
- return LDAP_UNWILLING_TO_PERFORM;
+ if(!frirestore || strcmp(direntry->name,bename)==0)
+ {
+ tmp_rval = PR_GetFileInfo(filename1, &info);
+ if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
+ inst = ldbm_instance_find_by_name(li, (char *)direntry->name);
+ if ( inst == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: target server has no %s configured\n", direntry->name, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "ERROR: target server has no %s configured\n", direntry->name);
+ }
+ PR_CloseDir(dirhandle);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
}
}
}
@@ -4981,17 +5244,33 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
}
/* We delete the existing database */
- return_value = dblayer_delete_database(li);
+
+ return_value = dblayer_delete_database_ex(li, bename);
if (return_value) {
return return_value;
}
+ if (frirestore) /*if we are restoring a single backend*/
+ {
+ char *new_src_dir = NULL;
+ return_value = dblayer_fri_restore(home_dir,src_dir,priv,task,&new_src_dir,bename);
+ if (return_value) {
+ return return_value;
+ }
+ /* Now modify the src_dir to point to our recovery area and carry on as if nothing had happened... */
+ real_src_dir = new_src_dir;
+ } else
+ {
+ /* Otherwise use the src_dir from the caller */
+ real_src_dir = src_dir;
+ }
+
/* We copy the files over from the staging area */
/* We want to treat the logfiles specially: if there's
* a log file directory configured, copy the logfiles there
* rather than to the db dirctory */
if (0 == return_value) {
- dirhandle = PR_OpenDir(src_dir);
+ dirhandle = PR_OpenDir(real_src_dir);
if (NULL != dirhandle) {
char *restore_dir;
char *prefix = NULL;
@@ -5004,8 +5283,9 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
break;
}
+
/* Is this entry a directory? */
- sprintf(filename1, "%s/%s", src_dir, direntry->name);
+ sprintf(filename1, "%s/%s", real_src_dir, direntry->name);
tmp_rval = PR_GetFileInfo(filename1, &info);
if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
/* This is an instance directory. It contains the *.db#
@@ -5019,9 +5299,9 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
continue;
restore_dir = inst->inst_parent_dir_name;
-
+ /* If we're doing a partial restore, we need to reset the LSNs on the data files */
if (dblayer_copy_directory(li, task, filename1,
- restore_dir, 1 /* restore */, &cnt, 0, 0) == 0)
+ restore_dir, 1 /* restore */, &cnt, 0, 0, (bename) ? 1 : 0) == 0)
continue;
else
{
@@ -5054,7 +5334,7 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
prefix = home_dir;
}
mkdir_p(prefix, 0700);
- sprintf(filename1, "%s/%s", src_dir, direntry->name);
+ sprintf(filename1, "%s/%s", real_src_dir, direntry->name);
sprintf(filename2, "%s/%s", prefix, direntry->name);
LDAPDebug(LDAP_DEBUG_ANY, "Restoring file %d (%s)\n",
cnt, filename2, 0);
@@ -5130,12 +5410,13 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
if (task) {
slapi_task_log_notice(task, "Failed to init database");
}
- return tmp_rval;
+ return_value = tmp_rval;
+ goto error_out;
}
if (0 == return_value) { /* only when the copyfile succeeded */
/* check the DSE_* files, if any */
- tmp_rval = dse_conf_verify(li, src_dir);
+ tmp_rval = dse_conf_verify(li, real_src_dir, bename);
if (0 != tmp_rval)
LDAPDebug(LDAP_DEBUG_ANY,
"Warning: Unable to verify the index configuration\n", 0, 0, 0);
@@ -5154,6 +5435,22 @@ int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
return_value = tmp_rval?tmp_rval:return_value;
+error_out:
+ /* Free the restore src dir, but only if we allocated it above */
+ if (real_src_dir != src_dir) {
+ /* If this was an FRI restore and the staging area exists, go ahead and remove it */
+ if (frirestore && PR_Access(real_src_dir, PR_ACCESS_EXISTS) == PR_SUCCESS)
+ {
+ int ret1 = 0;
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_restore: Removing staging area %s.\n",real_src_dir, 0, 0);
+ ret1 = ldbm_delete_dirs(real_src_dir);
+ if (ret1)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_restore: Removal of staging area %s failed!\n", real_src_dir, 0, 0);
+ }
+ }
+ slapi_ch_free((void**)&real_src_dir);
+ }
return return_value;
}
@@ -5393,3 +5690,4 @@ void dblayer_set_recovery_required(struct ldbminfo *li)
}
li->li_dblayer_private->dblayer_recovery_required = 1;
}
+
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.h b/ldap/servers/slapd/back-ldbm/dblayer.h
index 78274ec6..7c096617 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.h
+++ b/ldap/servers/slapd/back-ldbm/dblayer.h
@@ -133,8 +133,26 @@ struct dblayer_private
int dblayer_lock_config;
};
+void dblayer_log_print(const char* prefix, char *buffer);
+
int dblayer_db_remove(dblayer_private_env * env, char const path[], char const dbName[]);
int dblayer_delete_indices(ldbm_instance *inst);
+/* Helper functions in dbhelp.c */
+
+/* Make an environment to be used for isolated recovery (e.g. during a partial restore operation) */
+int dblayer_make_private_recovery_env(char *db_home_dir, dblayer_private *priv, DB_ENV **env);
+/* Make an environment to be used for simple non-transacted database operations, e.g. fixup during upgrade */
+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);
+/* Turn on the various logging and debug options for DB */
+void dblayer_set_env_debugging(DB_ENV *pEnv, dblayer_private *priv);
+
+/* Return the last four characters of a string; used for comparing extensions. */
+char* last_four_chars(const char* s);
+
#endif /* _DBLAYER_H_ */
diff --git a/ldap/servers/slapd/back-ldbm/dbversion.c b/ldap/servers/slapd/back-ldbm/dbversion.c
index 4c1a56da..843c5609 100644
--- a/ldap/servers/slapd/back-ldbm/dbversion.c
+++ b/ldap/servers/slapd/back-ldbm/dbversion.c
@@ -43,7 +43,11 @@ dbversion_write(struct ldbminfo *li, const char *directory,
PRFileDesc *prfd;
int rc = 0;
- PR_ASSERT(is_fullpath((char *)directory));
+ if (!is_fullpath((char *)directory)) {
+ rc = -1;
+ return rc;
+ }
+
mk_dbversion_fullpath(li, directory, filename);
/* Open the file */
@@ -115,7 +119,11 @@ dbversion_read(struct ldbminfo *li, const char *directory,
int rc = -1;
char * iter = NULL;
- PR_ASSERT(is_fullpath((char *)directory));
+ if (!is_fullpath((char *)directory)) {
+ rc = -1;
+ return rc;
+ }
+
mk_dbversion_fullpath(li, directory, filename);
ldbmversion[0]= '\0';
@@ -167,7 +175,6 @@ dbversion_exists(struct ldbminfo *li, const char *directory)
char filename[ MAXPATHLEN*2 ];
PRFileDesc *prfd;
- PR_ASSERT(is_fullpath((char *)directory));
mk_dbversion_fullpath(li, directory, filename);
if (( prfd = PR_Open( filename, PR_RDONLY, SLAPD_DEFAULT_FILE_MODE )) ==
diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c
index 413eaca6..653daf44 100644
--- a/ldap/servers/slapd/back-ldbm/import-threads.c
+++ b/ldap/servers/slapd/back-ldbm/import-threads.c
@@ -1881,7 +1881,7 @@ dse_conf_backup(struct ldbminfo *li, char *dest_dir)
* [547427] index config must not change between backup and restore
*/
int
-dse_conf_verify_core(struct ldbminfo *li, char *src_dir, char *file_name, char *filter, char *log_str)
+dse_conf_verify_core(struct ldbminfo *li, char *src_dir, char *file_name, char *filter, char *log_str, char *entry_filter)
{
char *filename = NULL;
int rval = 0;
@@ -1890,6 +1890,7 @@ dse_conf_verify_core(struct ldbminfo *li, char *src_dir, char *file_name, char *
int curr_lineno = 0;
int finished = 0;
int backup_entry_len = 256;
+ char *search_scope = NULL;
Slapi_Entry **backup_entries = NULL;
Slapi_Entry **bep = NULL;
Slapi_Entry **curr_entries = NULL;
@@ -1928,6 +1929,12 @@ dse_conf_verify_core(struct ldbminfo *li, char *src_dir, char *file_name, char *
if (!estr)
break;
+
+ if (entry_filter != NULL) /* Single instance restoration */
+ {
+ if (!(int)strstr(estr, entry_filter))
+ continue;
+ }
e = slapi_str2entry(estr, 0);
slapi_ch_free_string(&estr);
@@ -1951,11 +1958,23 @@ dse_conf_verify_core(struct ldbminfo *li, char *src_dir, char *file_name, char *
*bep = NULL;
pblock_init(&srch_pb);
- slapi_search_internal_set_pb(&srch_pb, li->li_plugin->plg_dn,
+
+ if (entry_filter != NULL)
+ { /* Single instance restoration */
+ int mylen = 0;
+ mylen = strlen(entry_filter) + strlen(li->li_plugin->plg_dn) + 2;
+ search_scope = slapi_ch_malloc(mylen);
+ sprintf(search_scope, "%s,%s", entry_filter, li->li_plugin->plg_dn);
+ } else { /* Normal restoration */
+ search_scope = slapi_ch_strdup(li->li_plugin->plg_dn);
+ }
+
+ slapi_search_internal_set_pb(&srch_pb, search_scope,
LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, li->li_identity, 0);
slapi_search_internal_pb(&srch_pb);
slapi_pblock_get(&srch_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &curr_entries);
+
if (0 != slapi_entries_diff(backup_entries, curr_entries, 1 /* test_all */,
log_str, 1 /* force_update */, li->li_identity))
{
@@ -1974,6 +1993,10 @@ out:
slapi_ch_free_string(&filename);
+ if (search_scope)
+ slapi_ch_free(&search_scope);
+
+
if (fd > 0)
close(fd);
@@ -1981,12 +2004,39 @@ out:
}
int
-dse_conf_verify(struct ldbminfo *li, char *src_dir)
+dse_conf_verify(struct ldbminfo *li, char *src_dir, char *bename)
{
int rval;
- rval = dse_conf_verify_core(li, src_dir, DSE_INSTANCE, DSE_INSTANCE_FILTER,
- "Instance Config");
+ char *entry_filter = NULL;
+ char *instance_entry_filter = NULL;
+
+ if (bename != NULL) /* This was a restore of a single backend */
+ {
+ int mylen = 0;
+ /* Entry filter string */
+ mylen = strlen(bename) + strlen("cn=") + 2;
+ entry_filter = slapi_ch_malloc(mylen);
+ sprintf(entry_filter, "cn=%s", bename);
+
+ mylen = 0;
+ /* Instance search filter */
+ mylen = strlen(DSE_INSTANCE_FILTER) + strlen(bename) + strlen("(&(cn=))") + 2;
+ instance_entry_filter = slapi_ch_malloc(mylen);
+ sprintf(instance_entry_filter, "(&%s(cn=%s))", DSE_INSTANCE_FILTER, bename);
+ } else {
+ instance_entry_filter = slapi_ch_strdup(DSE_INSTANCE_FILTER);
+ }
+
+ rval = dse_conf_verify_core(li, src_dir, DSE_INSTANCE, instance_entry_filter,
+ "Instance Config", entry_filter);
rval += dse_conf_verify_core(li, src_dir, DSE_INDEX, DSE_INDEX_FILTER,
- "Index Config");
+ "Index Config", entry_filter);
+
+ if (entry_filter)
+ slapi_ch_free(&entry_filter);
+ if (instance_entry_filter)
+ slapi_ch_free(&instance_entry_filter);
+
return rval;
}
+
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index 1930cb51..65ef0ddb 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -2066,7 +2066,7 @@ int ldbm_back_upgradedb(Slapi_PBlock *pb)
inst_dir, MAXPATHLEN);
backup_rval = dblayer_copy_directory(li, NULL /* task */,
inst_dirp, dest_dir, 0/*backup*/,
- &cnt, 0, 1);
+ &cnt, 0, 1, 0);
if (inst_dirp != inst_dir)
slapi_ch_free_string(&inst_dirp);
if (backup_rval < 0)
@@ -2210,7 +2210,7 @@ fail1:
backup_rval = dblayer_copy_directory(li, NULL /* task */,
inst->inst_dir_name,
dest_dir, 1/*restore*/,
- &cnt, 0, 1);
+ &cnt, 0, 1, 0);
if (inst_dirp != inst_dir)
slapi_ch_free_string(&inst_dirp);
if (backup_rval < 0)
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
index 4e8ed4df..0f42a28f 100644
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -93,11 +93,11 @@ int dblayer_memp_stat(struct ldbminfo *li, DB_MPOOL_STAT **gsp,DB_MPOOL_FSTAT **
int dblayer_memp_stat_instance(ldbm_instance *inst, DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp);
int dblayer_backup(struct ldbminfo *li, char *destination_directory,
Slapi_Task *task);
-int dblayer_restore(struct ldbminfo *li, char* source_directory, Slapi_Task *task);
+int dblayer_restore(struct ldbminfo *li, char* source_directory, Slapi_Task *task, char *bename);
int dblayer_copy_directory(struct ldbminfo *li, Slapi_Task *task,
char *instance_dir, char *destination_dir,
int restore, int *cnt, int instance_dir_flag,
- int indexonly);
+ int indexonly, int resetlsns);
int dblayer_copyfile(char* source, char * destination, int overwrite, int mode);
int dblayer_delete_instance_dir(backend *be);
int dblayer_delete_database(struct ldbminfo *li);
@@ -570,7 +570,7 @@ int ldbm_ancestorid_move_subtree(
* import-threads.c
*/
int dse_conf_backup(struct ldbminfo *li, char *destination_directory);
-int dse_conf_verify(struct ldbminfo *li, char *src_dir);
+int dse_conf_verify(struct ldbminfo *li, char *src_dir, char *bename);
/*
* ldbm_attrcrypt.c
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 7e4bd423..dd85e41d 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -1070,7 +1070,8 @@ static int task_restore_add(Slapi_PBlock *pb, Slapi_Entry *e,
Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
{
Slapi_Backend *be = NULL;
- const char *cn;
+ const char *cn = NULL;
+ const char *instance_name = NULL;
const char *archive_dir = NULL;
const char *my_database_type = NULL;
const char *database_type = "ldbm database";
@@ -1099,6 +1100,8 @@ static int task_restore_add(Slapi_PBlock *pb, Slapi_Entry *e,
if (NULL != my_database_type)
database_type = my_database_type;
+ instance_name = fetch_attr(e, "nsInstance", NULL);
+
/* get backend that has archive2db and the database type matches. */
cookie = NULL;
be = slapi_get_first_backend (&cookie);
@@ -1148,6 +1151,8 @@ static int task_restore_add(Slapi_PBlock *pb, Slapi_Entry *e,
}
mypb->pb_seq_val = slapi_ch_strdup(archive_dir);
mypb->pb_plugin = be->be_database;
+ if (NULL != instance_name)
+ mypb->pb_instance_name = slapi_ch_strdup(instance_name);
mypb->pb_task = task;
mypb->pb_task_flags = TASK_RUNNING_AS_TASK;