summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Bostic <keith@wiredtiger.com>2016-03-27 12:47:02 -0400
committerKeith Bostic <keith@wiredtiger.com>2016-03-27 12:47:02 -0400
commit45aa4385e43957970bfb8f768c63bf05afb5d5f8 (patch)
treed66a42e6b7cb812f0ac4f8a2c9662ea73152c6a0 /src
parent69b26f1f8338eee18fe0abdba43264e4cbfd443f (diff)
downloadmongo-45aa4385e43957970bfb8f768c63bf05afb5d5f8.tar.gz
WT-2330: in-memory configurations should not create on-disk collection files
The wt utility isn't syncing the enclosing directory on a backup file which leaves us potentially vulnerable on a crash on Linux. WiredTiger knows how to do the magic, so use a WiredTiger function to do the backup file copy. This also gets rid of some Windows-specific code in the wt utility.
Diffstat (limited to 'src')
-rw-r--r--src/include/extern.h1
-rw-r--r--src/support/filename.c66
-rw-r--r--src/utilities/util_backup.c102
3 files changed, 91 insertions, 78 deletions
diff --git a/src/include/extern.h b/src/include/extern.h
index f1fbdb4d30a..27e2ccb22de 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -609,6 +609,7 @@ extern int __wt_nfilename( WT_SESSION_IMPL *session, const char *name, size_t na
extern int __wt_remove_if_exists(WT_SESSION_IMPL *session, const char *name);
extern int __wt_rename_and_sync_directory( WT_SESSION_IMPL *session, const char *from, const char *to);
extern int __wt_sync_handle_and_rename( WT_SESSION_IMPL *session, WT_FH **fhp, const char *from, const char *to);
+extern int __wt_copy_and_sync(WT_SESSION *wt_session, const char *from, const char *to);
extern int __wt_library_init(void);
extern int __wt_breakpoint(void);
extern void __wt_attach(WT_SESSION_IMPL *session);
diff --git a/src/support/filename.c b/src/support/filename.c
index ac0aee5686e..b4858d2e982 100644
--- a/src/support/filename.c
+++ b/src/support/filename.c
@@ -123,3 +123,69 @@ __wt_sync_handle_and_rename(
return (__wt_rename_and_sync_directory(session, from, to));
}
+
+/*
+ * __wt_copy_and_sync --
+ * Copy a file safely; here to support the wt utility.
+ */
+int
+__wt_copy_and_sync(WT_SESSION *wt_session, const char *from, const char *to)
+{
+ WT_DECL_ITEM(tmp);
+ WT_DECL_RET;
+ WT_FH *ffh, *tfh;
+ WT_SESSION_IMPL *session;
+ size_t n;
+ wt_off_t offset, size;
+ char *buf;
+
+ session = (WT_SESSION_IMPL *)wt_session;
+ ffh = tfh = NULL;
+ buf = NULL;
+
+ /*
+ * Remove the target file if it exists, then create a temporary file,
+ * copy the original into it and rename it into place. I don't think
+ * its necessary to remove the file, or create a copy and do a rename,
+ * it's likely safe to overwrite the backup file directly. I'm doing
+ * the remove and rename to insulate us from errors in other programs
+ * that might not detect a corrupted backup file; it's cheap insurance
+ * in a path where undetected failure is very bad.
+ */
+ WT_RET(__wt_remove_if_exists(session, to));
+
+ WT_ERR(__wt_scr_alloc(session, 0, &tmp));
+ WT_ERR(__wt_buf_fmt(session, tmp, "%s.copy", to));
+
+ /* Open the from and temporary file handles. */
+ WT_ERR(__wt_open(session, from,
+ WT_FILE_TYPE_REGULAR, WT_OPEN_READONLY, &ffh));
+ WT_ERR(__wt_open(session, tmp->data,
+ WT_FILE_TYPE_REGULAR, WT_OPEN_CREATE | WT_OPEN_EXCLUSIVE, &tfh));
+
+ /*
+ * Allocate a copy buffer. Don't use a scratch buffer, this thing is
+ * big, and we don't want it hanging around.
+ */
+#define WT_BACKUP_COPY_SIZE (128 * 1024)
+ WT_ERR(__wt_malloc(session, WT_BACKUP_COPY_SIZE, &buf));
+
+ /* Get the file's size, then copy the bytes. */
+ WT_ERR(__wt_filesize(session, ffh, &size));
+ for (offset = 0; size > 0; size -= n, offset += n) {
+ n = (size_t)WT_MIN(size, WT_BACKUP_COPY_SIZE);
+ WT_ERR(__wt_read(session, ffh, offset, n, buf));
+ WT_ERR(__wt_write(session, tfh, offset, n, buf));
+ }
+
+ /* Close the from handle, then swap the temporary file into place. */
+ WT_ERR(__wt_close(session, &ffh));
+ ret = __wt_sync_handle_and_rename(session, &tfh, tmp->data, to);
+
+err: WT_TRET(__wt_close(session, &ffh));
+ WT_TRET(__wt_close(session, &tfh));
+
+ __wt_free(session, buf);
+ __wt_scr_free(session, &tmp);
+ return (ret);
+}
diff --git a/src/utilities/util_backup.c b/src/utilities/util_backup.c
index b3afc78e9e8..55c0e336111 100644
--- a/src/utilities/util_backup.c
+++ b/src/utilities/util_backup.c
@@ -8,12 +8,9 @@
#include "util.h"
-static int copy(const char *, const char *);
+static int copy(WT_SESSION *, const char *, const char *);
static int usage(void);
-#define CBUF_LEN (128 * 1024) /* Copy buffer and size. */
-static char *cbuf;
-
/*
* append_target --
* Build a list of comma-separated targets.
@@ -86,7 +83,7 @@ util_backup(WT_SESSION *session, int argc, char *argv[])
while (
(ret = cursor->next(cursor)) == 0 &&
(ret = cursor->get_key(cursor, &name)) == 0)
- if ((ret = copy(name, directory)) != 0)
+ if ((ret = copy(session, name, directory)) != 0)
goto err;
if (ret == WT_NOTFOUND)
ret = 0;
@@ -98,97 +95,46 @@ util_backup(WT_SESSION *session, int argc, char *argv[])
}
err: free(config);
- free(cbuf);
-
return (ret);
}
static int
-copy(const char *name, const char *directory)
+copy(WT_SESSION *session, const char *name, const char *directory)
{
WT_DECL_RET;
- ssize_t n;
- int ifd, ofd;
+ size_t len;
+ char *from, *to;
- ret = 1;
- ifd = ofd = -1;
+ from = to = NULL;
- if (verbose &&
- printf("Backing up %s/%s to %s\n", home, name, directory) < 0) {
- fprintf(stderr, "%s: %s\n", progname, strerror(errno));
- return (1);
- }
-
- /* Allocate a large copy buffer (use it to build pathnames as well. */
- if (cbuf == NULL && (cbuf = malloc(CBUF_LEN)) == NULL)
+ /* Build the 2 pathnames we need. */
+ len = strlen(home) + strlen(name) + 2;
+ if ((from = malloc(len)) == NULL)
goto memerr;
-
- /* Open the read file. */
- if (snprintf(cbuf, CBUF_LEN, "%s/%s", home, name) >= CBUF_LEN)
+ (void)snprintf(from, len, "%s/%s", home, name);
+ len = strlen(directory) + strlen(name) + 2;
+ if ((to = malloc(len)) == NULL)
goto memerr;
- if ((ifd = open(cbuf, O_BINARY | O_RDONLY, 0)) < 0)
- goto readerr;
+ (void)snprintf(to, len, "%s/%s", directory, name);
- /* Open the write file. */
- if (snprintf(cbuf, CBUF_LEN, "%s/%s", directory, name) >= CBUF_LEN)
- goto memerr;
- if ((ofd = open(
- cbuf, O_BINARY | O_CREAT | O_WRONLY | O_TRUNC, 0666)) < 0)
- goto writerr;
-
- /* Copy the file. */
- while ((n = read(ifd, cbuf, CBUF_LEN)) > 0)
- if (write(ofd, cbuf, (size_t)n) != n)
- goto writerr;
- if (n != 0)
- goto readerr;
-
- /*
- * Close file descriptors (forcing a flush on the write side), and
- * check for any errors.
- */
- ret = close(ifd);
- ifd = -1;
- if (ret != 0)
- goto readerr;
+ if (verbose && printf("Backing up %s to %s\n", from, to) < 0) {
+ fprintf(stderr, "%s: %s\n", progname, strerror(EIO));
+ goto err;
+ }
/*
- * We need to know this file was successfully written, it's a backup.
+ * Use WiredTiger to copy the file: ensuring stability of the copied
+ * file on disk requires care, and WiredTiger knows how to do it.
*/
-#ifdef _WIN32
- if (FlushFileBuffers((HANDLE)_get_osfhandle(ofd)) == 0) {
- DWORD err = GetLastError();
- ret = err;
- goto writerr;
- }
-#else
- if (fsync(ofd))
- goto writerr;
-#endif
- ret = close(ofd);
- ofd = -1;
- if (ret != 0)
- goto writerr;
-
- /* Success. */
- ret = 0;
+ if ((ret = __wt_copy_and_sync(session, from, to)) != 0)
+ fprintf(stderr, "%s to %s: backup copy: %s\n",
+ from, to, session->strerror(session, ret));
if (0) {
-readerr: fprintf(stderr,
- "%s: %s/%s: %s\n", progname, home, name, strerror(errno));
- }
- if (0) {
-writerr: fprintf(stderr, "%s: %s/%s: %s\n",
- progname, directory, name, strerror(errno));
- }
- if (0) {
memerr: fprintf(stderr, "%s: %s\n", progname, strerror(errno));
}
-
- if (ifd >= 0)
- (void)close(ifd);
- if (ofd >= 0)
- (void)close(ofd);
+err: free(from);
+ free(to);
return (ret);
}