* 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>
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)
{
*/
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()
--- /dev/null
+/* 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;
+}