#include "midl.h"
+/* Note: If O_DSYNC is undefined but exists in /usr/include,
+ * preferably set some compiler flag to get the definition.
+ * Otherwise compile with the less efficient -DMDB_DSYNC=O_SYNC.
+ */
+#ifndef MDB_DSYNC
+# define MDB_DSYNC O_DSYNC
+#endif
+
#ifndef DEBUG
#define DEBUG 1
#endif
#define IS_BRANCH(p) F_ISSET((p)->mp_flags, P_BRANCH)
#define IS_OVERFLOW(p) F_ISSET((p)->mp_flags, P_OVERFLOW)
-#define OVPAGES(size, psize) (PAGEHDRSZ + size + psize - 1) / psize;
+#define OVPAGES(size, psize) ((PAGEHDRSZ-1 + (size)) / (psize) + 1)
typedef struct MDB_db {
uint32_t md_pad;
struct MDB_xcursor *mc_xcursor;
};
-#define METADATA(p) ((void *)((char *)p + PAGEHDRSZ))
+#define METADATA(p) ((void *)((char *)(p) + PAGEHDRSZ))
typedef struct MDB_node {
#define mn_pgno mn_p.np_pgno
MDB_db *me_dbs[2];
MDB_oldpages *me_pghead;
pthread_key_t me_txkey; /* thread-key for readers */
+ MDB_dpage *me_dpages;
pgno_t me_free_pgs[MDB_IDL_UM_SIZE];
MIDL2 me_dirty_list[MDB_IDL_DB_SIZE];
};
return MDB_VERSION_STRING;
}
-static const char *errstr[] = {
+static char *const errstr[] = {
"MDB_KEYEXIST: Key/data pair already exists",
"MDB_NOTFOUND: No matching key/data pair found",
"MDB_PAGE_NOTFOUND: Requested page not found",
return ("Successful return: 0");
if (err >= MDB_KEYEXIST && err <= MDB_VERSION_MISMATCH)
- return (char *)errstr[err - MDB_KEYEXIST];
+ return errstr[err - MDB_KEYEXIST];
return strerror(err);
}
if (txn->mt_next_pgno + num >= txn->mt_env->me_maxpg)
return NULL;
}
- if ((dp = malloc(txn->mt_env->me_psize * num + sizeof(MDB_dhead))) == NULL)
- return NULL;
+ if (txn->mt_env->me_dpages && num == 1) {
+ dp = txn->mt_env->me_dpages;
+ txn->mt_env->me_dpages = (MDB_dpage *)dp->h.md_parent;
+ } else {
+ if ((dp = malloc(txn->mt_env->me_psize * num + sizeof(MDB_dhead))) == NULL)
+ return NULL;
+ }
dp->h.md_num = num;
dp->h.md_parent = parent;
dp->h.md_pi = parent_idx;
txn->mt_u.reader->mr_txnid = 0;
} else {
MDB_oldpages *mop;
+ MDB_dpage *dp;
unsigned int i;
- /* Discard all dirty pages. */
- for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++)
- free(txn->mt_u.dirty_list[i].mptr);
+ /* return all dirty pages to dpage list */
+ for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++) {
+ dp = txn->mt_u.dirty_list[i].mptr;
+ if (dp->h.md_num == 1) {
+ dp->h.md_parent = (MDB_page *)txn->mt_env->me_dpages;
+ txn->mt_env->me_dpages = dp;
+ } else {
+ /* large pages just get freed directly */
+ free(dp);
+ }
+ }
while ((mop = txn->mt_env->me_pghead)) {
txn->mt_env->me_pghead = mop->mo_next;
/* Drop the dirty pages.
*/
- for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++)
- free(txn->mt_u.dirty_list[i].mptr);
+ for (i=1; i<=txn->mt_u.dirty_list[0].mid; i++) {
+ dp = txn->mt_u.dirty_list[i].mptr;
+ if (dp->h.md_num == 1) {
+ dp->h.md_parent = (MDB_page *)txn->mt_env->me_dpages;
+ txn->mt_env->me_dpages = dp;
+ } else {
+ free(dp);
+ }
+ txn->mt_u.dirty_list[i].mid = 0;
+ }
if ((n = mdb_env_sync(env, 0)) != 0 ||
(n = mdb_env_write_meta(txn)) != MDB_SUCCESS) {
if ((rc = mdb_env_open2(env, flags)) == MDB_SUCCESS) {
/* synchronous fd for meta writes */
if (!(flags & (MDB_RDONLY|MDB_NOSYNC)))
- oflags |= O_DSYNC;
+ oflags |= MDB_DSYNC;
if ((env->me_mfd = open(dpath, oflags, mode)) == -1) {
rc = errno;
goto leave;
void
mdb_env_close(MDB_env *env)
{
+ MDB_dpage *dp;
+
if (env == NULL)
return;
+ while (env->me_dpages) {
+ dp = env->me_dpages;
+ env->me_dpages = (MDB_dpage *)dp->h.md_parent;
+ free(dp);
+ }
+
free(env->me_dbs[1]);
free(env->me_dbs[0]);
free(env->me_dbxs);