|
|
@ -1446,6 +1446,7 @@ struct MDB_txn { |
|
|
|
#define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */ |
|
|
|
#define MDB_TXN_DIRTY 0x04 /**< must write, even if dirty list is empty */ |
|
|
|
#define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */ |
|
|
|
#define MDB_TXN_SPILLS 0x08 /**< txn or a parent has spilled pages */ |
|
|
|
#define MDB_TXN_HAS_CHILD 0x10 /**< txn has an #MDB_txn.%mt_child */ |
|
|
|
#define MDB_TXN_HAS_CHILD 0x10 /**< txn has an #MDB_txn.%mt_child */ |
|
|
|
|
|
|
|
#define MDB_TXN_DIRTYNUM 0x20 /**< dirty list uses nump list */ |
|
|
|
/** most operations on the txn are currently illegal */ |
|
|
|
/** most operations on the txn are currently illegal */ |
|
|
|
#define MDB_TXN_BLOCKED (MDB_TXN_FINISHED|MDB_TXN_ERROR|MDB_TXN_HAS_CHILD) |
|
|
|
#define MDB_TXN_BLOCKED (MDB_TXN_FINISHED|MDB_TXN_ERROR|MDB_TXN_HAS_CHILD) |
|
|
|
/** @} */ |
|
|
|
/** @} */ |
|
|
@ -1620,6 +1621,7 @@ struct MDB_env { |
|
|
|
* Unused except for a dummy element when #MDB_WRITEMAP. |
|
|
|
* Unused except for a dummy element when #MDB_WRITEMAP. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
MDB_ID2L me_dirty_list; |
|
|
|
MDB_ID2L me_dirty_list; |
|
|
|
|
|
|
|
int *me_dirty_nump; |
|
|
|
/** 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 */ |
|
|
|
int me_maxfree_1pg; |
|
|
|
int me_maxfree_1pg; |
|
|
|
/** Max size of a node on a page */ |
|
|
|
/** Max size of a node on a page */ |
|
|
@ -1630,8 +1632,8 @@ struct MDB_env { |
|
|
|
int me_live_reader; /**< have liveness lock in reader table */ |
|
|
|
int me_live_reader; /**< have liveness lock in reader table */ |
|
|
|
#ifdef _WIN32 |
|
|
|
#ifdef _WIN32 |
|
|
|
int me_pidquery; /**< Used in OpenProcess */ |
|
|
|
int me_pidquery; /**< Used in OpenProcess */ |
|
|
|
OVERLAPPED *ov; /**< Used for for overlapping I/O requests */ |
|
|
|
OVERLAPPED *me_ov; /**< Used for overlapping I/O requests */ |
|
|
|
int ovs; /**< Count of OVERLAPPEDs */ |
|
|
|
int me_ovs; /**< Count of MDB_overlaps */ |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#ifdef MDB_USE_POSIX_MUTEX /* Posix mutexes reside in shared mem */ |
|
|
|
#ifdef MDB_USE_POSIX_MUTEX /* Posix mutexes reside in shared mem */ |
|
|
|
# define me_rmutex me_txns->mti_rmutex /**< Shared reader lock */ |
|
|
|
# define me_rmutex me_txns->mti_rmutex /**< Shared reader lock */ |
|
|
@ -2202,8 +2204,16 @@ mdb_dlist_free(MDB_txn *txn) |
|
|
|
MDB_ID2L dl = txn->mt_u.dirty_list; |
|
|
|
MDB_ID2L dl = txn->mt_u.dirty_list; |
|
|
|
unsigned i, n = dl[0].mid; |
|
|
|
unsigned i, n = dl[0].mid; |
|
|
|
|
|
|
|
|
|
|
|
for (i = 1; i <= n; i++) { |
|
|
|
if (txn->mt_flags & MDB_TXN_DIRTYNUM) { |
|
|
|
mdb_dpage_free(env, dl[i].mptr); |
|
|
|
int *dl_nump = env->me_dirty_nump; |
|
|
|
|
|
|
|
for (i = 1; i <= n; i++) { |
|
|
|
|
|
|
|
mdb_dpage_free_n(env, dl[i].mptr, dl_nump[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
txn->mt_flags ^= MDB_TXN_DIRTYNUM; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
for (i = 1; i <= n; i++) { |
|
|
|
|
|
|
|
mdb_dpage_free(env, dl[i].mptr); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
dl[0].mid = 0; |
|
|
|
dl[0].mid = 0; |
|
|
|
} |
|
|
|
} |
|
|
@ -3912,18 +3922,17 @@ mdb_page_flush(MDB_txn *txn, int keep) |
|
|
|
MDB_env *env = txn->mt_env; |
|
|
|
MDB_env *env = txn->mt_env; |
|
|
|
MDB_ID2L dl = txn->mt_u.dirty_list; |
|
|
|
MDB_ID2L dl = txn->mt_u.dirty_list; |
|
|
|
unsigned psize = env->me_psize, j; |
|
|
|
unsigned psize = env->me_psize, j; |
|
|
|
int i, pagecount = dl[0].mid, rc; |
|
|
|
int i, pagecount = dl[0].mid, rc, *dl_nump, nump = 1; |
|
|
|
size_t size = 0; |
|
|
|
size_t size = 0; |
|
|
|
MDB_OFF_T pos = 0; |
|
|
|
MDB_OFF_T pos = 0; |
|
|
|
pgno_t pgno = 0; |
|
|
|
pgno_t pgno = 0; |
|
|
|
MDB_page *dp = NULL; |
|
|
|
MDB_page *dp = NULL; |
|
|
|
#if MDB_RPAGE_CACHE |
|
|
|
#if MDB_RPAGE_CACHE |
|
|
|
int nump = 1; |
|
|
|
|
|
|
|
MDB_page *encp; |
|
|
|
MDB_page *encp; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#ifdef _WIN32 |
|
|
|
#ifdef _WIN32 |
|
|
|
OVERLAPPED ov; |
|
|
|
OVERLAPPED *ov, *this_ov; |
|
|
|
MDB_page *wdp; |
|
|
|
MDB_page *wdp; |
|
|
|
int async_i = 0; |
|
|
|
int async_i = 0; |
|
|
|
HANDLE fd = (env->me_flags & MDB_NOSYNC) ? env->me_fd : env->me_ovfd; |
|
|
|
HANDLE fd = (env->me_flags & MDB_NOSYNC) ? env->me_fd : env->me_ovfd; |
|
|
|
#else |
|
|
|
#else |
|
|
@ -3946,25 +3955,35 @@ mdb_page_flush(MDB_txn *txn, int keep) |
|
|
|
goto done; |
|
|
|
goto done; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* setup nump list, flag that it's in use */ |
|
|
|
|
|
|
|
dl_nump = env->me_dirty_nump; |
|
|
|
|
|
|
|
for (n=1; n<=pagecount; n++) { |
|
|
|
|
|
|
|
dp = dl[n].mptr; |
|
|
|
|
|
|
|
dl_nump[n] = IS_OVERFLOW(dp) ? dp->mp_pages : 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
n = 0; |
|
|
|
|
|
|
|
txn->mt_flags |= MDB_TXN_DIRTYNUM; |
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32 |
|
|
|
#ifdef _WIN32 |
|
|
|
if (pagecount - keep >= env->ovs) { |
|
|
|
if (pagecount - keep >= env->me_ovs) { |
|
|
|
/* ran out of room in ov array, and re-malloc, copy handles and free previous */ |
|
|
|
/* ran out of room in ov array, and re-malloc, copy handles and free previous */ |
|
|
|
int ovs = (pagecount - keep) * 1.5; /* provide extra padding to reduce number of re-allocations */ |
|
|
|
int ovs = (pagecount - keep) * 1.5; /* provide extra padding to reduce number of re-allocations */ |
|
|
|
int new_size = ovs * sizeof(OVERLAPPED); |
|
|
|
int new_size = ovs * sizeof(OVERLAPPED); |
|
|
|
ov = malloc(new_size); |
|
|
|
ov = malloc(new_size); |
|
|
|
if (ov == NULL) |
|
|
|
if (ov == NULL) |
|
|
|
return ENOMEM; |
|
|
|
return ENOMEM; |
|
|
|
int previous_size = env->ovs * sizeof(OVERLAPPED); |
|
|
|
int previous_size = env->me_ovs * sizeof(OVERLAPPED); |
|
|
|
memcpy(ov, env->ov, previous_size); /* Copy previous OVERLAPPED data to retain event handles */ |
|
|
|
memcpy(ov, env->me_ov, previous_size); /* Copy previous OVERLAPPED data to retain event handles */ |
|
|
|
/* And clear rest of memory */ |
|
|
|
/* And clear rest of memory */ |
|
|
|
memset(&ov[env->ovs], 0, new_size - previous_size); |
|
|
|
memset(&ov[env->me_ovs], 0, new_size - previous_size); |
|
|
|
if (env->ovs > 0) { |
|
|
|
if (env->me_ovs > 0) { |
|
|
|
free(env->ov); /* release previous allocation */ |
|
|
|
free(env->me_ov); /* release previous allocation */ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
env->ov = ov; |
|
|
|
env->me_ov = ov; |
|
|
|
env->ovs = ovs; |
|
|
|
env->me_ovs = ovs; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
ov = env->me_ov; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/* Write the pages */ |
|
|
|
/* Write the pages */ |
|
|
@ -3982,15 +4001,8 @@ mdb_page_flush(MDB_txn *txn, int keep) |
|
|
|
dp->mp_txnid = txn->mt_txnid; |
|
|
|
dp->mp_txnid = txn->mt_txnid; |
|
|
|
pos = pgno * psize; |
|
|
|
pos = pgno * psize; |
|
|
|
size = psize; |
|
|
|
size = psize; |
|
|
|
#if MDB_RPAGE_CACHE |
|
|
|
nump = dl_nump[i]; |
|
|
|
nump = 1; |
|
|
|
size *= nump; |
|
|
|
if (IS_OVERFLOW(dp)) { |
|
|
|
|
|
|
|
nump = dp->mp_pages; |
|
|
|
|
|
|
|
size *= dp->mp_pages; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#else |
|
|
|
|
|
|
|
if (IS_OVERFLOW(dp)) size *= dp->mp_pages; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
/* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ |
|
|
|
/* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ |
|
|
|
if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE |
|
|
|
if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE |
|
|
@ -4013,7 +4025,7 @@ retry_write: |
|
|
|
rc = 0; |
|
|
|
rc = 0; |
|
|
|
/* Write previous page(s) */ |
|
|
|
/* Write previous page(s) */ |
|
|
|
#ifdef _WIN32 |
|
|
|
#ifdef _WIN32 |
|
|
|
OVERLAPPED *this_ov = &ov[async_i]; |
|
|
|
this_ov = &ov[async_i]; |
|
|
|
/* Clear status, and keep hEvent, we reuse that */ |
|
|
|
/* Clear status, and keep hEvent, we reuse that */ |
|
|
|
this_ov->Internal = 0; |
|
|
|
this_ov->Internal = 0; |
|
|
|
this_ov->Offset = wpos & 0xffffffff; |
|
|
|
this_ov->Offset = wpos & 0xffffffff; |
|
|
@ -4033,6 +4045,7 @@ retry_write: |
|
|
|
DPRINTF(("WriteFile: %d", rc)); |
|
|
|
DPRINTF(("WriteFile: %d", rc)); |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
rc = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
async_i++; |
|
|
|
async_i++; |
|
|
|
#else /* _WIN32 */ |
|
|
|
#else /* _WIN32 */ |
|
|
@ -4067,15 +4080,6 @@ retry_seek: |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif /* _WIN32 */ |
|
|
|
#endif /* _WIN32 */ |
|
|
|
#if MDB_RPAGE_CACHE |
|
|
|
|
|
|
|
if (env->me_encfunc) { |
|
|
|
|
|
|
|
int j, num1; |
|
|
|
|
|
|
|
for (j=0; j<n; j++) { |
|
|
|
|
|
|
|
num1 = 1 + (iov[j].iov_len > psize); |
|
|
|
|
|
|
|
mdb_dpage_free_n(env, (MDB_page *)iov[j].iov_base, num1); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
if (rc) |
|
|
|
if (rc) |
|
|
|
return rc; |
|
|
|
return rc; |
|
|
|
n = 0; |
|
|
|
n = 0; |
|
|
@ -4096,7 +4100,9 @@ retry_seek: |
|
|
|
out.mv_size = size; |
|
|
|
out.mv_size = size; |
|
|
|
out.mv_data = encp; |
|
|
|
out.mv_data = encp; |
|
|
|
env->me_encfunc(&in, &out, env->me_enckey, 1); |
|
|
|
env->me_encfunc(&in, &out, env->me_enckey, 1); |
|
|
|
|
|
|
|
mdb_dpage_free_n(env, dp, nump); |
|
|
|
dp = encp; |
|
|
|
dp = encp; |
|
|
|
|
|
|
|
dl[i].mptr = dp; |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
#ifdef _WIN32 |
|
|
|
#ifdef _WIN32 |
|
|
@ -4143,9 +4149,6 @@ retry_seek: |
|
|
|
|
|
|
|
|
|
|
|
if (!(env->me_flags & MDB_WRITEMAP)) { |
|
|
|
if (!(env->me_flags & MDB_WRITEMAP)) { |
|
|
|
/* Don't free pages when using writemap (can only get here in NOSYNC mode in Windows)
|
|
|
|
/* Don't free pages when using writemap (can only get here in NOSYNC mode in Windows)
|
|
|
|
* MIPS has cache coherency issues, this is a no-op everywhere else |
|
|
|
|
|
|
|
* Note: for any size >= on-chip cache size, entire on-chip cache is |
|
|
|
|
|
|
|
* flushed. |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
for (i = keep; ++i <= pagecount; ) { |
|
|
|
for (i = keep; ++i <= pagecount; ) { |
|
|
|
dp = dl[i].mptr; |
|
|
|
dp = dl[i].mptr; |
|
|
@ -4155,9 +4158,10 @@ retry_seek: |
|
|
|
dl[j].mid = dp->mp_pgno; |
|
|
|
dl[j].mid = dp->mp_pgno; |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
mdb_dpage_free(env, dp); |
|
|
|
mdb_dpage_free_n(env, dp, dl_nump[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
txn->mt_flags ^= MDB_TXN_DIRTYNUM; |
|
|
|
|
|
|
|
|
|
|
|
done: |
|
|
|
done: |
|
|
|
i--; |
|
|
|
i--; |
|
|
@ -5205,7 +5209,7 @@ mdb_env_open2(MDB_env *env, int prev) |
|
|
|
if (!NtCreateSection) |
|
|
|
if (!NtCreateSection) |
|
|
|
return MDB_PROBLEM; |
|
|
|
return MDB_PROBLEM; |
|
|
|
} |
|
|
|
} |
|
|
|
env->ovs = 0; |
|
|
|
env->me_ovs = 0; |
|
|
|
#endif /* _WIN32 */ |
|
|
|
#endif /* _WIN32 */ |
|
|
|
|
|
|
|
|
|
|
|
#ifdef BROKEN_FDATASYNC |
|
|
|
#ifdef BROKEN_FDATASYNC |
|
|
@ -6010,6 +6014,8 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode |
|
|
|
if (!((env->me_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)) && |
|
|
|
if (!((env->me_free_pgs = mdb_midl_alloc(MDB_IDL_UM_MAX)) && |
|
|
|
(env->me_dirty_list = calloc(dl_size, sizeof(MDB_ID2))))) |
|
|
|
(env->me_dirty_list = calloc(dl_size, sizeof(MDB_ID2))))) |
|
|
|
rc = ENOMEM; |
|
|
|
rc = ENOMEM; |
|
|
|
|
|
|
|
if (env->me_dirty_list && !(env->me_dirty_nump = malloc(dl_size * sizeof(int)))) |
|
|
|
|
|
|
|
rc = ENOMEM; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
env->me_flags = flags; |
|
|
|
env->me_flags = flags; |
|
|
@ -6142,6 +6148,7 @@ mdb_env_close_active(MDB_env *env, int excl) |
|
|
|
free(env->me_dbflags); |
|
|
|
free(env->me_dbflags); |
|
|
|
free(env->me_path); |
|
|
|
free(env->me_path); |
|
|
|
free(env->me_dirty_list); |
|
|
|
free(env->me_dirty_list); |
|
|
|
|
|
|
|
free(env->me_dirty_nump); |
|
|
|
#if MDB_RPAGE_CACHE |
|
|
|
#if MDB_RPAGE_CACHE |
|
|
|
if (MDB_REMAPPING(env->me_flags)) { |
|
|
|
if (MDB_REMAPPING(env->me_flags)) { |
|
|
|
if (env->me_txn0 && env->me_txn0->mt_rpages) |
|
|
|
if (env->me_txn0 && env->me_txn0->mt_rpages) |
|
|
@ -6180,11 +6187,11 @@ mdb_env_close_active(MDB_env *env, int excl) |
|
|
|
if (env->me_mfd != INVALID_HANDLE_VALUE) |
|
|
|
if (env->me_mfd != INVALID_HANDLE_VALUE) |
|
|
|
(void) close(env->me_mfd); |
|
|
|
(void) close(env->me_mfd); |
|
|
|
#ifdef _WIN32 |
|
|
|
#ifdef _WIN32 |
|
|
|
if (env->ovs > 0) { |
|
|
|
if (env->me_ovs > 0) { |
|
|
|
for (i = 0; i < env->ovs; i++) { |
|
|
|
for (i = 0; i < env->me_ovs; i++) { |
|
|
|
CloseHandle(env->ov[i].hEvent); |
|
|
|
CloseHandle(env->me_ov[i].hEvent); |
|
|
|
} |
|
|
|
} |
|
|
|
free(env->ov); |
|
|
|
free(env->me_ov); |
|
|
|
} |
|
|
|
} |
|
|
|
if (env->me_ovfd != INVALID_HANDLE_VALUE) |
|
|
|
if (env->me_ovfd != INVALID_HANDLE_VALUE) |
|
|
|
(void) close(env->me_ovfd); |
|
|
|
(void) close(env->me_ovfd); |
|
|
|