bmatsuo / lmdb-go

Bindings for the LMDB C library
BSD 3-Clause "New" or "Revised" License
156 stars 59 forks source link

mdb_txn_renew: MDB_BAD_RSLOT: Invalid reuse of reader locktable slot #119

Closed ghost closed 7 years ago

ghost commented 7 years ago

I have a map and struct db defined like below:

dbMap map[int]db

type db struct {
        env         *lmdb.Env
        id          uint64
    actives     uint32

    dbi         lmdb.DBI
    cursor      *lmdb.Cursor
    rtxn        *lmdb.Txn
} 

When I need to open or close a new db, I create it in a write txn with a global env named globalEnv the code like below:

globalEnv.update(func(txn *lmdb.Txn) error {
        if _, ok := dbMap[id]; ok {
                return nil
        }

        db := &db{}
        ....
        env.Open(path, lmdb.Readonly|lmdb.NoSync|lmdb.NoSubdir, 0664)
        db.env = env
        rtxn, err := env.BeginTxn(nil, lmdb.Readonly)
        if err != nil {
            return err
        }
    db.rtxn = rtxn
    cursor, err := rtxn.OpenCursor(db.dbi)
    if err != nil {
        return err
    }
    db.cursor = cursor
    rtxn.Reset()

        dbMap[id] = db
}) 

I search map and scanner db in globalEnv.Update like below:

globalEnv.update(func(txn *lmdb.Txn) error {
         db, ok := dbMap[id]
         if !ok {
                Panic("xxx");
         }

         defer db.rtxn.Reset()
     if err := db.rtxn.Renew(); err != nil {
         log.Println("db.rtxn renew failed: ", err)
     }
         .... 
}) 

I have two goroutine to call above codes, after run sometime (most of the time, it works ok), I get error:

mdb_txn_renew: MDB_BAD_RSLOT: Invalid reuse of reader locktable slot

go version: 1.7.3 and above lmdb-go version: 7b9e3bb5a8e4b9aac8972dced855c5aabad6ba2e

ghost commented 7 years ago

I print in mdb.c's mdb_txn_renew0 get

in mdb_txn_renew0 r->mr_pid: 0, env->me_pid: 17718, r->mr_txnid: 18446744073709551615

ghost commented 7 years ago

@bmatsuo Execute me, is there a good way to debug this? I have totally no idea.