diff --git a/src/cursor/cur_backup.c b/src/cursor/cur_backup.c index fd416d3c4..0dfe15470 100644 --- a/src/cursor/cur_backup.c +++ b/src/cursor/cur_backup.c @@ -618,10 +618,6 @@ __backup_config(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *cfg[ F_SET(cb, WT_CURBACKUP_INCR); } - /* Return an error if block-based incremental backup is performed with open LSM trees. */ - if (incremental_config && !TAILQ_EMPTY(&conn->lsmqh)) - WT_ERR_MSG(session, ENOTSUP, "LSM does not work with block-based incremental backup"); - err: if (ret != 0 && cb->incr_src != NULL) { F_CLR(cb->incr_src, WT_BLKINCR_INUSE); diff --git a/test/format/backup.c b/test/format/backup.c index 8ec113dd6..438bc22db 100644 --- a/test/format/backup.c +++ b/test/format/backup.c @@ -234,27 +234,45 @@ active_files_free(ACTIVE_FILES *active) /* * copy_blocks -- * Perform a single block-based incremental backup of the given file. + * It's possible there will be no changes listed for the file, when that happens + * we don't create the backup file. We return a boolean value indicating we created + * the file. */ -static void +static bool copy_blocks(WT_SESSION *session, WT_CURSOR *bkup_c, const char *name) { WT_CURSOR *incr_cur; WT_DECL_RET; size_t len, tmp_sz; ssize_t rdsize; + uint32_t usec; uint64_t offset, size, this_size, total, type; int rfd, wfd1, wfd2; char config[512], *tmp; - bool first_pass; + bool created, first_pass; tmp_sz = 0; tmp = NULL; + created = false; first_pass = true; rfd = wfd1 = wfd2 = -1; - /* Open the duplicate incremental backup cursor with the file name given. */ + /* + * Open the duplicate incremental backup cursor with the file name given. LSM backup cursors + * can return EBUSY, so retry up to a second. + */ testutil_check(__wt_snprintf(config, sizeof(config), "incremental=(file=%s)", name)); - testutil_check(session->open_cursor(session, NULL, bkup_c, config, &incr_cur)); + usec = 1; + do { + ret = session->open_cursor(session, NULL, bkup_c, config, &incr_cur); + if (ret != EBUSY) + break; + __wt_sleep(0, usec); + fprintf(stderr, "retry: %d\n", (int)usec); + usec <<= 1; + } while (usec < WT_MILLION); + testutil_check(ret); + while ((ret = incr_cur->next(incr_cur)) == 0) { testutil_check(incr_cur->get_key(incr_cur, &offset, &size, &type)); if (type == WT_BACKUP_RANGE) { @@ -276,6 +294,7 @@ copy_blocks(WT_SESSION *session, WT_CURSOR *bkup_c, const char *name) error_sys_check(wfd1 = open(tmp, O_WRONLY | O_CREAT, 0644)); free(tmp); tmp = NULL; + created = true; len = strlen(g.home) + strlen("BACKUP.copy") + strlen(name) + 10; tmp = dmalloc(len); @@ -330,6 +349,7 @@ copy_blocks(WT_SESSION *session, WT_CURSOR *bkup_c, const char *name) testutil_check(__wt_copy_and_sync(session, name, tmp)); free(tmp); tmp = NULL; + created = true; len = strlen("BACKUP.copy") + strlen(name) + 10; tmp = dmalloc(len); @@ -346,7 +366,23 @@ copy_blocks(WT_SESSION *session, WT_CURSOR *bkup_c, const char *name) error_sys_check(close(wfd1)); error_sys_check(close(wfd2)); } + free(tmp); + + /* Even if we didn't create it this time, if it was previously created, return that. */ + if (!created) { + len = strlen(g.home) + strlen("BACKUP") + strlen(name) + 10; + tmp = dmalloc(len); + testutil_check(__wt_snprintf(tmp, len, "%s/BACKUP/%s", g.home, name)); + if (access(tmp, 0) == 0) + created = true; + free(tmp); + tmp = NULL; + } + if (!created) + fprintf(stderr, "\n*** BACKUP: %s: not created\n", name); + + return (created); } #define RESTORE_SKIP 1 @@ -478,7 +514,7 @@ backup(void *arg) uint64_t src_id, this_id; const char *config, *key; char cfg[512]; - bool full, incr_full; + bool created, full, incr_full; (void)(arg); @@ -595,15 +631,20 @@ backup(void *arg) while ((ret = backup_cursor->next(backup_cursor)) == 0) { testutil_check(backup_cursor->get_key(backup_cursor, &key)); + /* + * We will almost always create the file in the backup directory. However, if we're + * doing an incremental backup, we will only create it if we see individual changes. + */ + created = true; if (g.c_backup_incr_flag == INCREMENTAL_BLOCK) { if (full) testutil_copy_file(session, key); else - copy_blocks(session, backup_cursor, key); - + created = copy_blocks(session, backup_cursor, key); } else testutil_copy_file(session, key); - active_files_add(active_now, key); + if (created) + active_files_add(active_now, key); } if (ret != WT_NOTFOUND) testutil_die(ret, "backup-cursor"); diff --git a/test/format/config.c b/test/format/config.c index 88964902d..0479f5a88 100644 --- a/test/format/config.c +++ b/test/format/config.c @@ -825,28 +825,6 @@ config_lsm_reset(void) config_single("ops.prepare=off", false); config_single("transaction.timestamps=off", false); } - - /* - * LSM does not work with block-based incremental backup, change the incremental backup - * mechanism if block based in configured. - */ - if (g.c_backups) { - if (config_is_perm("backup.incremental") && g.c_backup_incr_flag == INCREMENTAL_BLOCK) - testutil_die(EINVAL, "LSM does not work with backup.incremental=block configuration."); - - if (g.c_backup_incr_flag == INCREMENTAL_BLOCK) - switch (mmrand(NULL, 1, 2)) { - case 1: - /* 50% */ - config_single("backup.incremental=off", false); - break; - case 2: - /* 50% */ - config_single("backup.incremental=log", false); - config_backup_incr_log_compatibility_check(); - break; - } - } } /*