#define MDB_FATAL_ERROR 0x80000000U
/** Read-only Filesystem. Allow read access, no locking. */
#define MDB_ROFS 0x40000000U
+ /** Some fields are initialized. */
+#define MDB_ENV_ACTIVE 0x20000000U
uint32_t me_flags; /**< @ref mdb_env */
unsigned int me_psize; /**< size of a page, from #GET_PAGESIZE */
unsigned int me_maxreaders; /**< size of the reader table */
/** Further setup required for opening an MDB environment
*/
static int
-mdb_env_open2(MDB_env *env, unsigned int flags)
+mdb_env_open2(MDB_env *env)
{
+ unsigned int flags = env->me_flags;
int i, newenv = 0, prot;
MDB_meta meta;
MDB_page *p;
- env->me_flags |= flags;
-
memset(&meta, 0, sizeof(meta));
if ((i = mdb_env_read_header(env, &meta)) != 0) {
FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
rc = ErrCode();
- if (rc == ERROR_WRITE_PROTECT) {
+ if (rc == ERROR_WRITE_PROTECT && (env->me_flags & MDB_RDONLY)) {
env->me_flags |= MDB_ROFS;
return MDB_SUCCESS;
}
int fdflags;
if ((env->me_lfd = open(lpath, O_RDWR|O_CREAT, mode)) == -1) {
rc = ErrCode();
- if (rc == EROFS) {
+ if (rc == EROFS && (env->me_flags & MDB_RDONLY)) {
env->me_flags |= MDB_ROFS;
return MDB_SUCCESS;
}
#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) {
+ if (rc == EROFS && (env->me_flags & MDB_RDONLY)) {
env->me_flags |= MDB_ROFS;
return MDB_SUCCESS;
}
sprintf(dpath, "%s" DATANAME, path);
}
- env->me_flags = 0;
+ /* silently ignore WRITEMAP if we're only getting read access */
+ if (F_ISSET(flags, MDB_RDONLY|MDB_WRITEMAP))
+ flags ^= MDB_WRITEMAP;
+ env->me_flags = flags |= MDB_ENV_ACTIVE;
+
rc = mdb_env_setup_locks(env, lpath, mode, &excl);
if (rc)
goto leave;
- /* silently ignore WRITEMAP if we're only getting read access */
- if (F_ISSET(flags, MDB_RDONLY) && F_ISSET(flags, MDB_WRITEMAP))
- flags ^= MDB_WRITEMAP;
-
#ifdef _WIN32
if (F_ISSET(flags, MDB_RDONLY)) {
oflags = GENERIC_READ;
goto leave;
}
- if ((rc = mdb_env_open2(env, flags)) == MDB_SUCCESS) {
+ if ((rc = mdb_env_open2(env)) == MDB_SUCCESS) {
if (flags & (MDB_RDONLY|MDB_NOSYNC|MDB_NOMETASYNC|MDB_WRITEMAP)) {
env->me_mfd = env->me_fd;
} else {
{
int i;
- if (env->me_lfd == INVALID_HANDLE_VALUE) /* 1st field to get inited */
+ if (!(env->me_flags & MDB_ENV_ACTIVE))
return;
free(env->me_dbflags);
#endif
munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo));
}
- close(env->me_lfd);
+ if (env->me_lfd != INVALID_HANDLE_VALUE) {
+ close(env->me_lfd);
+ }
- env->me_lfd = INVALID_HANDLE_VALUE; /* Mark env as reset */
+ env->me_flags &= ~MDB_ENV_ACTIVE;
}
int
}
#endif
- /* Temporarily block writers until we snapshot the meta pages */
- LOCK_MUTEX_W(env);
-
+ /* 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) {
- UNLOCK_MUTEX_W(env);
+ if (rc)
goto leave;
+
+ if (!(env->me_flags & MDB_ROFS)) {
+ /* We must start the actual read txn after blocking writers */
+ mdb_txn_reset0(txn);
+
+ /* Temporarily block writers until we snapshot the meta pages */
+ LOCK_MUTEX_W(env);
+
+ rc = mdb_txn_renew0(txn);
+ if (rc) {
+ UNLOCK_MUTEX_W(env);
+ goto leave;
+ }
}
wsize = env->me_psize * 2;
rc = write(newfd, env->me_map, wsize);
rc = (rc == (int)wsize) ? MDB_SUCCESS : ErrCode();
#endif
- UNLOCK_MUTEX_W(env);
+ if (! (env->me_flags & MDB_ROFS))
+ UNLOCK_MUTEX_W(env);
if (rc)
goto leave;