diff options
Diffstat (limited to 'ldap')
-rw-r--r-- | ldap/admin/src/create_instance.c | 69 | ||||
-rw-r--r-- | ldap/admin/src/scripts/template-bak2db.pl | 14 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/Makefile | 3 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/archive.c | 4 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/dbhelp.c | 271 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/dblayer.c | 426 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/dblayer.h | 18 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/dbversion.c | 13 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/import-threads.c | 62 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 4 | ||||
-rw-r--r-- | ldap/servers/slapd/back-ldbm/proto-back-ldbm.h | 6 | ||||
-rw-r--r-- | ldap/servers/slapd/task.c | 7 |
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; |