Commit ebb6859e authored by Howard Chu's avatar Howard Chu
Browse files

Add mdb_copy for backing up a DB environment

parent 756ce8e1
......@@ -5,7 +5,7 @@ CFLAGS = -pthread $(OPT) $(W) $(XCFLAGS)
LDLIBS =
SOLIBS =
PROGS = mdb_stat mtest mtest2 mtest3 mtest4 mtest5
PROGS = mdb_stat mdb_copy mtest mtest2 mtest3 mtest4 mtest5
all: libmdb.a libmdb.so $(PROGS)
clean:
......@@ -22,6 +22,7 @@ libmdb.so: mdb.o midl.o
gcc -pthread -shared -o $@ mdb.o midl.o $(SOLIBS)
mdb_stat: mdb_stat.o libmdb.a
mdb_copy: mdb_copy.o libmdb.a
mtest: mtest.o libmdb.a
mtest2: mtest2.o libmdb.a
mtest3: mtest3.o libmdb.a
......
......@@ -32,6 +32,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
......@@ -3280,6 +3281,101 @@ mdb_env_close0(MDB_env *env, int excl)
env->me_lfd = INVALID_HANDLE_VALUE; /* Mark env as reset */
}
int
mdb_env_copy(MDB_env *env, const char *path)
{
MDB_txn *txn = NULL;
int rc, len, oflags;
size_t wsize;
char *lpath, *ptr;
HANDLE newfd = INVALID_HANDLE_VALUE;
if (env->me_flags & MDB_NOSUBDIR) {
lpath = path;
} else {
len = strlen(path);
len += sizeof(DATANAME);
lpath = malloc(len);
if (!lpath)
return ENOMEM;
sprintf(lpath, "%s" DATANAME, path);
}
/* The destination path must exist, but the destination file must not.
* We don't want the OS to cache the writes, since the source data is
* already in the OS cache.
*/
#ifdef _WIN32
newfd = CreateFile(lpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
#else
newfd = open(lpath, O_WRONLY|O_CREAT|O_EXCL
#ifdef O_DIRECT
|O_DIRECT
#endif
, 0666);
#endif
if (!(env->me_flags & MDB_NOSUBDIR))
free(lpath);
if (newfd == INVALID_HANDLE_VALUE) {
rc = ErrCode();
goto leave;
}
#ifdef F_NOCACHE /* __APPLE__ */
rc = fcntl(newfd, F_NOCACHE, 1);
if (rc) {
rc = ErrCode();
goto leave;
}
#endif
/* Temporarily block writers until we snapshot the meta pages */
LOCK_MUTEX_W(env);
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
if (rc) {
UNLOCK_MUTEX_W(env);
goto leave;
}
wsize = env->me_psize * 2;
#ifdef _WIN32
{
DWORD len;
rc = WriteFile(newfd, env->me_map, wsize, &len, NULL);
rc = (len == wsize) ? MDB_SUCCESS : ErrCode();
}
#else
rc = write(newfd, env->me_map, wsize);
rc = (rc == (int)wsize) ? MDB_SUCCESS : ErrCode();
#endif
UNLOCK_MUTEX_W(env);
if (rc)
goto leave;
ptr = env->me_map + wsize;
wsize = txn->mt_next_pgno * env->me_psize - wsize;
#ifdef _WIN32
{
DWORD len;
rc = WriteFile(newfd, ptr, wsize, &len, NULL);
rc = (len == wsize) ? MDB_SUCCESS : ErrCode();
}
#else
rc = write(newfd, ptr, wsize);
rc = (rc == (int)wsize) ? MDB_SUCCESS : ErrCode();
#endif
mdb_txn_abort(txn);
leave:
if (newfd != INVALID_HANDLE_VALUE)
close(newfd);
return rc;
}
void
mdb_env_close(MDB_env *env)
{
......
......@@ -450,6 +450,18 @@ int mdb_env_create(MDB_env **env);
*/
int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mode_t mode);
/** @brief Copy an MDB environment to the specified path.
*
* This function may be used to make a backup of an existing environment.
* @param[in] env An environment handle returned by #mdb_env_create(). It
* must have already been opened successfully.
* @param[in] path The directory in which the copy will reside. This
* directory must already exist and be writable but must otherwise be
* empty.
* @return A non-zero error value on failure and 0 on success.
*/
int mdb_env_copy(MDB_env *env, const char *path);
/** @brief Return statistics about the MDB environment.
*
* @param[in] env An environment handle returned by #mdb_env_create()
......
/* mdb_copy.c - memory-mapped database backup tool */
/*
* Copyright 2012 Howard Chu, Symas Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "mdb.h"
int main(int argc,char * argv[])
{
int rc;
MDB_env *env;
char *envname = argv[1];
if (argc != 3) {
fprintf(stderr, "usage: %s srcpath dstpath\n", argv[0]);
exit(EXIT_FAILURE);
}
rc = mdb_env_create(&env);
rc = mdb_env_open(env, envname, MDB_RDONLY, 0);
if (rc) {
printf("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
} else {
rc = mdb_env_copy(env, argv[2]);
if (rc)
printf("mdb_env_copy failed, error %d %s\n", rc, mdb_strerror(rc));
}
mdb_env_close(env);
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment