Add mdb_env_copyfd()

Allow writing backup to an already opened file handle, for piping
to tar/gzip/ssh/whatever.
vmware
Howard Chu 12 years ago
parent 4b49291653
commit c68e5ae9be
  1. 19
      libraries/liblmdb/lmdb.h
  2. 107
      libraries/liblmdb/mdb.c
  3. 8
      libraries/liblmdb/mdb_copy.1
  4. 9
      libraries/liblmdb/mdb_copy.c

@ -144,6 +144,14 @@ typedef int mdb_mode_t;
typedef mode_t mdb_mode_t; typedef mode_t mdb_mode_t;
#endif #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 /** @defgroup mdb MDB API
* @{ * @{
* @brief OpenLDAP Lightning Memory-Mapped Database Manager * @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); 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. /** @brief Return statistics about the MDB environment.
* *
* @param[in] env An environment handle returned by #mdb_env_create() * @param[in] env An environment handle returned by #mdb_env_create()

@ -199,12 +199,6 @@ mdb_sem_wait(sem_t *sem)
*/ */
#define ErrCode() errno #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. /** A value for an invalid file handle.
* Mainly used to initialize file variables and signify that they are * Mainly used to initialize file variables and signify that they are
* unused. * unused.
@ -3631,60 +3625,20 @@ mdb_env_close0(MDB_env *env, int excl)
} }
int int
mdb_env_copy(MDB_env *env, const char *path) mdb_env_copyfd(MDB_env *env, int fd)
{ {
MDB_txn *txn = NULL; MDB_txn *txn = NULL;
int rc, len; int rc;
size_t wsize; size_t wsize;
char *lpath, *ptr; char *ptr;
HANDLE newfd = INVALID_HANDLE_VALUE; 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 /* Do the lock/unlock of the reader mutex before starting the
* write txn. Otherwise other read txns could block writers. * write txn. Otherwise other read txns could block writers.
*/ */
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn); rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
if (rc) if (rc)
goto leave; return rc;
if (env->me_txns) { if (env->me_txns) {
/* We must start the actual read txn after blocking writers */ /* We must start the actual read txn after blocking writers */
@ -3751,6 +3705,59 @@ mdb_env_copy(MDB_env *env, const char *path)
leave: leave:
mdb_txn_abort(txn); 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) if (newfd != INVALID_HANDLE_VALUE)
close(newfd); close(newfd);

@ -5,12 +5,18 @@
mdb_copy \- LMDB environment copy tool mdb_copy \- LMDB environment copy tool
.SH SYNOPSIS .SH SYNOPSIS
.B mdb_copy .B mdb_copy
.I srcpath\ dstpath .I srcpath\ [dstpath]
.SH DESCRIPTION .SH DESCRIPTION
The The
.B mdb_copy .B mdb_copy
utility copies an LMDB environment. The environment can utility copies an LMDB environment. The environment can
be copied regardless of whether it is currently in use. 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 .SH DIAGNOSTICS
Exit status is zero if no errors occur. Exit status is zero if no errors occur.
Errors result in a non-zero exit status and Errors result in a non-zero exit status and

@ -21,8 +21,8 @@ int main(int argc,char * argv[])
MDB_env *env; MDB_env *env;
char *envname = argv[1]; char *envname = argv[1];
if (argc != 3) { if (argc<2 || argc>3) {
fprintf(stderr, "usage: %s srcpath dstpath\n", argv[0]); fprintf(stderr, "usage: %s srcpath [dstpath]\n", argv[0]);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -32,7 +32,10 @@ int main(int argc,char * argv[])
if (rc) { if (rc) {
printf("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc)); printf("mdb_env_open failed, error %d %s\n", rc, mdb_strerror(rc));
} else { } 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) if (rc)
printf("mdb_env_copy failed, error %d %s\n", rc, mdb_strerror(rc)); printf("mdb_env_copy failed, error %d %s\n", rc, mdb_strerror(rc));
} }

Loading…
Cancel
Save