]> git.sur5r.net Git - openldap/blobdiff - libraries/libmdb/mdb.c
Use O_DSYNC on metafd.
[openldap] / libraries / libmdb / mdb.c
index b0b572dfefb7fdac13ef2f9583a6ebf89cd90f09..26712a8455f428d7553791f03005e68b2f178f81 100644 (file)
@@ -83,44 +83,51 @@ typedef uint16_t     indx_t;
 #define DEFAULT_MAPSIZE        1048576
 
 /* Lock descriptor stuff */
-#define RXBODY \
-       ULONG           mr_txnid; \
-       pid_t           mr_pid; \
-       pthread_t       mr_tid
-typedef struct MDB_rxbody {
-       RXBODY;
-} MDB_rxbody;
-
 #ifndef CACHELINE
-# ifdef __APPLE__
-#  define CACHELINE    128     /* 64 is too small to contain a mutex */
-# else
-#  define CACHELINE    64      /* most CPUs. Itanium uses 128 */
-# endif
+#define CACHELINE      64      /* most CPUs. Itanium uses 128 */
 #endif
 
+typedef struct MDB_rxbody {
+       ULONG           mrb_txnid;
+       pid_t           mrb_pid;
+       pthread_t       mrb_tid;
+} MDB_rxbody;
+
 typedef struct MDB_reader {
-       RXBODY;
-       /* cache line alignment */
-       char pad[CACHELINE-sizeof(MDB_rxbody)];
+       union {
+               MDB_rxbody mrx;
+#define        mr_txnid        mru.mrx.mrb_txnid
+#define        mr_pid  mru.mrx.mrb_pid
+#define        mr_tid  mru.mrx.mrb_tid
+               /* cache line alignment */
+               char pad[(sizeof(MDB_rxbody)+CACHELINE-1) & ~(CACHELINE-1)];
+       } mru;
 } MDB_reader;
 
-#define        TXBODY \
-       uint32_t        mt_magic;       \
-       uint32_t        mt_version;     \
-       pthread_mutex_t mt_mutex;       \
-       ULONG           mt_txnid;       \
-       uint32_t        mt_numreaders
 typedef struct MDB_txbody {
-       TXBODY;
+       uint32_t        mtb_magic;
+       uint32_t        mtb_version;
+       pthread_mutex_t mtb_mutex;
+       ULONG           mtb_txnid;
+       uint32_t        mtb_numreaders;
 } MDB_txbody;
 
 typedef struct MDB_txninfo {
-       TXBODY;
-       char pad[CACHELINE-sizeof(MDB_txbody)];
-       pthread_mutex_t mt_wmutex;
-       char pad2[CACHELINE-sizeof(pthread_mutex_t)];
-       MDB_reader      mt_readers[1];
+       union {
+               MDB_txbody mtb;
+#define mti_magic      mt1.mtb.mtb_magic
+#define mti_version    mt1.mtb.mtb_version
+#define mti_mutex      mt1.mtb.mtb_mutex
+#define mti_txnid      mt1.mtb.mtb_txnid
+#define mti_numreaders mt1.mtb.mtb_numreaders
+               char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)];
+       } mt1;
+       union {
+               pthread_mutex_t mt2_wmutex;
+#define mti_wmutex     mt2.mt2_wmutex
+               char pad[(sizeof(pthread_mutex_t)+CACHELINE-1) & ~(CACHELINE-1)];
+       } mt2;
+       MDB_reader      mti_readers[1];
 } MDB_txninfo;
 
 /* Common header for all page types. Overflow pages
@@ -138,6 +145,7 @@ typedef struct MDB_page {           /* represents a page of storage */
 #define        P_OVERFLOW       0x04           /* overflow page */
 #define        P_META           0x08           /* meta page */
 #define        P_DIRTY          0x10           /* dirty page */
+#define        P_LEAF2          0x20           /* DB with small, fixed size keys and no data */
        uint32_t        mp_flags;
 #define mp_lower       mp_pb.pb.pb_lower
 #define mp_upper       mp_pb.pb.pb_upper
@@ -148,6 +156,10 @@ typedef struct MDB_page {          /* represents a page of storage */
                        indx_t          pb_upper;               /* upper bound of free space */
                } pb;
                uint32_t        pb_pages;       /* number of overflow pages */
+               struct {
+                       indx_t  pb_ksize;       /* on a LEAF2 page */
+                       indx_t  pb_numkeys;
+               } pb2;
        } mp_pb;
        indx_t          mp_ptrs[1];             /* dynamic size */
 } MDB_page;
@@ -245,7 +257,6 @@ struct MDB_cursor {
        struct MDB_xcursor      *mc_xcursor;
 };
 
-#define METAHASHLEN     offsetof(MDB_meta, mm_hash)
 #define METADATA(p)     ((void *)((char *)p + PAGEHDRSZ))
 
 typedef struct MDB_node {
@@ -285,8 +296,8 @@ struct MDB_txn {
        MDB_db          *mt_dbs;
        unsigned int    mt_numdbs;
 
-#define MDB_TXN_RDONLY          0x01           /* read-only transaction */
-#define MDB_TXN_ERROR           0x02           /* an error has occurred */
+#define MDB_TXN_RDONLY         0x01            /* read-only transaction */
+#define MDB_TXN_ERROR          0x02            /* an error has occurred */
 #define MDB_TXN_METOGGLE       0x04            /* used meta page 1 */
        unsigned int    mt_flags;
 };
@@ -302,7 +313,10 @@ typedef struct MDB_xcursor {
 struct MDB_env {
        int                     me_fd;
        int                     me_lfd;
-       uint32_t        me_flags;
+       int                     me_mfd;                 /* just for writing the meta pages */
+       uint16_t        me_flags;
+       uint16_t                me_db_toggle;
+       unsigned int    me_psize;
        unsigned int    me_maxreaders;
        unsigned int    me_numdbs;
        unsigned int    me_maxdbs;
@@ -314,8 +328,6 @@ struct MDB_env {
        MDB_txn         *me_txn;                /* current write transaction */
        size_t          me_mapsize;
        off_t           me_size;                /* current file size */
-       unsigned int    me_psize;
-       int                     me_db_toggle;
        MDB_dbx         *me_dbxs;               /* array */
        MDB_db          *me_dbs[2];
        MDB_oldpages *me_pghead;
@@ -334,7 +346,6 @@ struct MDB_env {
 #define NODEDSZ(node)   ((node)->mn_dsize)
 
 #define MDB_COMMIT_PAGES        64     /* max number of pages to write in one commit */
-#define MDB_MAXCACHE_DEF        1024   /* max number of pages to keep in cache  */
 
 static int  mdb_search_page_root(MDB_txn *txn,
                            MDB_dbi dbi, MDB_val *key,
@@ -524,11 +535,11 @@ mdb_alloc_page(MDB_txn *txn, MDB_page *parent, unsigned int parent_idx, int num)
        }
        if (txn->mt_env->me_pghead) {
                unsigned int i;
-               for (i=0; i<txn->mt_env->me_txns->mt_numreaders; i++) {
-                       ULONG mr = txn->mt_env->me_txns->mt_readers[i].mr_txnid;
+               for (i=0; i<txn->mt_env->me_txns->mti_numreaders; i++) {
+                       ULONG mr = txn->mt_env->me_txns->mti_readers[i].mr_txnid;
                        if (!mr) continue;
                        if (mr < oldest)
-                               oldest = txn->mt_env->me_txns->mt_readers[i].mr_txnid;
+                               oldest = txn->mt_env->me_txns->mti_readers[i].mr_txnid;
                }
                if (oldest > txn->mt_env->me_pghead->mo_txnid) {
                        MDB_oldpages *mop = txn->mt_env->me_pghead;
@@ -609,7 +620,7 @@ mdb_env_sync(MDB_env *env, int force)
 {
        int rc = 0;
        if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) {
-               if (fsync(env->me_fd))
+               if (fdatasync(env->me_fd))
                        rc = errno;
        }
        return rc;
@@ -636,32 +647,32 @@ mdb_txn_begin(MDB_env *env, int rdonly, MDB_txn **ret)
                }
                STAILQ_INIT(txn->mt_u.dirty_queue);
 
-               pthread_mutex_lock(&env->me_txns->mt_wmutex);
-               env->me_txns->mt_txnid++;
+               pthread_mutex_lock(&env->me_txns->mti_wmutex);
+               env->me_txns->mti_txnid++;
                txn->mt_free_pgs = env->me_free_pgs;
                txn->mt_free_pgs[0] = 0;
        }
 
-       txn->mt_txnid = env->me_txns->mt_txnid;
+       txn->mt_txnid = env->me_txns->mti_txnid;
        if (rdonly) {
                MDB_reader *r = pthread_getspecific(env->me_txkey);
                if (!r) {
                        unsigned int i;
-                       pthread_mutex_lock(&env->me_txns->mt_mutex);
-                       for (i=0; i<env->me_txns->mt_numreaders; i++)
-                               if (env->me_txns->mt_readers[i].mr_pid == 0)
+                       pthread_mutex_lock(&env->me_txns->mti_mutex);
+                       for (i=0; i<env->me_txns->mti_numreaders; i++)
+                               if (env->me_txns->mti_readers[i].mr_pid == 0)
                                        break;
                        if (i == env->me_maxreaders) {
                                pthread_mutex_unlock(&env->me_txns->mti_mutex);
                                return ENOSPC;
                        }
-                       env->me_txns->mt_readers[i].mr_pid = getpid();
-                       env->me_txns->mt_readers[i].mr_tid = pthread_self();
-                       r = &env->me_txns->mt_readers[i];
+                       env->me_txns->mti_readers[i].mr_pid = getpid();
+                       env->me_txns->mti_readers[i].mr_tid = pthread_self();
+                       r = &env->me_txns->mti_readers[i];
                        pthread_setspecific(env->me_txkey, r);
-                       if (i >= env->me_txns->mt_numreaders)
-                               env->me_txns->mt_numreaders = i+1;
-                       pthread_mutex_unlock(&env->me_txns->mt_mutex);
+                       if (i >= env->me_txns->mti_numreaders)
+                               env->me_txns->mti_numreaders = i+1;
+                       pthread_mutex_unlock(&env->me_txns->mti_mutex);
                }
                r->mr_txnid = txn->mt_txnid;
                txn->mt_u.reader = r;
@@ -733,10 +744,10 @@ mdb_txn_abort(MDB_txn *txn)
                }
 
                env->me_txn = NULL;
-               env->me_txns->mt_txnid--;
+               env->me_txns->mti_txnid--;
                for (i=2; i<env->me_numdbs; i++)
                        env->me_dbxs[i].md_dirty = 0;
-               pthread_mutex_unlock(&env->me_txns->mt_wmutex);
+               pthread_mutex_unlock(&env->me_txns->mti_wmutex);
        }
 
        free(txn);
@@ -909,8 +920,7 @@ mdb_txn_commit(MDB_txn *txn)
        }
 
        if ((n = mdb_env_sync(env, 0)) != 0 ||
-           (n = mdb_env_write_meta(txn)) != MDB_SUCCESS ||
-           (n = mdb_env_sync(env, 0)) != 0) {
+           (n = mdb_env_write_meta(txn)) != MDB_SUCCESS) {
                mdb_txn_abort(txn);
                return n;
        }
@@ -937,7 +947,7 @@ mdb_txn_commit(MDB_txn *txn)
                free(txn->mt_dbs);
        }
 
-       pthread_mutex_unlock(&env->me_txns->mt_wmutex);
+       pthread_mutex_unlock(&env->me_txns->mti_wmutex);
        free(txn->mt_u.dirty_queue);
        free(txn);
        txn = NULL;
@@ -1064,8 +1074,7 @@ mdb_env_write_meta(MDB_txn *txn)
                off += env->me_psize;
        off += PAGEHDRSZ;
 
-       lseek(env->me_fd, off, SEEK_SET);
-       rc = write(env->me_fd, ptr, len);
+       rc = pwrite(env->me_fd, ptr, len, off);
        if (rc != len) {
                DPRINTF("write failed, disk error?");
                return errno;
@@ -1106,6 +1115,7 @@ mdb_env_create(MDB_env **env)
        e->me_maxdbs = 2;
        e->me_fd = -1;
        e->me_lfd = -1;
+       e->me_mfd = -1;
        *env = e;
        return MDB_SUCCESS;
 }
@@ -1219,7 +1229,7 @@ mdb_env_share_locks(MDB_env *env)
 {
        struct flock lock_info;
 
-       env->me_txns->mt_txnid = env->me_meta->mm_txnid;
+       env->me_txns->mti_txnid = env->me_meta->mm_txnid;
 
        memset((void *)&lock_info, 0, sizeof(lock_info));
        lock_info.l_type = F_RDLCK;
@@ -1283,23 +1293,26 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
                pthread_mutexattr_t mattr;
 
                pthread_mutexattr_init(&mattr);
-               pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
-               pthread_mutex_init(&env->me_txns->mt_mutex, &mattr);
-               pthread_mutex_init(&env->me_txns->mt_wmutex, &mattr);
-               env->me_txns->mt_version = MDB_VERSION;
-               env->me_txns->mt_magic = MDB_MAGIC;
-               env->me_txns->mt_txnid = 0;
-               env->me_txns->mt_numreaders = 0;
+               rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
+               if (rc) {
+                       goto fail;
+               }
+               pthread_mutex_init(&env->me_txns->mti_mutex, &mattr);
+               pthread_mutex_init(&env->me_txns->mti_wmutex, &mattr);
+               env->me_txns->mti_version = MDB_VERSION;
+               env->me_txns->mti_magic = MDB_MAGIC;
+               env->me_txns->mti_txnid = 0;
+               env->me_txns->mti_numreaders = 0;
 
        } else {
-               if (env->me_txns->mt_magic != MDB_MAGIC) {
+               if (env->me_txns->mti_magic != MDB_MAGIC) {
                        DPRINTF("lock region has invalid magic");
                        rc = EINVAL;
                        goto fail;
                }
-               if (env->me_txns->mt_version != MDB_VERSION) {
+               if (env->me_txns->mti_version != MDB_VERSION) {
                        DPRINTF("lock region is version %u, expected version %u",
-                               env->me_txns->mt_version, MDB_VERSION);
+                               env->me_txns->mti_version, MDB_VERSION);
                        rc = MDB_VERSION_MISMATCH;
                        goto fail;
                }
@@ -1312,6 +1325,7 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl)
 
 fail:
        close(env->me_lfd);
+       env->me_lfd = -1;
        return rc;
 
 }
@@ -1341,13 +1355,20 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mode_t mode)
        else
                oflags = O_RDWR | O_CREAT;
 
-       if ((env->me_fd = open(dpath, oflags, mode)) == -1)
-               return errno;
+       if ((env->me_fd = open(dpath, oflags, mode)) == -1) {
+               rc = errno;
+               goto leave;
+       }
+
+       if ((rc = mdb_env_open2(env, flags)) == MDB_SUCCESS) {
+               /* synchronous fd for meta writes */
+               if (!(flags & (MDB_RDONLY|MDB_NOSYNC)))
+                       oflags |= O_DSYNC;
+               if ((env->me_mfd = open(dpath, oflags, mode)) == -1) {
+                       rc = errno;
+                       goto leave;
+               }
 
-       if ((rc = mdb_env_open2(env, flags)) != MDB_SUCCESS) {
-               close(env->me_fd);
-               env->me_fd = -1;
-       } else {
                env->me_path = strdup(path);
                DPRINTF("opened dbenv %p", (void *) env);
                pthread_key_create(&env->me_txkey, mdb_env_reader_dest);
@@ -1360,6 +1381,16 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mode_t mode)
        }
 
 leave:
+       if (rc) {
+               if (env->me_fd >= 0) {
+                       close(env->me_fd);
+                       env->me_fd = -1;
+               }
+               if (env->me_lfd >= 0) {
+                       close(env->me_lfd);
+                       env->me_lfd = -1;
+               }
+       }
        free(lpath);
        return rc;
 }
@@ -1380,6 +1411,7 @@ mdb_env_close(MDB_env *env)
        if (env->me_map) {
                munmap(env->me_map, env->me_mapsize);
        }
+       close(env->me_mfd);
        close(env->me_fd);
        if (env->me_txns) {
                pid_t pid = getpid();