@Test
    void testValueMutation() {
        final int cnt = 10;

        final BasicLmdbDb<String, MultiKey> lmdbDb = new BasicLmdbDb<>(
                lmdbEnv,
                byteBufferPool,
                new StringSerde(),
                new MultiKeySerde(),
                "testValueMutation");

        final List<Entry<String, MultiKey>> entries = new ArrayList<>(cnt);

        IntStream.rangeClosed(1, cnt)
                .boxed()
                .map(i -> new SimpleEntry<>(
                        "key-" + i,
                        new MultiKey(i, i, i, i, "value-" + i)))
                .forEach(entries::add);

        lmdbEnv.doWithWriteTxn(writeTxn -> {
            LOGGER.logDurationIfDebugEnabled(() -> {
                entries
                        .forEach(entry -> {
                            try (final PooledByteBufferPair pooledBufferPair = lmdbDb.getPooledBufferPair()) {
                                final ByteBuffer keyBuff = pooledBufferPair.getKeyBuffer();
                                final ByteBuffer valBuff = pooledBufferPair.getValueBuffer();
                                lmdbDb.serializeKey(keyBuff, entry.getKey());
                                lmdbDb.serializeValue(valBuff, entry.getValue());
                                lmdbDb.getLmdbDbi().put(
                                        writeTxn,
                                        keyBuff,
                                        valBuff,
                                        PutFlags.MDB_NOOVERWRITE);
                            }
                        });
            }, "initial load");
        });

        final TimedCase incrementLongInPlaceCase = TimedCase.of("Increment long in place", (round, iterations) -> {
            if (lmdbEnv.getEnvFlags().contains(EnvFlags.MDB_WRITEMAP)) {
                lmdbEnv.doWithWriteTxn(writeTxn -> {
                    entries
                            .forEach(entry -> {
                                try (final PooledByteBufferPair pooledBufferPair = lmdbDb.getPooledBufferPair()) {
                                    final ByteBuffer keyBuff = pooledBufferPair.getKeyBuffer();
                                    lmdbDb.serializeKey(keyBuff, entry.getKey());
                                    final ByteBuffer valBuff = lmdbDb.getLmdbDbi().get(writeTxn,
                                            keyBuff);

                                    // Mutating the value buffer without a copy only works if MDB_WRITEMAP is set
                                    MultiKeySerde.incrementLong2(valBuff);
                                }
                            });
                });
            } else {
                LOGGER.warn("{} not set on env so can't test increment in place", EnvFlags.MDB_WRITEMAP);
            }
        });

        final TimedCase incUnsignedInPlaceCase = TimedCase.of(
                "Increment unsigned long in place",
                (round, iterations) -> {
                    if (lmdbEnv.getEnvFlags().contains(EnvFlags.MDB_WRITEMAP)) {
                        lmdbEnv.doWithWriteTxn(writeTxn -> {
                            entries.forEach(entry -> {
                                try (final PooledByteBufferPair pooledBufferPair = lmdbDb.getPooledBufferPair()) {
                                    final ByteBuffer keyBuff = pooledBufferPair.getKeyBuffer();
                                    lmdbDb.serializeKey(keyBuff, entry.getKey());
                                    final ByteBuffer valBuff = lmdbDb.getLmdbDbi().get(writeTxn,
                                            keyBuff);

                                    // Mutating the value buffer without a copy only works if MDB_WRITEMAP is set
                                    MultiKeySerde.incrementUnsignedLong(valBuff);
                                }
                            });
                        });
                    } else {
                        LOGGER.warn("{} not set on env so can't test increment in place", EnvFlags.MDB_WRITEMAP);
                    }
                });

        final TimedCase getPutCase = TimedCase.of("Get/Put increment", (round, iterations) -> {
            lmdbEnv.doWithWriteTxn(writeTxn -> {
                entries.forEach(entry -> {
                    try (final PooledByteBufferPair pooledBufferPair = lmdbDb.getPooledBufferPair()) {
                        final ByteBuffer keyBuff = pooledBufferPair.getKeyBuffer();
                        final ByteBuffer newValBuff = pooledBufferPair.getValueBuffer();
                        lmdbDb.serializeKey(keyBuff, entry.getKey());
                        // Mutate the value using get/put via a copy of the buffer. This is the only
                        // way if MDB_WRITEMAP is not set.
                        final ByteBuffer dbValBuff = lmdbDb.getLmdbDbi().get(
                                writeTxn,
                                keyBuff);
                        ByteBufferUtils.copy(dbValBuff, newValBuff);

                        UNSIGNED_BYTES.increment(newValBuff);
                        MultiKeySerde.incrementLong2(newValBuff);
                        lmdbDb.put(writeTxn, keyBuff, newValBuff, false);
                    }
                });
            });
        });

        TestUtil.comparePerformance(
                2,
                cnt,
                LOGGER::info,
                incrementLongInPlaceCase,
                incUnsignedInPlaceCase,
                getPutCase);
    }
This test is an example of how to abuse LMDB. If run it will crash the JVM
as a direct bytebuffer returned from a get() was mutated outside the transaction.
stroom-lmdb/src/test/java/stroom/lmdb/TestBasicLmdbDb.java