2323import jnr .ffi .byref .PointerByReference ;
2424import static org .lmdbjava .ByteBufferProxy .PROXY_OPTIMAL ;
2525import static org .lmdbjava .ByteUnit .MEBIBYTES ;
26+ import static org .lmdbjava .EnvFlags .MDB_RDONLY_ENV ;
2627import static org .lmdbjava .Library .LIB ;
2728import org .lmdbjava .Library .MDB_envinfo ;
2829import org .lmdbjava .Library .MDB_stat ;
2930import static org .lmdbjava .Library .RUNTIME ;
31+ import static org .lmdbjava .MaskedFlag .isSet ;
3032import static org .lmdbjava .MaskedFlag .mask ;
3133import static org .lmdbjava .ResultCodeMapper .checkRc ;
32- import static org .lmdbjava .TxnFlags .MDB_RDONLY ;
34+ import static org .lmdbjava .TxnFlags .MDB_RDONLY_TXN ;
3335
3436/**
3537 * LMDB environment.
@@ -57,8 +59,7 @@ public final class Env<T> implements AutoCloseable {
5759 * @return the environment (never null)
5860 */
5961 public static Builder <ByteBuffer > create () {
60- Env <ByteBuffer > env = new Env <>(PROXY_OPTIMAL );
61- return new Builder <>(env );
62+ return new Builder <>(PROXY_OPTIMAL );
6263 }
6364
6465 /**
@@ -69,7 +70,7 @@ public static Builder<ByteBuffer> create() {
6970 * @return the environment (never null)
7071 */
7172 public static <T > Builder <T > create (final BufferProxy <T > proxy ) {
72- return new Builder <>(new Env <>( proxy ) );
73+ return new Builder <>(proxy );
7374 }
7475
7576 /**
@@ -82,23 +83,21 @@ public static <T> Builder<T> create(final BufferProxy<T> proxy) {
8283 * @return env the environment (never null)
8384 */
8485 public static Env <ByteBuffer > open (File path , int size , EnvFlags ... flags ) {
85- Env <ByteBuffer > env = new Env <>(PROXY_OPTIMAL );
86- return new Builder <>(env )
87- .setMaxDbs (1 )
86+ return new Builder <>(PROXY_OPTIMAL )
8887 .setMapSize (size , MEBIBYTES )
8988 .open (path , flags );
9089 }
9190
9291 private boolean closed = false ;
9392 private final BufferProxy <T > proxy ;
9493 final Pointer ptr ;
94+ final boolean readOnly ;
9595
96- private Env (final BufferProxy <T > proxy ) {
97- requireNonNull ( proxy );
96+ private Env (final BufferProxy <T > proxy , final Pointer ptr ,
97+ final boolean readOnly ) {
9898 this .proxy = proxy ;
99- final PointerByReference envPtr = new PointerByReference ();
100- checkRc (LIB .mdb_env_create (envPtr ));
101- ptr = envPtr .getValue ();
99+ this .readOnly = readOnly ;
100+ this .ptr = ptr ;
102101 }
103102
104103 /**
@@ -188,9 +187,9 @@ public boolean isClosed() {
188187 * @return a database that is ready to use
189188 */
190189 public Dbi <T > openDbi (final String name , final DbiFlags ... flags ) {
191- try (Txn <T > txn = txnWrite ()) {
190+ try (Txn <T > txn = readOnly ? txnRead () : txnWrite ()) {
192191 final Dbi <T > dbi = new Dbi <>(this , txn , name , flags );
193- txn .commit ();
192+ txn .commit (); // even RO Txns require a commit to retain Dbi in Env
194193 return dbi ;
195194 }
196195 }
@@ -247,7 +246,7 @@ public Txn<T> txn(final Txn<T> parent, final TxnFlags... flags) {
247246 * @return a read-only transaction
248247 */
249248 public Txn <T > txnRead () {
250- return new Txn <>(this , null , proxy , MDB_RDONLY );
249+ return new Txn <>(this , null , proxy , MDB_RDONLY_TXN );
251250 }
252251
253252 /**
@@ -292,15 +291,19 @@ public AlreadyOpenException() {
292291 /**
293292 * Builder for configuring and opening Env.
294293 *
295- * @param <T> buffer type
294+ * @param <T>
296295 */
297296 public static final class Builder <T > {
298297
299- private final Env <T > env ;
298+ private long mapSize = MEBIBYTES .toBytes (1 );
299+ private int maxDbs = 1 ;
300+ private int maxReaders = 1 ;
300301 private boolean opened = false ;
302+ private final BufferProxy <T > proxy ;
301303
302- private Builder (Env <T > env ) {
303- this .env = env ;
304+ private Builder (final BufferProxy <T > proxy ) {
305+ requireNonNull (proxy );
306+ this .proxy = proxy ;
304307 }
305308
306309 /**
@@ -317,10 +320,17 @@ public Env<T> open(final File path, final int mode,
317320 if (opened ) {
318321 throw new AlreadyOpenException ();
319322 }
320- final int flagsMask = mask (flags );
321- checkRc (LIB .mdb_env_open (env .ptr , path .getAbsolutePath (), flagsMask , mode ));
322323 opened = true ;
323- return this .env ;
324+ final PointerByReference envPtr = new PointerByReference ();
325+ checkRc (LIB .mdb_env_create (envPtr ));
326+ final Pointer ptr = envPtr .getValue ();
327+ checkRc (LIB .mdb_env_set_mapsize (ptr , mapSize ));
328+ checkRc (LIB .mdb_env_set_maxdbs (ptr , maxDbs ));
329+ checkRc (LIB .mdb_env_set_maxreaders (ptr , maxReaders ));
330+ final int flagsMask = mask (flags );
331+ final boolean readOnly = isSet (flagsMask , MDB_RDONLY_ENV );
332+ checkRc (LIB .mdb_env_open (ptr , path .getAbsolutePath (), flagsMask , mode ));
333+ return new Env <>(proxy , ptr , readOnly );
324334 }
325335
326336 /**
@@ -344,7 +354,7 @@ public Builder<T> setMapSize(final long mapSize) {
344354 if (opened ) {
345355 throw new AlreadyOpenException ();
346356 }
347- checkRc ( LIB . mdb_env_set_mapsize ( env . ptr , mapSize )) ;
357+ this . mapSize = mapSize ;
348358 return this ;
349359 }
350360
@@ -369,7 +379,7 @@ public Builder<T> setMaxDbs(final int dbs) {
369379 if (opened ) {
370380 throw new AlreadyOpenException ();
371381 }
372- checkRc ( LIB . mdb_env_set_maxdbs ( env . ptr , dbs )) ;
382+ this . maxDbs = dbs ;
373383 return this ;
374384 }
375385
@@ -383,7 +393,7 @@ public Builder<T> setMaxReaders(final int readers) {
383393 if (opened ) {
384394 throw new AlreadyOpenException ();
385395 }
386- checkRc ( LIB . mdb_env_set_maxreaders ( env . ptr , readers )) ;
396+ this . maxReaders = readers ;
387397 return this ;
388398 }
389399 }
0 commit comments