@Test
    void testPutsWithConcurrentReadTxn() throws ExecutionException, InterruptedException {
        try (TemporaryPathCreator temporaryPathCreator = new TemporaryPathCreator()) {
            final BasicLmdbDb<String, String> basicLmdb1 = createDb(
                    temporaryPathCreator,
                    new EnvFlags[]{EnvFlags.MDB_NOTLS},
                    false,
                    "1");
            final LmdbEnv lmdbEnv = basicLmdb1.getLmdbEnvironment();

            final AtomicInteger runNo = new AtomicInteger(1);

            final Consumer<Txn<ByteBuffer>> putConsumer = writeTxn -> {
                final int run = runNo.getAndIncrement();
//                LOGGER.info("Putting for run: {}", run);
                for (int i = 1; i <= 1_000; i++) {
                    basicLmdb1.put(
                            writeTxn,
                            Strings.padStart(Integer.toString(i), 6, '0'),
                            "val-"
                            + Strings.padStart(Integer.toString(i), 6, '0')
                            + "_run-"
                            + Strings.padStart(Integer.toString(run), 3, '0'),
                            true);

                }
                final Optional<String> optVal1 = basicLmdb1.get(writeTxn, "000001");
                assertThat(optVal1)
                        .isNotEmpty();
//                LOGGER.info("Val for key 1: {}", optVal1.orElse("[empty]"));
            };

            // Initial rounds of putting the same set of keys but with different values
            // each round.
            for (int i = 0; i < 5; i++) {
                lmdbEnv.doWithWriteTxn(putConsumer);
                LOGGER.info("Run: {}, DB size on disk: {}, entry count: {}",
                        runNo.get() - 1,  // already incremented
                        ByteSize.ofBytes(lmdbEnv.getSizeOnDisk()),
                        basicLmdb1.getEntryCount());
            }

            final CountDownLatch readStartLatch = new CountDownLatch(1);
            final CountDownLatch writeFinishLatch = new CountDownLatch(1);

            final CompletableFuture<Void> readFuture = CompletableFuture.runAsync(() -> {
                LOGGER.info("Read thread started");
                lmdbEnv.doWithReadTxn(ThrowingConsumer.unchecked(readTxn -> {
                    LOGGER.info("Read txn started");
                    readStartLatch.countDown();
                    LOGGER.info("readStartLatch counted down");

                    // Just hold the readTxn open while all the writes happen

                    awaitWithTimeout(writeFinishLatch, 10);
                }));
                LOGGER.info("Finished read thread");
            });

            // Wait for the read txn to be active
            awaitWithTimeout(readStartLatch, 10);

            final CompletableFuture<Void> writeFuture = CompletableFuture.runAsync(() -> {
                LOGGER.info("Write thread started");
                lmdbEnv.doWithWriteTxn(ThrowingConsumer.unchecked(writeTxn -> {
                    LOGGER.info("Write txn started");

                    for (int i = 0; i < 5; i++) {
                        // Initial puts with no read txn
                        putConsumer.accept(writeTxn);
                        LOGGER.info("Run: {}, DB size on disk: {}, entry count: {}",
                                runNo.get() - 1,  // already incremented
                                ByteSize.ofBytes(lmdbEnv.getSizeOnDisk()),
                                basicLmdb1.getEntryCount());
                    }

                    writeFinishLatch.countDown();
                }));
                LOGGER.info("Finished write thread");
            });

            readFuture.get();
            writeFuture.get();
        }
    }
See the impact on disk space of doing writes with an open read txn
stroom-lmdb/src/test/java/stroom/lmdb/TestBasicLmdbDb.java