Clean up MDB_env setup.

Malloc before I/O. Avoids possible malloc error after I/O.
Don't allocate dirty & free lists when MDB_RDONLY.
Factor out code.
vmware
Hallvard Furuseth 12 years ago
parent dbb9ded2f8
commit 65a6542765
  1. 98
      libraries/liblmdb/mdb.c

@ -963,8 +963,8 @@ struct MDB_env {
MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */ MDB_page *me_dpages; /**< list of malloc'd blocks for re-use */
/** IDL of pages that became unused in a write txn */ /** IDL of pages that became unused in a write txn */
MDB_IDL me_free_pgs; MDB_IDL me_free_pgs;
/** ID2L of pages that were written during a write txn */ /** ID2L of pages written during a write txn. Length MDB_IDL_UM_SIZE. */
MDB_ID2 me_dirty_list[MDB_IDL_UM_SIZE]; MDB_ID2L me_dirty_list;
/** Max number of freelist items that can fit in a single overflow page */ /** Max number of freelist items that can fit in a single overflow page */
unsigned int me_maxfree_1pg; unsigned int me_maxfree_1pg;
/** Max size of a node on a page */ /** Max size of a node on a page */
@ -2770,11 +2770,6 @@ mdb_env_create(MDB_env **env)
if (!e) if (!e)
return ENOMEM; return ENOMEM;
e->me_free_pgs = mdb_midl_alloc();
if (!e->me_free_pgs) {
free(e);
return ENOMEM;
}
e->me_maxreaders = DEFAULT_READERS; e->me_maxreaders = DEFAULT_READERS;
e->me_maxdbs = 2; e->me_maxdbs = 2;
e->me_fd = INVALID_HANDLE_VALUE; e->me_fd = INVALID_HANDLE_VALUE;
@ -3193,58 +3188,45 @@ mdb_hash_hex(MDB_val *val, char *hexbuf)
* @param[in] lpath The pathname of the file used for the lock region. * @param[in] lpath The pathname of the file used for the lock region.
* @param[in] mode The Unix permissions for the file, if we create it. * @param[in] mode The Unix permissions for the file, if we create it.
* @param[out] excl Resulting file lock type: -1 none, 0 shared, 1 exclusive * @param[out] excl Resulting file lock type: -1 none, 0 shared, 1 exclusive
* @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive
* @return 0 on success, non-zero on failure. * @return 0 on success, non-zero on failure.
*/ */
static int static int
mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl) mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
{ {
#ifdef _WIN32
# define MDB_ERRCODE_ROFS ERROR_WRITE_PROTECT
#else
# define MDB_ERRCODE_ROFS EROFS
#ifdef O_CLOEXEC /* Linux: Open file and set FD_CLOEXEC atomically */
# define MDB_CLOEXEC O_CLOEXEC
#else
int fdflags;
# define MDB_CLOEXEC 0
#endif
#endif
int rc; int rc;
off_t size, rsize; off_t size, rsize;
*excl = -1;
#ifdef _WIN32 #ifdef _WIN32
if ((env->me_lfd = CreateFile(lpath, GENERIC_READ|GENERIC_WRITE, env->me_lfd = CreateFile(lpath, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { FILE_ATTRIBUTE_NORMAL, NULL);
rc = ErrCode();
if (rc == ERROR_WRITE_PROTECT && (env->me_flags & MDB_RDONLY)) {
env->me_flags |= MDB_ROFS;
return MDB_SUCCESS;
}
goto fail_errno;
}
/* Try to get exclusive lock. If we succeed, then
* nobody is using the lock region and we should initialize it.
*/
if ((rc = mdb_env_excl_lock(env, excl))) goto fail;
size = GetFileSize(env->me_lfd, NULL);
#else #else
#if !(O_CLOEXEC) env->me_lfd = open(lpath, O_RDWR|O_CREAT|MDB_CLOEXEC, mode);
{ #endif
int fdflags; if (env->me_lfd == INVALID_HANDLE_VALUE) {
if ((env->me_lfd = open(lpath, O_RDWR|O_CREAT, mode)) == -1) {
rc = ErrCode(); rc = ErrCode();
if (rc == EROFS && (env->me_flags & MDB_RDONLY)) { if (rc == MDB_ERRCODE_ROFS && (env->me_flags & MDB_RDONLY)) {
env->me_flags |= MDB_ROFS; env->me_flags |= MDB_ROFS;
return MDB_SUCCESS; return MDB_SUCCESS;
} }
goto fail_errno; goto fail_errno;
} }
#if ! ((MDB_CLOEXEC) || defined(_WIN32))
/* Lose record locks when exec*() */ /* Lose record locks when exec*() */
if ((fdflags = fcntl(env->me_lfd, F_GETFD) | FD_CLOEXEC) >= 0) if ((fdflags = fcntl(env->me_lfd, F_GETFD) | FD_CLOEXEC) >= 0)
fcntl(env->me_lfd, F_SETFD, fdflags); fcntl(env->me_lfd, F_SETFD, fdflags);
}
#else /* O_CLOEXEC on Linux: Open file and set FD_CLOEXEC atomically */
if ((env->me_lfd = open(lpath, O_RDWR|O_CREAT|O_CLOEXEC, mode)) == -1) {
rc = ErrCode();
if (rc == EROFS && (env->me_flags & MDB_RDONLY)) {
env->me_flags |= MDB_ROFS;
return MDB_SUCCESS;
}
goto fail_errno;
}
#endif #endif
/* Try to get exclusive lock. If we succeed, then /* Try to get exclusive lock. If we succeed, then
@ -3252,6 +3234,9 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
*/ */
if ((rc = mdb_env_excl_lock(env, excl))) goto fail; if ((rc = mdb_env_excl_lock(env, excl))) goto fail;
#ifdef _WIN32
size = GetFileSize(env->me_lfd, NULL);
#else
size = lseek(env->me_lfd, 0, SEEK_END); size = lseek(env->me_lfd, 0, SEEK_END);
#endif #endif
rsize = (env->me_maxreaders-1) * sizeof(MDB_reader) + sizeof(MDB_txninfo); rsize = (env->me_maxreaders-1) * sizeof(MDB_reader) + sizeof(MDB_txninfo);
@ -3412,7 +3397,7 @@ fail:
int int
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; int oflags, rc, len, excl = -1;
char *lpath, *dpath; char *lpath, *dpath;
if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS))) if (env->me_fd!=INVALID_HANDLE_VALUE || (flags & ~(CHANGEABLE|CHANGELESS)))
@ -3437,11 +3422,27 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
sprintf(dpath, "%s" DATANAME, path); sprintf(dpath, "%s" DATANAME, path);
} }
rc = MDB_SUCCESS;
flags |= env->me_flags; flags |= env->me_flags;
/* silently ignore WRITEMAP if we're only getting read access */ if (flags & MDB_RDONLY) {
if (F_ISSET(flags, MDB_RDONLY|MDB_WRITEMAP)) /* silently ignore WRITEMAP when we're only getting read access */
flags ^= MDB_WRITEMAP; flags &= ~MDB_WRITEMAP;
} else {
if (!((env->me_free_pgs = mdb_midl_alloc()) &&
(env->me_dirty_list = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2)))))
rc = ENOMEM;
}
env->me_flags = flags |= MDB_ENV_ACTIVE; env->me_flags = flags |= MDB_ENV_ACTIVE;
if (rc)
goto leave;
env->me_path = strdup(path);
env->me_dbxs = calloc(env->me_maxdbs, sizeof(MDB_dbx));
env->me_dbflags = calloc(env->me_maxdbs, sizeof(uint16_t));
if (!(env->me_dbxs && env->me_path && env->me_dbflags)) {
rc = ENOMEM;
goto leave;
}
rc = mdb_env_setup_locks(env, lpath, mode, &excl); rc = mdb_env_setup_locks(env, lpath, mode, &excl);
if (rc) if (rc)
@ -3506,14 +3507,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode
#endif #endif
if (excl > 0) { if (excl > 0) {
rc = mdb_env_share_locks(env, &excl); rc = mdb_env_share_locks(env, &excl);
if (rc)
goto leave;
} }
env->me_dbxs = calloc(env->me_maxdbs, sizeof(MDB_dbx));
env->me_dbflags = calloc(env->me_maxdbs, sizeof(uint16_t));
env->me_path = strdup(path);
if (!env->me_dbxs || !env->me_dbflags || !env->me_path)
rc = ENOMEM;
} }
leave: leave:
@ -3536,6 +3530,9 @@ mdb_env_close0(MDB_env *env, int excl)
free(env->me_dbflags); free(env->me_dbflags);
free(env->me_dbxs); free(env->me_dbxs);
free(env->me_path); free(env->me_path);
free(env->me_dirty_list);
if (env->me_free_pgs)
mdb_midl_free(env->me_free_pgs);
if (env->me_numdbs) { if (env->me_numdbs) {
pthread_key_delete(env->me_txkey); pthread_key_delete(env->me_txkey);
@ -3753,7 +3750,6 @@ mdb_env_close(MDB_env *env)
} }
mdb_env_close0(env, 0); mdb_env_close0(env, 0);
mdb_midl_free(env->me_free_pgs);
free(env); free(env);
} }

Loading…
Cancel
Save