[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#7688) MDB_WRITEMAP + non-writemap process broken

Full_Name: Hallvard B Furuseth
Version: LMDB_0.9.8
OS: Linux x86_64
Submission from: (NULL) (
Submitted by: hallvard

mdb_env_open(,,MDB_WRITEMAP,) does not grow the data
file to the mapsize if another process has it open
without MDB_WRITEMAP. The new MDB_env gets Bus Error
in mdb_page_alloc() if it tries to grow mt_next_pgno.

Broken by 2e7130cab0129e3b72a25d39c5d4e5a5c55cb353
"Allow mdb_env_set_mapsize() on an open environment".
It made ftruncate() conditional on 'newsize'.  To
avoid mapsize wars between environments?  Could do:

if (flags & MDB_WRITEMAP) {
    prot |= PROT_WRITE;
    if (!newsize) {
        off_t pos = lseek(env->me_fd, 0, SEEK_END);
        if (pos == (off_t)-1)
            return ErrCode();
        if ((size_t)pos < env->me_mapsize)
            newsize = 1;
    if (newsize && ftruncate(env->me_fd, env->me_mapsize) < 0)
        return ErrCode();

But that still has a race between processes mapping
the environment at the same time, one process could
shrink the map just after another grew it.  And I'm
unsure how env->me_mapsize would end up in this case.

Another way: Move ftruncate() to mdb_page_alloc(),
which has no race. Grow to <new mt_next_pgno + 25%>.
To avoid seeks, maintain me_txns->mti_next_pgno in
mdb_page_alloc{MDB_WRITEMAP} and txn_reset(writer).