Move opening files to mdb_fopen()

No change in functionality.
mdb.RE/0.9
Hallvard Furuseth 8 years ago
parent 3faef632a0
commit 9c76e95dbe
  1. 218
      libraries/liblmdb/mdb.c

@ -4142,16 +4142,122 @@ mdb_fname_init(const char *path, unsigned envflags, MDB_name *fname)
#define mdb_fname_destroy(fname) \ #define mdb_fname_destroy(fname) \
do { if ((fname).mn_alloced) free((fname).mn_val); } while (0) do { if ((fname).mn_alloced) free((fname).mn_val); } while (0)
#ifdef O_CLOEXEC /* POSIX.1-2008: Set FD_CLOEXEC atomically at open() */
# define MDB_CLOEXEC O_CLOEXEC
#else
# define MDB_CLOEXEC 0
#endif
/** File type, access mode etc. for #mdb_fopen() */
enum mdb_fopen_type { enum mdb_fopen_type {
MDB_O_DATA, MDB_O_LOCKS #ifdef _WIN32
MDB_O_RDONLY, MDB_O_RDWR, MDB_O_META, MDB_O_COPY, MDB_O_LOCKS
#else
/* A comment in mdb_fopen() explains some O_* flag choices. */
MDB_O_RDONLY= O_RDONLY, /**< for RDONLY me_fd */
MDB_O_RDWR = O_RDWR |O_CREAT, /**< for me_fd */
MDB_O_META = O_RDWR |MDB_DSYNC, /**< for me_mfd */
MDB_O_COPY = O_WRONLY|O_CREAT|O_EXCL, /**< for #mdb_env_copy() */
/** Bitmask for open() flags in enum #mdb_fopen_type. The other bits
* distinguish otherwise-equal MDB_O_* constants from each other.
*/
MDB_O_MASK = MDB_O_RDWR|MDB_CLOEXEC | MDB_O_RDONLY|MDB_O_META|MDB_O_COPY,
MDB_O_LOCKS = MDB_O_RDWR|MDB_CLOEXEC | ((MDB_O_MASK+1) & ~MDB_O_MASK) /**< for me_lfd */
#endif
}; };
static void ESECT /** Open an LMDB file.
mdb_fname_suffix_set(MDB_env *env, MDB_name *fname, enum mdb_fopen_type which) * @param[in] env The LMDB environment.
* @param[in,out] fname Path from from #mdb_fname_init(). A suffix is
* appended if necessary to create the filename, without changing mn_len.
* @param[in] which Determines file type, access mode, etc.
* @param[in] mode The Unix permissions for the file, if we create it.
* @param[out] res Resulting file handle.
* @return 0 on success, non-zero on failure.
*/
static int ESECT
mdb_fopen(const MDB_env *env, MDB_name *fname,
enum mdb_fopen_type which, mdb_mode_t mode,
HANDLE *res)
{ {
int rc = MDB_SUCCESS;
HANDLE fd;
#ifdef _WIN32
DWORD acc, share, disp, attrs;
#else
int flags;
#endif
if (fname->mn_alloced) /* modifiable copy */ if (fname->mn_alloced) /* modifiable copy */
mdb_name_cpy(fname->mn_val + fname->mn_len, mdb_name_cpy(fname->mn_val + fname->mn_len,
mdb_suffixes[which==MDB_O_LOCKS][F_ISSET(env->me_flags, MDB_NOSUBDIR)]); mdb_suffixes[which==MDB_O_LOCKS][F_ISSET(env->me_flags, MDB_NOSUBDIR)]);
/* The directory must already exist. Usually the file need not.
* MDB_O_META requires the file because we already created it using
* MDB_O_RDWR. MDB_O_COPY must not overwrite an existing file.
*
* With MDB_O_COPY we do not want the OS to cache the writes, since
* the source data is already in the OS cache.
*
* The lockfile needs FD_CLOEXEC (close file descriptor on exec*())
* to avoid the flock() issues noted under Caveats in lmdb.h.
*/
#ifdef _WIN32
acc = GENERIC_READ|GENERIC_WRITE;
share = FILE_SHARE_READ|FILE_SHARE_WRITE;
disp = OPEN_ALWAYS;
attrs = FILE_ATTRIBUTE_NORMAL;
switch (which) {
case MDB_O_RDONLY: /* read-only datafile */
acc = GENERIC_READ;
disp = OPEN_EXISTING;
break;
case MDB_O_META: /* for writing metapages */
disp = OPEN_EXISTING;
attrs = FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH;
break;
case MDB_O_COPY: /* mdb_env_copy() & co */
acc = GENERIC_WRITE;
share = 0;
disp = CREATE_NEW;
attrs = FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH;
break;
default: break; /* silence gcc -Wswitch (not all enum values handled) */
}
fd = CreateFileW(fname->mn_val, acc, share, NULL, disp, attrs, NULL);
#else
fd = open(fname->mn_val, which & MDB_O_MASK, mode);
#endif
if (fd == INVALID_HANDLE_VALUE)
rc = ErrCode();
#ifndef _WIN32
else {
if (which == MDB_O_LOCKS) {
/* Set CLOEXEC if we could not pass it to open() */
if (!MDB_CLOEXEC && (flags = fcntl(fd, F_GETFD)) != -1)
(void) fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
}
if (which == MDB_O_COPY && env->me_psize >= env->me_os_psize) {
/* This may require buffer alignment. There is no portable
* way to ask how much, so we require OS pagesize alignment.
*/
# ifdef F_NOCACHE /* __APPLE__ */
(void) fcntl(fd, F_NOCACHE, 1);
# elif defined O_DIRECT
/* open(...O_DIRECT...) would break on filesystems without
* O_DIRECT support (ITS#7682). Try to set it here instead.
*/
if ((flags = fcntl(fd, F_GETFL)) != -1)
(void) fcntl(fd, F_SETFL, flags | O_DIRECT);
# endif
}
}
#endif /* !_WIN32 */
*res = fd;
return rc;
} }
@ -4572,36 +4678,18 @@ mdb_env_setup_locks(MDB_env *env, MDB_name *fname, int mode, int *excl)
# define MDB_ERRCODE_ROFS ERROR_WRITE_PROTECT # define MDB_ERRCODE_ROFS ERROR_WRITE_PROTECT
#else #else
# define MDB_ERRCODE_ROFS EROFS # define MDB_ERRCODE_ROFS EROFS
#ifdef O_CLOEXEC /* Linux: Open file and set FD_CLOEXEC atomically */
# define MDB_CLOEXEC O_CLOEXEC
#else
# define MDB_CLOEXEC 0
#endif
int fdflags;
#endif #endif
int rc; int rc;
off_t size, rsize; off_t size, rsize;
mdb_fname_suffix_set(env, fname, MDB_O_LOCKS); rc = mdb_fopen(env, fname, MDB_O_LOCKS, mode, &env->me_lfd);
#ifdef _WIN32 if (rc) {
env->me_lfd = CreateFileW(fname->mn_val, GENERIC_READ|GENERIC_WRITE, /* Omit lockfile if read-only env on read-only filesystem */
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
#else
env->me_lfd = open(fname->mn_val, O_RDWR|O_CREAT|MDB_CLOEXEC, mode);
#endif
if (env->me_lfd == INVALID_HANDLE_VALUE) {
rc = ErrCode();
if (rc == MDB_ERRCODE_ROFS && (env->me_flags & MDB_RDONLY)) { if (rc == MDB_ERRCODE_ROFS && (env->me_flags & MDB_RDONLY)) {
return MDB_SUCCESS; return MDB_SUCCESS;
} }
goto fail; goto fail;
} }
#ifndef _WIN32
/* Lose record locks when exec*() */
if (!(MDB_CLOEXEC) && (fdflags = fcntl(env->me_lfd, F_GETFD)) != -1)
fcntl(env->me_lfd, F_SETFD, fdflags | FD_CLOEXEC);
#endif
if (!(env->me_flags & MDB_NOTLS)) { if (!(env->me_flags & MDB_NOTLS)) {
rc = pthread_key_create(&env->me_txkey, mdb_env_reader_dest); rc = pthread_key_create(&env->me_txkey, mdb_env_reader_dest);
@ -4806,7 +4894,7 @@ fail:
int ESECT int ESECT
mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode) mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode)
{ {
int oflags, rc, len, excl = -1; int rc, excl = -1;
MDB_name fname; MDB_name fname;
if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS))) if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS)))
@ -4847,30 +4935,11 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
goto leave; goto leave;
} }
mdb_fname_suffix_set(env, &fname, MDB_O_DATA); rc = mdb_fopen(env, &fname,
#ifdef _WIN32 (flags & MDB_RDONLY) ? MDB_O_RDONLY : MDB_O_RDWR,
if (F_ISSET(flags, MDB_RDONLY)) { mode, &env->me_fd);
oflags = GENERIC_READ; if (rc)
len = OPEN_EXISTING;
} else {
oflags = GENERIC_READ|GENERIC_WRITE;
len = OPEN_ALWAYS;
}
mode = FILE_ATTRIBUTE_NORMAL;
env->me_fd = CreateFileW(fname.mn_val, oflags, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, len, mode, NULL);
#else
if (F_ISSET(flags, MDB_RDONLY))
oflags = O_RDONLY;
else
oflags = O_RDWR | O_CREAT;
env->me_fd = open(fname.mn_val, oflags, mode);
#endif
if (env->me_fd == INVALID_HANDLE_VALUE) {
rc = ErrCode();
goto leave; goto leave;
}
if ((flags & (MDB_RDONLY|MDB_NOLOCK)) == MDB_RDONLY) { if ((flags & (MDB_RDONLY|MDB_NOLOCK)) == MDB_RDONLY) {
rc = mdb_env_setup_locks(env, &fname, mode, &excl); rc = mdb_env_setup_locks(env, &fname, mode, &excl);
@ -4885,21 +4954,10 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
/* Synchronous fd for meta writes. Needed even with /* Synchronous fd for meta writes. Needed even with
* MDB_NOSYNC/MDB_NOMETASYNC, in case these get reset. * MDB_NOSYNC/MDB_NOMETASYNC, in case these get reset.
*/ */
mdb_fname_suffix_set(env, &fname, MDB_O_DATA); rc = mdb_fopen(env, &fname, MDB_O_META, mode, &env->me_mfd);
#ifdef _WIN32 if (rc)
len = OPEN_EXISTING;
env->me_mfd = CreateFileW(fname.mn_val, oflags,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, len,
mode | FILE_FLAG_WRITE_THROUGH, NULL);
#else
oflags &= ~O_CREAT;
env->me_mfd = open(fname.mn_val, oflags | MDB_DSYNC, mode);
#endif
if (env->me_mfd == INVALID_HANDLE_VALUE) {
rc = ErrCode();
goto leave; goto leave;
} }
}
DPRINTF(("opened dbenv %p", (void *) env)); DPRINTF(("opened dbenv %p", (void *) env));
if (excl > 0) { if (excl > 0) {
rc = mdb_env_share_locks(env, &excl); rc = mdb_env_share_locks(env, &excl);
@ -9403,43 +9461,15 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
HANDLE newfd = INVALID_HANDLE_VALUE; HANDLE newfd = INVALID_HANDLE_VALUE;
rc = mdb_fname_init(path, env->me_flags | MDB_NOLOCK, &fname); rc = mdb_fname_init(path, env->me_flags | MDB_NOLOCK, &fname);
if (rc) if (rc == MDB_SUCCESS) {
return rc; rc = mdb_fopen(env, &fname, MDB_O_COPY, 0666, &newfd);
mdb_fname_suffix_set(env, &fname, MDB_O_DATA); mdb_fname_destroy(fname);
/* 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 = CreateFileW(fname.mn_val, GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
#else
newfd = open(fname.mn_val, O_WRONLY|O_CREAT|O_EXCL, 0666);
#endif
if (newfd == INVALID_HANDLE_VALUE) {
rc = ErrCode();
goto leave;
}
if (env->me_psize >= env->me_os_psize) {
#ifdef F_NOCACHE /* __APPLE__ */
(void) fcntl(newfd, F_NOCACHE, 1);
#elif defined O_DIRECT
/* Set O_DIRECT if the file system supports it */
if ((rc = fcntl(newfd, F_GETFL)) != -1)
(void) fcntl(newfd, F_SETFL, rc | O_DIRECT);
#endif
} }
if (rc == MDB_SUCCESS) {
rc = mdb_env_copyfd2(env, newfd, flags); rc = mdb_env_copyfd2(env, newfd, flags);
leave:
mdb_fname_destroy(fname);
if (newfd != INVALID_HANDLE_VALUE)
if (close(newfd) < 0 && rc == MDB_SUCCESS) if (close(newfd) < 0 && rc == MDB_SUCCESS)
rc = ErrCode(); rc = ErrCode();
}
return rc; return rc;
} }

Loading…
Cancel
Save