summaryrefslogtreecommitdiff
path: root/src/db/db_backup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/db/db_backup.c')
-rw-r--r--src/db/db_backup.c169
1 files changed, 143 insertions, 26 deletions
diff --git a/src/db/db_backup.c b/src/db/db_backup.c
index 66d7382a..1c72e4d7 100644
--- a/src/db/db_backup.c
+++ b/src/db/db_backup.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -24,8 +24,9 @@ static int backup_read_data_dir
__P((DB_ENV *, DB_THREAD_INFO *, const char *, const char *, u_int32_t));
static int backup_dir_clean
__P((DB_ENV *, const char *, const char *, int *, u_int32_t));
-static int backup_data_copy
- __P((DB_ENV *, const char *, const char *, const char *, int));
+static int backup_lgconf_chk __P((DB_ENV *));
+static int __db_backup
+ __P((DB_ENV *, const char *, DB_THREAD_INFO *, int, u_int32_t));
/*
* __db_dbbackup_pp --
@@ -47,9 +48,9 @@ __db_dbbackup_pp(dbenv, dbfile, target, flags)
"DB_ENV->dbbackup", flags, DB_EXCL)) != 0)
return (ret);
ENV_ENTER(dbenv->env, ip);
-
- ret = __db_dbbackup(dbenv, ip, dbfile, target, flags);
-
+ REPLICATION_WRAP(dbenv->env,
+ (__db_dbbackup(
+ dbenv, ip, dbfile, target, flags, 0, NULL)), 0, ret);
ENV_LEAVE(dbenv->env, ip);
return (ret);
}
@@ -58,15 +59,17 @@ __db_dbbackup_pp(dbenv, dbfile, target, flags)
* __db_dbbackup --
* Copy a database file coordinated with mpool.
*
- * PUBLIC: int __db_dbbackup __P((DB_ENV *, DB_THREAD_INFO *,
- * PUBLIC: const char *, const char *, u_int32_t));
+ * PUBLIC: int __db_dbbackup __P((DB_ENV *, DB_THREAD_INFO *, const char *,
+ * PUBLIC: const char *, u_int32_t, u_int32_t, const char *));
*/
int
-__db_dbbackup(dbenv, ip, dbfile, target, flags)
+__db_dbbackup(dbenv, ip, dbfile, target, flags, oflags, full_path)
DB_ENV *dbenv;
DB_THREAD_INFO *ip;
const char *dbfile, *target;
u_int32_t flags;
+ u_int32_t oflags;
+ const char *full_path;
{
DB *dbp;
DB_FH *fp;
@@ -77,8 +80,8 @@ __db_dbbackup(dbenv, ip, dbfile, target, flags)
retry_count = 0;
retry: if ((ret = __db_create_internal(&dbp, dbenv->env, 0)) == 0 &&
- (ret = __db_open(dbp, ip, NULL, dbfile, NULL,
- DB_UNKNOWN, DB_AUTO_COMMIT | DB_RDONLY, 0, PGNO_BASE_MD)) != 0) {
+ (ret = __db_open(dbp, ip, NULL, dbfile, NULL, DB_UNKNOWN,
+ DB_AUTO_COMMIT | DB_RDONLY | oflags, 0, PGNO_BASE_MD)) != 0) {
if (ret == DB_LOCK_DEADLOCK || ret == DB_LOCK_NOTGRANTED) {
(void)__db_close(dbp, NULL, DB_NOSYNC);
dbp = NULL;
@@ -91,9 +94,16 @@ retry: if ((ret = __db_create_internal(&dbp, dbenv->env, 0)) == 0 &&
}
}
+ /* Hot backup requires DB_LOG_BLOB. */
+ if (ret == 0 && dbp->blob_threshold != 0 &&
+ (ret = backup_lgconf_chk(dbenv)) != 0)
+ goto err;
+
+ if (full_path == NULL)
+ full_path = dbfile;
if (ret == 0) {
if ((ret = __memp_backup_open(dbenv->env,
- dbp->mpf, dbfile, target, flags, &fp, &handle)) == 0) {
+ dbp->mpf, full_path, target, flags, &fp, &handle)) == 0) {
if (dbp->type == DB_HEAP)
ret = __heap_backup(
dbenv, dbp, ip, fp, handle, flags);
@@ -104,10 +114,21 @@ retry: if ((ret = __db_create_internal(&dbp, dbenv->env, 0)) == 0 &&
fp, handle, flags);
}
if ((t_ret = __memp_backup_close(dbenv->env,
- dbp->mpf, dbfile, fp, handle)) != 0 && ret == 0)
+ dbp->mpf, full_path, fp, handle)) != 0 && ret == 0)
ret = t_ret;
}
+ /*
+ * Copy blob files. Since no locking is done here, it is possible
+ * that a blob file may be copied in the middle of being written.
+ * This is not a problem since hotbackup requires DB_LOG_BLOB and
+ * catastrophic recovery, which will fix any inconsistances in the
+ * blob files.
+ */
+ if (ret == 0 && dbp->blob_threshold != 0 &&
+ (t_ret = __blob_copy_all(dbp, target, flags)) != 0)
+ ret= t_ret;
+
#ifdef HAVE_QUEUE
/*
* For compatibility with the 5.2 and patch versions of db_copy
@@ -117,7 +138,7 @@ retry: if ((ret = __db_create_internal(&dbp, dbenv->env, 0)) == 0 &&
ret = __qam_backup_extents(dbp, ip, target, flags);
#endif
- if (dbp != NULL &&
+err: if (dbp != NULL &&
(t_ret = __db_close(dbp, NULL, DB_NOSYNC)) != 0 && ret == 0)
ret = t_ret;
@@ -205,8 +226,11 @@ backup_dir_clean(dbenv, backup_dir, log_dir, remove_maxp, flags)
/*
* backup_data_copy --
* Copy a non-database file into the backup directory.
+ *
+ * PUBLIC: int backup_data_copy __P((
+ * PUBLIC: DB_ENV *, const char *, const char *, const char *, int));
*/
-static int
+int
backup_data_copy(dbenv, file, from_dir, to_dir, log)
DB_ENV *dbenv;
const char *file, *from_dir, *to_dir;
@@ -352,13 +376,16 @@ backup_read_data_dir(dbenv, ip, dir, backup_dir, flags)
ENV *env;
FILE *savefile;
int fcnt, ret;
- size_t cnt;
+ size_t cnt, len;
const char *bd;
char **names, buf[DB_MAXPATHLEN], bbuf[DB_MAXPATHLEN];
+ char fullpath[DB_MAXPATHLEN];
void (*savecall) (const DB_ENV *, const char *, const char *);
env = dbenv->env;
memset(bbuf, 0, sizeof(bbuf));
+ memset(fullpath, 0, sizeof(fullpath));
+ len = 0;
bd = backup_dir;
if (!LF_ISSET(DB_BACKUP_SINGLE_DIR) && dir != env->db_home) {
@@ -401,6 +428,12 @@ backup_read_data_dir(dbenv, ip, dir, backup_dir, flags)
"%s: path too long", "%s"), buf);
return (EINVAL);
}
+ /* Save the original dir. */
+ if (!LF_ISSET(DB_BACKUP_SINGLE_DIR)) {
+ (void)snprintf(fullpath, sizeof(fullpath),
+ "%s%c%c", dir, PATH_SEPARATOR[0], '\0');
+ len = strlen(fullpath);
+ }
dir = buf;
}
/* Get a list of file names. */
@@ -449,7 +482,16 @@ backup_read_data_dir(dbenv, ip, dir, backup_dir, flags)
savefile = dbenv->db_errfile;
dbenv->db_errfile = NULL;
- ret = __db_dbbackup(dbenv, ip, names[cnt], bd, flags);
+ /*
+ * If it is not backing up to a single directory, prefix
+ * the file with 'dir' so that the file and directory structure
+ * in the source and backup location will be the same.
+ */
+ if (len != 0)
+ (void)snprintf(fullpath + len,
+ sizeof(fullpath) - len, "%s%c", names[cnt], '\0');
+ ret = __db_dbbackup(dbenv, ip, names[cnt],
+ backup_dir, flags, 0, len != 0 ? fullpath : NULL);
dbenv->db_errcall = savecall;
dbenv->db_errfile = savefile;
@@ -662,21 +704,22 @@ err: if (logd != dbenv->db_log_dir && logd != env->db_home)
* __db_backup --
* Backup databases in the enviornment.
*
- * PUBLIC: int __db_backup __P((DB_ENV *, const char *, u_int32_t));
+ * PUBLIC: int __db_backup_pp __P((DB_ENV *, const char *, u_int32_t));
*/
int
-__db_backup(dbenv, target, flags)
+__db_backup_pp(dbenv, target, flags)
DB_ENV *dbenv;
const char *target;
u_int32_t flags;
{
DB_THREAD_INFO *ip;
ENV *env;
- int copy_min, remove_max, ret;
- char **dir;
+ u_int32_t bytes;
+ int remove_max, ret;
env = dbenv->env;
- remove_max = copy_min = 0;
+ bytes = 0;
+ remove_max = 0;
#undef OKFLAGS
#define OKFLAGS \
@@ -692,6 +735,11 @@ __db_backup(dbenv, target, flags)
return (EINVAL);
}
+ /* Hot backup requires DB_LOG_BLOB. */
+ if ((ret = __env_get_blob_threshold_int(env, &bytes)) != 0 ||
+ (bytes != 0 && (ret = backup_lgconf_chk(dbenv)) != 0))
+ return (ret);
+
/*
* If the target directory for the backup does not exist, create it
* with mode read-write-execute for the owner. Ignore errors here,
@@ -714,6 +762,30 @@ __db_backup(dbenv, target, flags)
}
ENV_ENTER(env, ip);
+ REPLICATION_WRAP(env,
+ (__db_backup(dbenv, target, ip, remove_max, flags)), 0, ret);
+ ENV_LEAVE(env, ip);
+ return (ret);
+}
+
+/*
+ * __db_backup --
+ * Backup databases in the enviornment.
+ */
+static int
+__db_backup(dbenv, target, ip, remove_max, flags)
+ DB_ENV *dbenv;
+ const char *target;
+ DB_THREAD_INFO *ip;
+ int remove_max;
+ u_int32_t flags;
+{
+ ENV *env;
+ int copy_min, ret;
+ char **dir;
+
+ env = dbenv->env;
+ copy_min = 0;
/*
* If the UPDATE option was not specified, copy all database
@@ -724,6 +796,19 @@ __db_backup(dbenv, target, flags)
goto end;
F_SET(dbenv, DB_ENV_HOTBACKUP);
if (!LF_ISSET(DB_BACKUP_UPDATE)) {
+ /*
+ * Don't allow absolute path of blob directory when
+ * it is not backing up to a single directory.
+ */
+ if (!LF_ISSET(DB_BACKUP_SINGLE_DIR) &&
+ dbenv->db_blob_dir != NULL &&
+ __os_abspath(dbenv->db_blob_dir)) {
+ __db_errx(env, DB_STR_A("0780",
+"blob directory '%s' is absolute path, not permitted unless backup is to a single directory",
+ "%s"), dbenv->db_blob_dir);
+ ret = EINVAL;
+ goto err;
+ }
if ((ret = backup_read_data_dir(dbenv,
ip, env->db_home, target, flags)) != 0)
goto err;
@@ -734,8 +819,8 @@ __db_backup(dbenv, target, flags)
* enviroment -- running recovery with them would
* corrupt the source files.
*/
- if (!LF_ISSET(DB_BACKUP_SINGLE_DIR)
- && __os_abspath(*dir)) {
+ if (!LF_ISSET(DB_BACKUP_SINGLE_DIR) &&
+ __os_abspath(*dir)) {
__db_errx(env, DB_STR_A("0725",
"data directory '%s' is absolute path, not permitted unless backup is to a single directory",
"%s"), *dir);
@@ -751,7 +836,17 @@ __db_backup(dbenv, target, flags)
/*
* Copy all log files found in the log directory.
* The log directory defaults to the home directory.
+ * Don't allow absolute path of log directory when
+ * it is not backing up to a single directory.
*/
+ if (!LF_ISSET(DB_BACKUP_SINGLE_DIR) &&
+ dbenv->db_log_dir != NULL && __os_abspath(dbenv->db_log_dir)) {
+ __db_errx(env, DB_STR_A("0781",
+"log directory '%s' is absolute path, not permitted unless backup is to a single directory",
+ "%s"), dbenv->db_log_dir);
+ ret = EINVAL;
+ goto err;
+ }
if ((ret = backup_read_log_dir(dbenv, target, &copy_min, flags)) != 0)
goto err;
/*
@@ -761,7 +856,7 @@ __db_backup(dbenv, target, flags)
* cleanup.
*/
if (LF_ISSET(DB_BACKUP_UPDATE) && remove_max < copy_min &&
- !(remove_max == 0 && copy_min == 1)) {
+ remove_max != 0 && copy_min != 1) {
__db_errx(env, DB_STR_A("0743",
"the largest log file removed (%d) must be greater than or equal the smallest log file copied (%d)",
"%d %d"), remove_max, copy_min);
@@ -770,6 +865,28 @@ __db_backup(dbenv, target, flags)
err: F_CLR(dbenv, DB_ENV_HOTBACKUP);
(void)__env_set_backup(env, 0);
-end: ENV_LEAVE(env, ip);
+end: return (ret);
+}
+
+/*
+ * __db_backup_fchk --
+ * Log configure checking for backup when blob is enabled.
+ */
+static int
+backup_lgconf_chk(dbenv)
+ DB_ENV *dbenv;
+{
+ int lgconf, ret;
+
+ ret = 0;
+
+ if (LOGGING_ON(dbenv->env) && ((ret = __log_get_config(dbenv,
+ DB_LOG_BLOB, &lgconf)) != 0 || lgconf == 0)) {
+ __db_errx(dbenv->env, DB_STR("0782",
+ "Hot backup requires DB_LOG_BLOB"));
+ if (ret == 0)
+ ret = EINVAL;
+ }
+
return (ret);
}