Correct way to use MapDB DB instances with multiple concurrent threads

242 views
Skip to first unread message

Paul Jackson

unread,
Oct 12, 2017, 9:56:30 AM10/12/17
to MapDB
I am confused by the documentation when it describes the DB object:
A DB instance represents an opened database (or a single transaction session).

It sounds like each thread should have its own DB instance. I wrote this test class:
import org.mapdb.BTreeMap;
import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.mapdb.Serializer;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

public class MapDbTest
{
 
static final AtomicInteger count = new AtomicInteger(0);
 
public static void main(String[] args) throws InterruptedException
 
{
    DB db
= getDbMaker().make();
   
BTreeMap<String, Long> bTreeMap = getTreeMapMaker(db).create();
//    db.close();
   
CyclicBarrier barrier = new CyclicBarrier(2);
   
Thread t1 = new Thread(new MyRunnable(db, barrier));
    t1
.start();
   
Thread t2 = new Thread(new MyRunnable(db, barrier));
    t2
.start();
    t1
.join();
    t2
.join();
//    db = getDbMaker().make();
//    bTreeMap = getTreeMapMaker(db).open();
   
System.out.println(bTreeMap.entrySet());
 
}

 
private static DB.TreeMapMaker<String, Long> getTreeMapMaker(DB db)
 
{
   
return db.treeMap("test").
            keySerializer
(Serializer.STRING).
            valueSerializer
(Serializer.LONG);
 
}

 
private static DBMaker.Maker getDbMaker()
 
{
   
return DBMaker.fileDB("db").
            fileMmapEnableIfSupported
().
            cleanerHackEnable
();
//            fileLockDisable();
 
}

 
private static class MyRunnable implements Runnable
 
{
   
private final DB db;
   
private final CyclicBarrier barrier;

   
MyRunnable(DB db, CyclicBarrier barrier)
   
{
     
this.db = db;
     
this.barrier = barrier;
   
}

   
@Override
   
public void run()
   
{
     
try
     
{
        barrier
.await();
//        DB db = getDbMaker().make();
       
BTreeMap<String, Long> bTreeMap = getTreeMapMaker(db).open();
        barrier
.await();
        bTreeMap
.put("ABC" + count.getAndIncrement(), 0L);
        barrier
.await();
        db
.commit();
     
}
     
catch (InterruptedException | BrokenBarrierException e)
     
{
        e
.printStackTrace();
     
}
   
}
 
}
}

The code as written appears to work correctly. I expected the commented lines to be required, but when I remove those comments, I find that the work of one thread replaces the other. That is, instead of outputting:
[MapEntry[ABC0=0], MapEntry[ABC1=0]]
it outputs:
[MapEntry[ABC0=0]]

I'm hoping someone can explain when a DB instance should be shared amongst threads and when the threads should make their own instance.

Thanks,
-Paul

Reply all
Reply to author
Forward
0 new messages