diff options
Diffstat (limited to 'external/db_drivers/liblmdb64/mdb.c')
-rw-r--r-- | external/db_drivers/liblmdb64/mdb.c | 472 |
1 files changed, 155 insertions, 317 deletions
diff --git a/external/db_drivers/liblmdb64/mdb.c b/external/db_drivers/liblmdb64/mdb.c index c4dc26903..c788b8534 100644 --- a/external/db_drivers/liblmdb64/mdb.c +++ b/external/db_drivers/liblmdb64/mdb.c @@ -5,7 +5,7 @@ * BerkeleyDB API, but much simplified. */ /* - * Copyright 2011-2014 Howard Chu, Symas Corp. + * Copyright 2011-2015 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -110,7 +110,7 @@ extern int cacheflush(char *addr, int nbytes, int cache); #endif #if defined(__APPLE__) || defined (BSD) -# define MDB_USE_SYSV_SEM 1 +# define MDB_USE_POSIX_SEM 1 # define MDB_FDATASYNC fsync #elif defined(ANDROID) # define MDB_FDATASYNC fsync @@ -118,18 +118,11 @@ extern int cacheflush(char *addr, int nbytes, int cache); #ifndef _WIN32 #include <pthread.h> -#ifdef MDB_USE_SYSV_SEM -#include <sys/ipc.h> -#include <sys/sem.h> -#ifdef _SEM_SEMUN_UNDEFINED -union semun { - int val; - struct semid_ds *buf; - unsigned short *array; -}; -#endif /* _SEM_SEMUN_UNDEFINED */ -#endif /* MDB_USE_SYSV_SEM */ -#endif /* !_WIN32 */ +#ifdef MDB_USE_POSIX_SEM +# define MDB_USE_HASH 1 +#include <semaphore.h> +#endif +#endif #ifdef USE_VALGRIND #include <valgrind/memcheck.h> @@ -208,10 +201,6 @@ union semun { #define MDB_DEVEL 0 #endif -#if defined(_WIN32) || defined(MDB_USE_SYSV_SEM) || defined(EOWNERDEAD) -#define MDB_ROBUST_SUPPORTED 1 -#endif - /** Wrapper around __func__, which is a C99 feature */ #if __STDC_VERSION__ >= 199901L # define mdb_func_ __func__ @@ -222,16 +211,6 @@ union semun { # define mdb_func_ "<mdb_unknown>" #endif -/* Internal error codes, not exposed outside liblmdb */ -#define MDB_NO_ROOT (MDB_LAST_ERRCODE + 10) -#ifdef _WIN32 -#define MDB_OWNERDEAD ((int) WAIT_ABANDONED) -#elif defined MDB_USE_SYSV_SEM -#define MDB_OWNERDEAD (MDB_LAST_ERRCODE + 11) -#else -#define MDB_OWNERDEAD EOWNERDEAD -#endif - #ifdef _WIN32 #define MDB_USE_HASH 1 #define MDB_PIDLOCK 0 @@ -239,7 +218,6 @@ union semun { #define pthread_t HANDLE #define pthread_mutex_t HANDLE #define pthread_cond_t HANDLE -typedef HANDLE mdb_mutex_t; #define pthread_key_t DWORD #define pthread_self() GetCurrentThreadId() #define pthread_key_create(x,y) \ @@ -253,10 +231,10 @@ typedef HANDLE mdb_mutex_t; #define pthread_cond_wait(cond,mutex) do{SignalObjectAndWait(*mutex, *cond, INFINITE, FALSE); WaitForSingleObject(*mutex, INFINITE);}while(0) #define THREAD_CREATE(thr,start,arg) thr=CreateThread(NULL,0,start,arg,0,NULL) #define THREAD_FINISH(thr) WaitForSingleObject(thr, INFINITE) -#define MDB_MUTEX(env, rw) ((env)->me_##rw##mutex) -#define LOCK_MUTEX0(mutex) WaitForSingleObject(mutex, INFINITE) -#define UNLOCK_MUTEX(mutex) ReleaseMutex(mutex) -#define mdb_mutex_consistent(mutex) 0 +#define LOCK_MUTEX_R(env) pthread_mutex_lock(&(env)->me_rmutex) +#define UNLOCK_MUTEX_R(env) pthread_mutex_unlock(&(env)->me_rmutex) +#define LOCK_MUTEX_W(env) pthread_mutex_lock(&(env)->me_wmutex) +#define UNLOCK_MUTEX_W(env) pthread_mutex_unlock(&(env)->me_wmutex) #define getpid() GetCurrentProcessId() #define MDB_FDATASYNC(fd) (!FlushFileBuffers(fd)) #define MDB_MSYNC(addr,len,flags) (!FlushViewOfFile(addr,len)) @@ -279,59 +257,38 @@ typedef HANDLE mdb_mutex_t; /** For MDB_LOCK_FORMAT: True if readers take a pid lock in the lockfile */ #define MDB_PIDLOCK 1 -#ifdef MDB_USE_SYSV_SEM +#ifdef MDB_USE_POSIX_SEM -typedef struct mdb_mutex { - int semid; - int semnum; - int *locked; -} mdb_mutex_t; - -#define MDB_MUTEX(env, rw) (&(env)->me_##rw##mutex) -#define LOCK_MUTEX0(mutex) mdb_sem_wait(mutex) -#define UNLOCK_MUTEX(mutex) do { \ - struct sembuf sb = { 0, 1, SEM_UNDO }; \ - sb.sem_num = (mutex)->semnum; \ - *(mutex)->locked = 0; \ - semop((mutex)->semid, &sb, 1); \ -} while(0) +#define LOCK_MUTEX_R(env) mdb_sem_wait((env)->me_rmutex) +#define UNLOCK_MUTEX_R(env) sem_post((env)->me_rmutex) +#define LOCK_MUTEX_W(env) mdb_sem_wait((env)->me_wmutex) +#define UNLOCK_MUTEX_W(env) sem_post((env)->me_wmutex) static int -mdb_sem_wait(mdb_mutex_t *sem) +mdb_sem_wait(sem_t *sem) { - int rc, *locked = sem->locked; - struct sembuf sb = { 0, -1, SEM_UNDO }; - sb.sem_num = sem->semnum; - do { - if (!semop(sem->semid, &sb, 1)) { - rc = *locked ? MDB_OWNERDEAD : MDB_SUCCESS; - *locked = 1; - break; - } - } while ((rc = errno) == EINTR); - return rc; + int rc; + while ((rc = sem_wait(sem)) && (rc = errno) == EINTR) ; + return rc; } -#define mdb_mutex_consistent(mutex) 0 - #else - /** Pointer/HANDLE type of shared mutex/semaphore. - */ -typedef pthread_mutex_t mdb_mutex_t; - /** Mutex for the reader table (rw = r) or write transaction (rw = w). + /** Lock the reader mutex. */ -#define MDB_MUTEX(env, rw) (&(env)->me_txns->mti_##rw##mutex) - /** Lock the reader or writer mutex. - * Returns 0 or a code to give #mdb_mutex_failed(), as in #LOCK_MUTEX(). +#define LOCK_MUTEX_R(env) pthread_mutex_lock(&(env)->me_txns->mti_mutex) + /** Unlock the reader mutex. */ -#define LOCK_MUTEX0(mutex) pthread_mutex_lock(mutex) - /** Unlock the reader or writer mutex. +#define UNLOCK_MUTEX_R(env) pthread_mutex_unlock(&(env)->me_txns->mti_mutex) + + /** Lock the writer mutex. + * Only a single write transaction is allowed at a time. Other writers + * will block waiting for this mutex. */ -#define UNLOCK_MUTEX(mutex) pthread_mutex_unlock(mutex) - /** Mark mutex-protected data as repaired, after death of previous owner. +#define LOCK_MUTEX_W(env) pthread_mutex_lock(&(env)->me_txns->mti_wmutex) + /** Unlock the writer mutex. */ -#define mdb_mutex_consistent(mutex) pthread_mutex_consistent(mutex) -#endif /* MDB_USE_SYSV_SEM */ +#define UNLOCK_MUTEX_W(env) pthread_mutex_unlock(&(env)->me_txns->mti_wmutex) +#endif /* MDB_USE_POSIX_SEM */ /** Get the error code for the last failed system function. */ @@ -356,35 +313,14 @@ typedef pthread_mutex_t mdb_mutex_t; #define GET_PAGESIZE(x) ((x) = sysconf(_SC_PAGE_SIZE)) #endif -#if defined(_WIN32) +#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) #define MNAME_LEN 32 -#elif defined(MDB_USE_SYSV_SEM) -#define MNAME_LEN (sizeof(int)) #else #define MNAME_LEN (sizeof(pthread_mutex_t)) #endif -#ifdef MDB_USE_SYSV_SEM -#define SYSV_SEM_FLAG 1 /**< SysV sems in lockfile format */ -#else -#define SYSV_SEM_FLAG 0 -#endif - /** @} */ -#ifdef MDB_ROBUST_SUPPORTED - /** Lock mutex, handle any error, set rc = result. - * Return 0 on success, nonzero (not rc) on error. - */ -#define LOCK_MUTEX(rc, env, mutex) \ - (((rc) = LOCK_MUTEX0(mutex)) && \ - ((rc) = mdb_mutex_failed(env, mutex, rc))) -static int mdb_mutex_failed(MDB_env *env, mdb_mutex_t *mutex, int rc); -#else -#define LOCK_MUTEX(rc, env, mutex) ((rc) = LOCK_MUTEX0(mutex)) -#define mdb_mutex_failed(env, mutex, rc) (rc) -#endif - #ifndef _WIN32 /** A flag for opening a file and requesting synchronous data writes. * This is only used when writing a meta page. It's not strictly needed; @@ -508,7 +444,7 @@ static txnid_t mdb_debug_start; /** The version number for a database's datafile format. */ #define MDB_DATA_VERSION ((MDB_DEVEL) ? 999 : 1) /** The version number for a database's lockfile format. */ -#define MDB_LOCK_VERSION ((MDB_DEVEL) ? 999 : 1) +#define MDB_LOCK_VERSION 1 /** @brief The max size of a key we can write, or 0 for dynamic max. * @@ -692,16 +628,13 @@ typedef struct MDB_txbody { uint32_t mtb_magic; /** Format of this lock file. Must be set to #MDB_LOCK_FORMAT. */ uint32_t mtb_format; -#if defined(_WIN32) +#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) char mtb_rmname[MNAME_LEN]; -#elif defined(MDB_USE_SYSV_SEM) - int mtb_semid; - int mtb_rlocked; #else /** Mutex protecting access to this table. - * This is the #MDB_MUTEX(env,r) reader table lock. + * This is the reader lock that #LOCK_MUTEX_R acquires. */ - pthread_mutex_t mtb_rmutex; + pthread_mutex_t mtb_mutex; #endif /** The ID of the last transaction committed to the database. * This is recorded here only for convenience; the value can always @@ -721,23 +654,16 @@ typedef struct MDB_txninfo { MDB_txbody mtb; #define mti_magic mt1.mtb.mtb_magic #define mti_format mt1.mtb.mtb_format -#define mti_rmutex mt1.mtb.mtb_rmutex +#define mti_mutex mt1.mtb.mtb_mutex #define mti_rmname mt1.mtb.mtb_rmname #define mti_txnid mt1.mtb.mtb_txnid #define mti_numreaders mt1.mtb.mtb_numreaders -#ifdef MDB_USE_SYSV_SEM -#define mti_semid mt1.mtb.mtb_semid -#define mti_rlocked mt1.mtb.mtb_rlocked -#endif char pad[(sizeof(MDB_txbody)+CACHELINE-1) & ~(CACHELINE-1)]; } mt1; union { -#if defined(_WIN32) +#if defined(_WIN32) || defined(MDB_USE_POSIX_SEM) char mt2_wmname[MNAME_LEN]; #define mti_wmname mt2.mt2_wmname -#elif defined MDB_USE_SYSV_SEM - int mt2_wlocked; -#define mti_wlocked mt2.mt2_wlocked #else pthread_mutex_t mt2_wmutex; #define mti_wmutex mt2.mt2_wmutex @@ -752,7 +678,6 @@ typedef struct MDB_txninfo { ((uint32_t) \ ((MDB_LOCK_VERSION) \ /* Flags which describe functionality */ \ - + (SYSV_SEM_FLAG << 18) \ + (((MDB_PIDLOCK) != 0) << 16))) /** @} */ @@ -1222,11 +1147,11 @@ struct MDB_env { int me_live_reader; /**< have liveness lock in reader table */ #ifdef _WIN32 int me_pidquery; /**< Used in OpenProcess */ -#endif -#if defined(_WIN32) || defined(MDB_USE_SYSV_SEM) - /* Windows mutexes/SysV semaphores do not reside in shared mem */ - mdb_mutex_t me_rmutex; - mdb_mutex_t me_wmutex; + HANDLE me_rmutex; /* Windows mutexes don't reside in shared mem */ + HANDLE me_wmutex; +#elif defined(MDB_USE_POSIX_SEM) + sem_t *me_rmutex; /* Shared mutexes are not supported */ + sem_t *me_wmutex; #endif void *me_userctx; /**< User-settable context */ MDB_assert_func *me_assert_func; /**< Callback for assertion failures */ @@ -1278,7 +1203,7 @@ static int mdb_page_split(MDB_cursor *mc, MDB_val *newkey, MDB_val *newdata, static int mdb_env_read_header(MDB_env *env, MDB_meta *meta); static int mdb_env_pick_meta(const MDB_env *env); static int mdb_env_write_meta(MDB_txn *txn); -#if !(defined(_WIN32) || defined(MDB_USE_SYSV_SEM)) /* Drop unused excl arg */ +#if !(defined(_WIN32) || defined(MDB_USE_POSIX_SEM)) /* Drop unused excl arg */ # define mdb_env_close0(env, excl) mdb_env_close1(env) #endif static void mdb_env_close0(MDB_env *env, int excl); @@ -1315,7 +1240,6 @@ static void mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node); static int mdb_drop0(MDB_cursor *mc, int subs); static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi); -static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead); /** @cond */ static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; @@ -1343,7 +1267,7 @@ static char *const mdb_errstr[] = { "MDB_NOTFOUND: No matching key/data pair found", "MDB_PAGE_NOTFOUND: Requested page not found", "MDB_CORRUPTED: Located page was wrong type", - "MDB_PANIC: Update of meta page failed or environment had fatal error", + "MDB_PANIC: Update of meta page failed", "MDB_VERSION_MISMATCH: Database environment version mismatch", "MDB_INVALID: File is not an LMDB file", "MDB_MAP_FULL: Environment mapsize limit reached", @@ -2583,7 +2507,6 @@ mdb_txn_renew0(MDB_txn *txn) } else { MDB_PID_T pid = env->me_pid; MDB_THR_T tid = pthread_self(); - mdb_mutex_t *rmutex = MDB_MUTEX(env, r); if (!env->me_live_reader) { rc = mdb_reader_pid(env, Pidset, pid); @@ -2592,26 +2515,24 @@ mdb_txn_renew0(MDB_txn *txn) env->me_live_reader = 1; } - if (LOCK_MUTEX(rc, env, rmutex)) - return rc; + LOCK_MUTEX_R(env); nr = ti->mti_numreaders; for (i=0; i<nr; i++) if (ti->mti_readers[i].mr_pid == 0) break; if (i == env->me_maxreaders) { - UNLOCK_MUTEX(rmutex); + UNLOCK_MUTEX_R(env); return MDB_READERS_FULL; } - r = &ti->mti_readers[i]; - r->mr_txnid = (txnid_t)-1; - r->mr_tid = tid; - r->mr_pid = pid; /* should be written last, see ITS#7971. */ + ti->mti_readers[i].mr_pid = pid; + ti->mti_readers[i].mr_tid = tid; if (i == nr) ti->mti_numreaders = ++nr; /* Save numreaders for un-mutexed mdb_env_close() */ env->me_numreaders = nr; - UNLOCK_MUTEX(rmutex); + UNLOCK_MUTEX_R(env); + r = &ti->mti_readers[i]; new_notls = (env->me_flags & MDB_NOTLS); if (!new_notls && (rc=pthread_setspecific(env->me_txkey, r))) { r->mr_pid = 0; @@ -2627,8 +2548,8 @@ mdb_txn_renew0(MDB_txn *txn) } } else { if (ti) { - if (LOCK_MUTEX(rc, env, MDB_MUTEX(env, w))) - return rc; + LOCK_MUTEX_W(env); + txn->mt_txnid = ti->mti_txnid; meta = env->me_metas[txn->mt_txnid & 1]; } else { @@ -2822,13 +2743,6 @@ mdb_txn_env(MDB_txn *txn) return txn->mt_env; } -size_t -mdb_txn_id(MDB_txn *txn) -{ - if(!txn) return 0; - return txn->mt_txnid; -} - /** Export or close DBI handles opened in this txn. */ static void mdb_dbis_update(MDB_txn *txn, int keep) @@ -2901,7 +2815,7 @@ mdb_txn_reset0(MDB_txn *txn, const char *act) env->me_txn = NULL; /* The writer mutex was locked in mdb_txn_begin. */ if (env->me_txns) - UNLOCK_MUTEX(MDB_MUTEX(env, w)); + UNLOCK_MUTEX_W(env); } else { txn->mt_parent->mt_child = NULL; env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate; @@ -3494,7 +3408,7 @@ done: mdb_dbis_update(txn, 1); if (env->me_txns) - UNLOCK_MUTEX(MDB_MUTEX(env, w)); + UNLOCK_MUTEX_W(env); if (txn != env->me_txn0) free(txn); @@ -3569,7 +3483,6 @@ mdb_env_read_header(MDB_env *env, MDB_meta *meta) return 0; } -/** Fill in most of the zeroed #MDB_meta for an empty database environment */ static void ESECT mdb_env_init_meta0(MDB_env *env, MDB_meta *meta) { @@ -3586,7 +3499,7 @@ mdb_env_init_meta0(MDB_env *env, MDB_meta *meta) /** Write the environment parameters of a freshly created DB environment. * @param[in] env the environment handle - * @param[in] meta the #MDB_meta to write + * @param[out] meta address of where to store the meta information * @return 0 on success, non-zero on failure. */ static int ESECT @@ -3613,6 +3526,8 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta) psize = env->me_psize; + mdb_env_init_meta0(env, meta); + p = calloc(2, psize); p->mp_pgno = 0; p->mp_flags = P_META; @@ -3670,10 +3585,6 @@ mdb_env_write_meta(MDB_txn *txn) mp->mm_dbs[0] = txn->mt_dbs[0]; mp->mm_dbs[1] = txn->mt_dbs[1]; mp->mm_last_pg = txn->mt_next_pgno - 1; -#if !(defined(_MSC_VER) || defined(__i386__) || defined(__x86_64__)) - /* LY: issue a memory barrier, if not x86. ITS#7969 */ - __sync_synchronize(); -#endif mp->mm_txnid = txn->mt_txnid; if (!(env->me_flags & (MDB_NOMETASYNC|MDB_NOSYNC))) { unsigned meta_size = env->me_psize; @@ -3783,9 +3694,9 @@ mdb_env_create(MDB_env **env) e->me_fd = INVALID_HANDLE_VALUE; e->me_lfd = INVALID_HANDLE_VALUE; e->me_mfd = INVALID_HANDLE_VALUE; -#ifdef MDB_USE_SYSV_SEM - e->me_rmutex.semid = -1; - e->me_wmutex.semid = -1; +#ifdef MDB_USE_POSIX_SEM + e->me_rmutex = SEM_FAILED; + e->me_wmutex = SEM_FAILED; #endif e->me_pid = getpid(); GET_PAGESIZE(e->me_os_psize); @@ -3886,16 +3797,16 @@ mdb_env_set_mapsize(MDB_env *env, size_t size) */ if (env->me_map) { int rc; - MDB_meta *meta; void *old; if (env->me_txn) return EINVAL; - meta = env->me_metas[mdb_env_pick_meta(env)]; if (!size) - size = meta->mm_mapsize; - { - /* Silently round up to minimum if the size is too small */ - size_t minsize = (meta->mm_last_pg + 1) * env->me_psize; + size = env->me_metas[mdb_env_pick_meta(env)]->mm_mapsize; + else if (size < env->me_mapsize) { + /* If the configured size is smaller, make sure it's + * still big enough. Silently round up to minimum if not. + */ + size_t minsize = (env->me_metas[mdb_env_pick_meta(env)]->mm_last_pg + 1) * env->me_psize; if (size < minsize) size = minsize; } @@ -3982,7 +3893,6 @@ mdb_env_open2(MDB_env *env) else env->me_pidquery = PROCESS_QUERY_INFORMATION; #endif /* _WIN32 */ - #ifdef BROKEN_FDATASYNC /* ext3/ext4 fdatasync is broken on some older Linux kernels. * https://lkml.org/lkml/2012/9/3/83 @@ -4031,6 +3941,8 @@ mdb_env_open2(MDB_env *env) } #endif + memset(&meta, 0, sizeof(meta)); + if ((i = mdb_env_read_header(env, &meta)) != 0) { if (i != ENOENT) return i; @@ -4039,40 +3951,24 @@ mdb_env_open2(MDB_env *env) env->me_psize = env->me_os_psize; if (env->me_psize > MAX_PAGESIZE) env->me_psize = MAX_PAGESIZE; - memset(&meta, 0, sizeof(meta)); - mdb_env_init_meta0(env, &meta); - meta.mm_mapsize = DEFAULT_MAPSIZE; } else { env->me_psize = meta.mm_psize; } /* Was a mapsize configured? */ if (!env->me_mapsize) { - env->me_mapsize = meta.mm_mapsize; - } - { - /* Make sure mapsize >= committed data size. Even when using - * mm_mapsize, which could be broken in old files (ITS#7789). + /* If this is a new environment, take the default, + * else use the size recorded in the existing env. + */ + env->me_mapsize = newenv ? DEFAULT_MAPSIZE : meta.mm_mapsize; + } else if (env->me_mapsize < meta.mm_mapsize) { + /* If the configured size is smaller, make sure it's + * still big enough. Silently round up to minimum if not. */ size_t minsize = (meta.mm_last_pg + 1) * meta.mm_psize; if (env->me_mapsize < minsize) env->me_mapsize = minsize; } - meta.mm_mapsize = env->me_mapsize; - - if (newenv && !(flags & MDB_FIXEDMAP)) { - /* mdb_env_map() may grow the datafile. Write the metapages - * first, so the file will be valid if initialization fails. - * Except with FIXEDMAP, since we do not yet know mm_address. - * We could fill in mm_address later, but then a different - * program might end up doing that - one with a memory layout - * and map address which does not suit the main program. - */ - rc = mdb_env_init_meta(env, &meta); - if (rc) - return rc; - newenv = 0; - } rc = mdb_env_map(env, (flags & MDB_FIXEDMAP) ? meta.mm_address : NULL); if (rc) @@ -4256,8 +4152,8 @@ mdb_env_excl_lock(MDB_env *env, int *excl) if (!rc) { *excl = 1; } else -# ifdef MDB_USE_SYSV_SEM - if (*excl < 0) /* always true when !MDB_USE_SYSV_SEM */ +# ifdef MDB_USE_POSIX_SEM + if (*excl < 0) /* always true when !MDB_USE_POSIX_SEM */ # endif { lock_info.l_type = F_RDLCK; @@ -4383,10 +4279,6 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl) # define MDB_CLOEXEC 0 #endif #endif -#ifdef MDB_USE_SYSV_SEM - int semid; - union semun semu; -#endif int rc; off_t size, rsize; @@ -4499,28 +4391,50 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl) if (!env->me_rmutex) goto fail_errno; env->me_wmutex = CreateMutex(&mdb_all_sa, FALSE, env->me_txns->mti_wmname); if (!env->me_wmutex) goto fail_errno; -#elif defined(MDB_USE_SYSV_SEM) - unsigned short vals[2] = {1, 1}; - semid = semget(IPC_PRIVATE, 2, mode); - if (semid < 0) - goto fail_errno; - semu.array = vals; - if (semctl(semid, 0, SETALL, semu) < 0) - goto fail_errno; - env->me_txns->mti_semid = semid; -#else /* MDB_USE_SYSV_SEM */ +#elif defined(MDB_USE_POSIX_SEM) + struct stat stbuf; + struct { + dev_t dev; + ino_t ino; + } idbuf; + MDB_val val; + char encbuf[11]; + +#if defined(__NetBSD__) +#define MDB_SHORT_SEMNAMES 1 /* limited to 14 chars */ +#endif + if (fstat(env->me_lfd, &stbuf)) goto fail_errno; + idbuf.dev = stbuf.st_dev; + idbuf.ino = stbuf.st_ino; + val.mv_data = &idbuf; + val.mv_size = sizeof(idbuf); + mdb_hash_enc(&val, encbuf); +#ifdef MDB_SHORT_SEMNAMES + encbuf[9] = '\0'; /* drop name from 15 chars to 14 chars */ +#endif + sprintf(env->me_txns->mti_rmname, "/MDBr%s", encbuf); + sprintf(env->me_txns->mti_wmname, "/MDBw%s", encbuf); + /* Clean up after a previous run, if needed: Try to + * remove both semaphores before doing anything else. + */ + sem_unlink(env->me_txns->mti_rmname); + sem_unlink(env->me_txns->mti_wmname); + env->me_rmutex = sem_open(env->me_txns->mti_rmname, + O_CREAT|O_EXCL, mode, 1); + if (env->me_rmutex == SEM_FAILED) goto fail_errno; + env->me_wmutex = sem_open(env->me_txns->mti_wmname, + O_CREAT|O_EXCL, mode, 1); + if (env->me_wmutex == SEM_FAILED) goto fail_errno; +#else /* MDB_USE_POSIX_SEM */ pthread_mutexattr_t mattr; if ((rc = pthread_mutexattr_init(&mattr)) || (rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)) -#ifdef MDB_ROBUST_SUPPORTED - || (rc = pthread_mutexattr_setrobust(&mattr, PTHREAD_MUTEX_ROBUST)) -#endif - || (rc = pthread_mutex_init(&env->me_txns->mti_rmutex, &mattr)) + || (rc = pthread_mutex_init(&env->me_txns->mti_mutex, &mattr)) || (rc = pthread_mutex_init(&env->me_txns->mti_wmutex, &mattr))) goto fail; pthread_mutexattr_destroy(&mattr); -#endif /* _WIN32 || MDB_USE_SYSV_SEM */ +#endif /* _WIN32 || MDB_USE_POSIX_SEM */ env->me_txns->mti_magic = MDB_MAGIC; env->me_txns->mti_format = MDB_LOCK_FORMAT; @@ -4528,9 +4442,6 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl) env->me_txns->mti_numreaders = 0; } else { -#ifdef MDB_USE_SYSV_SEM - struct semid_ds buf; -#endif if (env->me_txns->mti_magic != MDB_MAGIC) { DPUTS("lock region has invalid magic"); rc = MDB_INVALID; @@ -4551,26 +4462,13 @@ mdb_env_setup_locks(MDB_env *env, char *lpath, int mode, int *excl) if (!env->me_rmutex) goto fail_errno; env->me_wmutex = OpenMutex(SYNCHRONIZE, FALSE, env->me_txns->mti_wmname); if (!env->me_wmutex) goto fail_errno; -#elif defined(MDB_USE_SYSV_SEM) - semid = env->me_txns->mti_semid; - semu.buf = &buf; - /* check for read access */ - if (semctl(semid, 0, IPC_STAT, semu) < 0) - goto fail_errno; - /* check for write access */ - if (semctl(semid, 0, IPC_SET, semu) < 0) - goto fail_errno; +#elif defined(MDB_USE_POSIX_SEM) + env->me_rmutex = sem_open(env->me_txns->mti_rmname, 0); + if (env->me_rmutex == SEM_FAILED) goto fail_errno; + env->me_wmutex = sem_open(env->me_txns->mti_wmname, 0); + if (env->me_wmutex == SEM_FAILED) goto fail_errno; #endif } -#ifdef MDB_USE_SYSV_SEM - env->me_rmutex.semid = semid; - env->me_wmutex.semid = semid; - env->me_rmutex.semnum = 0; - env->me_wmutex.semnum = 1; - env->me_rmutex.locked = &env->me_txns->mti_rlocked; - env->me_wmutex.locked = &env->me_txns->mti_wlocked; -#endif - return MDB_SUCCESS; fail_errno: @@ -4590,8 +4488,8 @@ fail: * environment and re-opening it with the new flags. */ #define CHANGEABLE (MDB_NOSYNC|MDB_NOMETASYNC|MDB_MAPASYNC|MDB_NOMEMINIT) -#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY| \ - MDB_WRITEMAP|MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD) +#define CHANGELESS (MDB_FIXEDMAP|MDB_NOSUBDIR|MDB_RDONLY|MDB_WRITEMAP| \ + MDB_NOTLS|MDB_NOLOCK|MDB_NORDAHEAD) #if VALID_FLAGS & PERSISTENT_FLAGS & (CHANGEABLE|CHANGELESS) # error "Persistent DB flags & env flags overlap, but both go in mm_flags" @@ -4802,15 +4700,20 @@ mdb_env_close0(MDB_env *env, int excl) /* Windows automatically destroys the mutexes when * the last handle closes. */ -#elif defined(MDB_USE_SYSV_SEM) - if (env->me_rmutex.semid != -1) { +#elif defined(MDB_USE_POSIX_SEM) + if (env->me_rmutex != SEM_FAILED) { + sem_close(env->me_rmutex); + if (env->me_wmutex != SEM_FAILED) + sem_close(env->me_wmutex); /* If we have the filelock: If we are the * only remaining user, clean up semaphores. */ if (excl == 0) mdb_env_excl_lock(env, &excl); - if (excl > 0) - semctl(env->me_rmutex.semid, 0, IPC_RMID); + if (excl > 0) { + sem_unlink(env->me_txns->mti_rmname); + sem_unlink(env->me_txns->mti_wmname); + } } #endif munmap((void *)env->me_txns, (env->me_maxreaders-1)*sizeof(MDB_reader)+sizeof(MDB_txninfo)); @@ -4830,6 +4733,7 @@ mdb_env_close0(MDB_env *env, int excl) env->me_flags &= ~(MDB_ENV_ACTIVE|MDB_ENV_TXKEY); } + void ESECT mdb_env_close(MDB_env *env) { @@ -6164,6 +6068,7 @@ int mdb_cursor_put(MDB_cursor *mc, MDB_val *key, MDB_val *data, unsigned int flags) { + enum { MDB_NO_ROOT = MDB_LAST_ERRCODE+10 }; /* internal code */ MDB_env *env; MDB_node *leaf = NULL; MDB_page *fp, *mp; @@ -8822,7 +8727,6 @@ static int ESECT mdb_env_copyfd0(MDB_env *env, HANDLE fd) { MDB_txn *txn = NULL; - mdb_mutex_t *wmutex = NULL; int rc; size_t wsize; char *ptr; @@ -8847,13 +8751,11 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd) mdb_txn_reset0(txn, "reset-stage1"); /* Temporarily block writers until we snapshot the meta pages */ - wmutex = MDB_MUTEX(env, w); - if (LOCK_MUTEX(rc, env, wmutex)) - goto leave; + LOCK_MUTEX_W(env); rc = mdb_txn_renew0(txn); if (rc) { - UNLOCK_MUTEX(wmutex); + UNLOCK_MUTEX_W(env); goto leave; } } @@ -8877,8 +8779,8 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd) break; } } - if (wmutex) - UNLOCK_MUTEX(wmutex); + if (env->me_txns) + UNLOCK_MUTEX_W(env); if (rc) goto leave; @@ -9001,7 +8903,7 @@ mdb_env_copy(MDB_env *env, const char *path) int ESECT mdb_env_set_flags(MDB_env *env, unsigned int flag, int onoff) { - if (flag & (env->me_map ? ~CHANGEABLE : ~(CHANGEABLE|CHANGELESS))) + if ((flag & CHANGEABLE) != flag) return EINVAL; if (onoff) env->me_flags |= flag; @@ -9555,22 +9457,17 @@ mdb_pid_insert(MDB_PID_T *ids, MDB_PID_T pid) int ESECT mdb_reader_check(MDB_env *env, int *dead) { - if (!env) - return EINVAL; - if (dead) - *dead = 0; - return env->me_txns ? mdb_reader_check0(env, 0, dead) : MDB_SUCCESS; -} - -/** As #mdb_reader_check(). rlocked = <caller locked the reader mutex>. */ -static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead) -{ - mdb_mutex_t *rmutex = rlocked ? NULL : MDB_MUTEX(env, r); unsigned int i, j, rdrs; MDB_reader *mr; MDB_PID_T *pids, pid; - int rc = MDB_SUCCESS, count = 0; + int count = 0; + if (!env) + return EINVAL; + if (dead) + *dead = 0; + if (!env->me_txns) + return MDB_SUCCESS; rdrs = env->me_txns->mti_numreaders; pids = malloc((rdrs+1) * sizeof(MDB_PID_T)); if (!pids) @@ -9578,32 +9475,22 @@ static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead) pids[0] = 0; mr = env->me_txns->mti_readers; for (i=0; i<rdrs; i++) { - pid = mr[i].mr_pid; - if (pid && pid != env->me_pid) { + if (mr[i].mr_pid && mr[i].mr_pid != env->me_pid) { + pid = mr[i].mr_pid; if (mdb_pid_insert(pids, pid) == 0) { if (!mdb_reader_pid(env, Pidcheck, pid)) { - /* Stale reader found */ - j = i; - if (rmutex) { - if ((rc = LOCK_MUTEX0(rmutex)) != 0) { - if ((rc = mdb_mutex_failed(env, rmutex, rc))) - break; - rdrs = 0; /* the above checked all readers */ - } else { - /* Recheck, a new process may have reused pid */ - if (mdb_reader_pid(env, Pidcheck, pid)) - j = rdrs; - } - } - for (; j<rdrs; j++) + LOCK_MUTEX_R(env); + /* Recheck, a new process may have reused pid */ + if (!mdb_reader_pid(env, Pidcheck, pid)) { + for (j=i; j<rdrs; j++) if (mr[j].mr_pid == pid) { DPRINTF(("clear stale reader pid %u txn %"Z"d", (unsigned) pid, mr[j].mr_txnid)); mr[j].mr_pid = 0; count++; } - if (rmutex) - UNLOCK_MUTEX(rmutex); + } + UNLOCK_MUTEX_R(env); } } } @@ -9611,55 +9498,6 @@ static int mdb_reader_check0(MDB_env *env, int rlocked, int *dead) free(pids); if (dead) *dead = count; - return rc; -} - -#ifdef MDB_ROBUST_SUPPORTED -/** Handle #LOCK_MUTEX0() failure. - * Try to repair the lock file if the mutex owner died. - * @param[in] env the environment handle - * @param[in] mutex LOCK_MUTEX0() mutex - * @param[in] rc LOCK_MUTEX0() error (nonzero) - * @return 0 on success with the mutex locked, or an error code on failure. - */ -static int mdb_mutex_failed(MDB_env *env, mdb_mutex_t *mutex, int rc) -{ - int toggle, rlocked, rc2; - - if (rc == MDB_OWNERDEAD) { - /* We own the mutex. Clean up after dead previous owner. */ - rc = MDB_SUCCESS; - rlocked = (mutex == MDB_MUTEX(env, r)); - if (!rlocked) { - /* Keep mti_txnid updated, otherwise next writer can - * overwrite data which latest meta page refers to. - */ - toggle = mdb_env_pick_meta(env); - env->me_txns->mti_txnid = env->me_metas[toggle]->mm_txnid; - /* env is hosed if the dead thread was ours */ - if (env->me_txn) { - env->me_flags |= MDB_FATAL_ERROR; - env->me_txn = NULL; - rc = MDB_PANIC; - } - } - DPRINTF(("%cmutex owner died, %s", (rlocked ? 'r' : 'w'), - (rc ? "this process' env is hosed" : "recovering"))); - rc2 = mdb_reader_check0(env, rlocked, NULL); - if (rc2 == 0) - rc2 = mdb_mutex_consistent(mutex); - if (rc || (rc = rc2)) { - DPRINTF(("LOCK_MUTEX recovery failed, %s", mdb_strerror(rc))); - UNLOCK_MUTEX(mutex); - } - } else { -#ifdef _WIN32 - rc = ErrCode(); -#endif - DPRINTF(("LOCK_MUTEX failed, %s", mdb_strerror(rc))); - } - - return rc; + return MDB_SUCCESS; } -#endif /* MDB_ROBUST_SUPPORTED */ /** @} */ |