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

Add mdb_env_copyfd()

Allow writing backup to an already opened file handle, for piping
to tar/gzip/ssh/whatever.
parent 4b492916
......@@ -144,6 +144,14 @@ typedef int mdb_mode_t;
typedef mode_t mdb_mode_t;
#endif
#ifndef _WIN32
/** An abstraction for a file handle.
* On POSIX systems file handles are small integers. On Windows
* they're opaque pointers.
*/
#define HANDLE int
#endif
/** @defgroup mdb MDB API
* @{
* @brief OpenLDAP Lightning Memory-Mapped Database Manager
......@@ -533,6 +541,17 @@ int mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t
*/
int mdb_env_copy(MDB_env *env, const char *path);
/** @brief Copy an MDB environment to the specified file descriptor.
*
* 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] fd The filedescriptor to write the copy to. It must
* have already been opened for Write access.
* @return A non-zero error value on failure and 0 on success.
*/
int mdb_env_copyfd(MDB_env *env, HANDLE fd);
/** @brief Return statistics about the MDB environment.
*
* @param[in] env An environment handle returned by #mdb_env_create()
......
......@@ -199,12 +199,6 @@ mdb_sem_wait(sem_t *sem)
*/
#define ErrCode() errno
/** An abstraction for a file handle.
* On POSIX systems file handles are small integers. On Windows
* they're opaque pointers.
*/
#define HANDLE int
/** A value for an invalid file handle.
* Mainly used to initialize file variables and signify that they are
* unused.
......@@ -3631,60 +3625,20 @@ mdb_env_close0(MDB_env *env, int excl)
}
int
mdb_env_copy(MDB_env *env, const char *path)
mdb_env_copyfd(MDB_env *env, int fd)
{
MDB_txn *txn = NULL;
int rc, len;
int rc;
size_t wsize;
char *lpath, *ptr;
char *ptr;
HANDLE newfd = INVALID_HANDLE_VALUE;
if (env->me_flags & MDB_NOSUBDIR) {
lpath = (char *)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
/* Do the lock/unlock of the reader mutex before starting the
* write txn. Otherwise other read txns could block writers.
*/
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
if (rc)
goto leave;
return rc;
if (env->me_txns) {
/* We must start the actual read txn after blocking writers */
......@@ -3751,6 +3705,59 @@ mdb_env_copy(MDB_env *env, const char *path)
leave:
mdb_txn_abort(txn);
return rc;
}
int
mdb_env_copy(MDB_env *env, const char *path)
{
int rc, len;
char *lpath;
HANDLE newfd = INVALID_HANDLE_VALUE;
if (env->me_flags & MDB_NOSUBDIR) {
lpath = (char *)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
rc = mdb_env_copyfd(env, newfd);
leave:
if (newfd != INVALID_HANDLE_VALUE)
close(newfd);
......
......@@ -5,12 +5,18 @@
mdb_copy \- LMDB environment copy tool
.SH SYNOPSIS
.B mdb_copy
.I srcpath\ dstpath
.I srcpath\ [dstpath]
.SH DESCRIPTION
The
.B mdb_copy
utility copies an LMDB environment. The environment can
be copied regardless of whether it is currently in use.
If
.I dstpath
is specified it must be the path of an empty directory
for storing the backup. Otherwise, the backup will be
written to stdout.
.SH DIAGNOSTICS
Exit status is zero if no errors occur.
Errors result in a non-zero exit status and
......
......@@ -21,8 +21,8 @@ int main(int argc,char * argv[])
MDB_env *env;
char *envname = argv[1];
if (argc != 3) {
fprintf(stderr, "usage: %s srcpath dstpath\n", argv[0]);
if (argc<2 || argc>3) {
fprintf(stderr, "usage: %s srcpath [dstpath]\n", argv[0]);
exit(EXIT_FAILURE);
}
......@@ -32,7 +32,10 @@ int main(int argc,char * argv[])
if (rc) {
printf("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
} else {
rc = mdb_env_copy(env, argv[2]);
if (argc == 2)
rc = mdb_env_copyfd(env, 1);
else
rc = mdb_env_copy(env, argv[2]);
if (rc)
printf("mdb_env_copy failed, error %d %s\n", rc, mdb_strerror(rc));
}
......
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