├── src ├── test │ └── java │ │ └── org │ │ └── mapdb │ │ ├── guavaTests │ │ ├── GwtCompatible.java │ │ └── Helpers.java │ │ ├── StoreWALTxTest.kt │ │ ├── CCTest.kt │ │ ├── BTreeMapExtraTest.kt │ │ ├── UseFromJava.java │ │ ├── BTreeKeySet_JSR166_ConcurrentSkipListSetTest.kt │ │ ├── BTreeSetTest.java │ │ ├── HTreeMapV8Test.kt │ │ ├── BTreeKeySet_JSR166_ConcurrentSkipListSubSetTest.kt │ │ ├── IndexTreeList_JSR166Test.kt │ │ ├── jsr166Tests │ │ ├── CollectionImplementation.java │ │ ├── CollectionTest.java │ │ └── Collection8Test.java │ │ ├── StoreTxTest.kt │ │ ├── BTreeMapNavigableSubMapInclusiveTest.java │ │ ├── volume │ │ ├── FileLockTest.kt │ │ ├── XXHashTest.kt │ │ ├── FileCrashTestr.kt │ │ ├── FileChannelCrashTest.kt │ │ ├── RAFCrashtest.kt │ │ ├── VolumeSyncCrashTest.kt │ │ └── VolumeCrashTest.kt │ │ ├── BTreeMap_ConcurrentSkipListSubMapTest_JSR166Test.kt │ │ ├── HTreeMap_JSR166Test.kt │ │ ├── BTreeMapNavigableSubMapExclusiveTest.java │ │ ├── UtilsTest.kt │ │ ├── BTreeMap_ConcurrentSkipListMapTest_JSR166Test.kt │ │ ├── issues │ │ ├── Issue697.java │ │ ├── IssueFromDatumbox.java │ │ ├── Issue418Test.java │ │ └── ParallelMaps.kt │ │ ├── DataOutput2Test.java │ │ ├── JUnitRunListener.kt │ │ ├── BTreeMapParTest.kt │ │ ├── HTreeMapConcTest.kt │ │ ├── BTreeMap_HashMap_JSR166Test.kt │ │ ├── MapExtraTest.kt │ │ ├── crash │ │ ├── UnplugFileOutputStreamCrash.kt │ │ ├── WALChannelCrashTest.kt │ │ ├── StoreCrashTest.kt │ │ ├── WALCrashTest.kt │ │ └── WALStreamCrashTest.kt │ │ ├── BTreeMap_SortedMap_GuavaTest.kt │ │ ├── HTreeMap_Expiration_Multithreaded.kt │ │ ├── SortedTableMap_ConcurrentMap_Guava.kt │ │ ├── PumpTest.kt │ │ ├── StoreWALTest.kt │ │ ├── SortedTableMap_ConcurrentSkipListSubMapTest_JSR166Test.kt │ │ ├── AtomicStringTest.java │ │ ├── AtomicVarTest.java │ │ ├── IndexTreeListJavaTest.kt │ │ ├── BrokenDBTest.kt │ │ ├── DBBrokenTest.java │ │ ├── AtomicBooleanTest.java │ │ ├── WALSequence.java │ │ ├── DBSerTest.kt │ │ ├── WALTruncate.java │ │ ├── SortedTableMap_ConcurrentSkipListMapTest_JSR166Test.kt │ │ └── StoreReopenTest.kt └── main │ └── java │ └── org │ └── mapdb │ ├── Verifiable.kt │ ├── QueueLongTakeUntil.java │ ├── StoreBinaryGetLong.java │ ├── MapModificationListener.java │ ├── ConcurrencyAware.kt │ ├── serializer │ ├── SerializerElsa.kt │ ├── SerializerIllegalAccess.java │ ├── SerializerBigInteger.java │ ├── SerializerByte.java │ ├── SerializerChar.java │ ├── SerializerShort.java │ ├── SerializerRecidArray.java │ ├── SerializerStringIntern.java │ ├── SerializerBigDecimal.java │ ├── SerializerDouble.java │ ├── SerializerFloat.java │ ├── SerializerDate.java │ ├── SerializerStringOrigHash.java │ ├── SerializerStringNoSize.java │ ├── SerializerInteger.java │ ├── SerializerStringAscii.java │ ├── SerializerByteArrayNoSize.java │ ├── SerializerClass.java │ ├── SerializerLong.java │ ├── SerializerFloatArray.java │ ├── SerializerJava.java │ ├── SerializerRecid.java │ ├── SerializerDoubleArray.java │ ├── SerializerLongPacked.java │ ├── SerializerIntegerPacked.java │ ├── SerializerCharArray.java │ ├── SerializerShortArray.java │ ├── SerializerByteArrayDelta.java │ ├── SerializerIntArray.java │ ├── SerializerLongArray.java │ ├── SerializerLongDelta.java │ ├── GroupSerializer.java │ ├── SerializerIntegerDelta.java │ ├── GroupSerializerObjectArray.java │ ├── SerializerUtils.java │ ├── SerializerArrayDelta.java │ ├── SerializerStringDelta.java │ ├── SerializerArray.java │ ├── SerializerBoolean.java │ ├── SerializerEightByte.java │ ├── SerializerFourByte.java │ └── SerializerString.java │ ├── volume │ ├── ReadOnlyVolumeFactory.kt │ ├── VolumeFactory.java │ └── ByteBufferMemoryVolSingle.java │ ├── Store.kt │ ├── StoreReadOnlyWrapper.kt │ ├── StoreDirectJava.java │ ├── CC.java │ ├── DBException.kt │ └── MapExtra.kt ├── .travis.yml ├── .gitignore ├── logger.properties └── README.md /src/test/java/org/mapdb/guavaTests/GwtCompatible.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.guavaTests; 2 | 3 | public @interface GwtCompatible { 4 | } 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | cache: 3 | directories: 4 | - $HOME/.m2 5 | 6 | jdk: 7 | - oraclejdk8 8 | 9 | install: true 10 | 11 | script: mvn test 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .classpath 2 | .project 3 | .settings 4 | .idea 5 | target 6 | build 7 | bin 8 | out 9 | helper 10 | *.iml 11 | *.ipr 12 | *.iws 13 | .directory 14 | *.log 15 | .gradle 16 | *.log -------------------------------------------------------------------------------- /src/test/java/org/mapdb/StoreWALTxTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | class StoreWALTxTest:StoreTxTest(){ 4 | 5 | override fun open(): StoreTx { 6 | return StoreWAL.make() 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/Verifiable.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | /** 4 | * Class can verify its status and data integrity: collections, Stores... 5 | */ 6 | interface Verifiable{ 7 | 8 | fun verify(); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/QueueLongTakeUntil.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | /** 4 | * Callback interface for {@link QueueLong} 5 | */ 6 | public interface QueueLongTakeUntil { 7 | 8 | boolean take(long nodeRecid, QueueLong.Node node); 9 | } 10 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/CCTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Test 4 | import org.junit.Assert.assertEquals 5 | 6 | class CCTest{ 7 | @Test fun constants(){ 8 | assertEquals(CC.PAGE_SIZE, 1L shl CC.PAGE_SHIFT) 9 | } 10 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMapExtraTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | class BTreeMapExtraTest:MapExtraTest(){ 4 | 5 | override fun makeMap(): MapExtra { 6 | return BTreeMap.make(keySerializer = Serializer.INTEGER, valueSerializer = Serializer.STRING) 7 | } 8 | 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/StoreBinaryGetLong.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import java.io.IOException; 4 | 5 | /** 6 | * Binary operations performed on {@link StoreBinary} which retuns long 7 | */ 8 | public interface StoreBinaryGetLong { 9 | 10 | long get(DataInput2 input, int size) throws IOException; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/UseFromJava.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import org.junit.Test; 4 | 5 | import java.nio.channels.OverlappingFileLockException; 6 | 7 | /** 8 | * Tests jave interoperability 9 | */ 10 | public class UseFromJava { 11 | @Test 12 | public void basic_store() { 13 | StoreTrivial st = new StoreTrivial(); 14 | st.put(1L, Serializer.LONG); 15 | st.close(); 16 | } 17 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeKeySet_JSR166_ConcurrentSkipListSetTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.mapdb.jsr166Tests.ConcurrentSkipListSetTest 4 | 5 | /** 6 | * Created by jan on 4/2/16. 7 | */ 8 | class BTreeKeySet_JSR166_ConcurrentSkipListSetTest: ConcurrentSkipListSetTest(){ 9 | 10 | override fun emptySet() = DBMaker.memoryDB().make() 11 | .treeSet("aa").serializer(Serializer.INTEGER).create() 12 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/MapModificationListener.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | 6 | /** 7 | * Callback interface for {@link MapExtra} modification notifications. 8 | */ 9 | public interface MapModificationListener { 10 | 11 | void modify(@NotNull K key, @Nullable V oldValue, @Nullable V newValue, boolean triggered); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeSetTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | 4 | import org.junit.Before; 5 | 6 | import java.util.Collections; 7 | 8 | @SuppressWarnings({ "unchecked", "rawtypes" }) 9 | public class BTreeSetTest extends HTreeSetTest{ 10 | 11 | @Before 12 | public void setUp() throws Exception { 13 | db = DBMaker.memoryDB().make(); 14 | 15 | hs = db.treeSet("name").make(); 16 | 17 | Collections.addAll(hs, objArray); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/HTreeMapV8Test.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.mapdb.jsr166Tests.ConcurrentHashMapV8Test 4 | import java.util.concurrent.ConcurrentMap 5 | 6 | /** 7 | * Created by jan on 4/2/16. 8 | */ 9 | class HtreeMapV8Test: ConcurrentHashMapV8Test() { 10 | 11 | override fun newMap(): ConcurrentMap<*, *>? { 12 | return HTreeMap.make() 13 | } 14 | 15 | override fun newMap(size: Int): ConcurrentMap<*, *>? { 16 | return newMap() 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/guavaTests/Helpers.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.guavaTests; 2 | 3 | 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | 9 | public class Helpers { 10 | public static Map.Entry mapEntry(final K key, final V value) { 11 | Map m = new HashMap(); 12 | m.put(key,value); 13 | m = Collections.unmodifiableMap(m); 14 | return m.entrySet().iterator().next(); 15 | } 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeKeySet_JSR166_ConcurrentSkipListSubSetTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.mapdb.jsr166Tests.ConcurrentSkipListSubSetTest 4 | import java.util.concurrent.ConcurrentSkipListSet 5 | 6 | /** 7 | * Created by jan on 4/2/16. 8 | */ 9 | class BTreeKeySet_JSR166_ConcurrentSkipListSubSetTest : ConcurrentSkipListSubSetTest(){ 10 | override fun emptySet() = DBMaker 11 | .memoryDB().make().treeSet("aa") 12 | .serializer(Serializer.INTEGER).create() 13 | 14 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/ConcurrencyAware.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | /** 4 | * Concurrency aware, can verify that its configuration is thread safe 5 | */ 6 | interface ConcurrencyAware{ 7 | 8 | /** returns true if this is configured to be thread safe */ 9 | val isThreadSafe:Boolean 10 | 11 | /** checks all subcomponents, if this component is really thread safe, and throws an exception if not thread safe */ 12 | fun checkThreadSafe() { 13 | if(isThreadSafe.not()) 14 | throw AssertionError(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/IndexTreeList_JSR166Test.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.mapdb.jsr166Tests.CopyOnWriteArrayListTest 4 | import java.util.* 5 | 6 | class IndexTreeList_JSR166Test:CopyOnWriteArrayListTest(){ 7 | 8 | override fun emptyArray():MutableList { 9 | val store = StoreDirect.make(); 10 | val index = IndexTreeLongLongMap.make(store) 11 | val list = IndexTreeList(store = store, serializer=Serializer.INTEGER, isThreadSafe = true, 12 | map =index, counterRecid = store.put(0L, Serializer.LONG_PACKED)) 13 | return list 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerElsa.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer 2 | 3 | import org.mapdb.DataInput2 4 | import org.mapdb.DataOutput2 5 | import org.mapdb.elsa.SerializerPojo 6 | 7 | /** 8 | * Uses Elsa serialization: http://www.github.com/jankotek/elsa 9 | */ 10 | class SerializerElsa :GroupSerializerObjectArray(){ 11 | 12 | protected val ser = SerializerPojo() 13 | 14 | override fun deserialize(input: DataInput2, available: Int): Any? { 15 | return ser.deserialize(input, available) 16 | } 17 | 18 | override fun serialize(out: DataOutput2, value: Any) { 19 | ser.serialize(out, value) 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/volume/ReadOnlyVolumeFactory.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | /** 4 | * Wraps volume factory and returns volume as readonly 5 | */ 6 | class ReadOnlyVolumeFactory(protected val volfab:VolumeFactory): VolumeFactory() { 7 | 8 | override fun exists(file: String?): Boolean { 9 | return volfab.exists(file) 10 | } 11 | 12 | override fun makeVolume(file: String?, readOnly: Boolean, fileLockWait:Long, sliceShift: Int, initSize: Long, fixedSize: Boolean): Volume? { 13 | val volume = volfab.makeVolume(file, readOnly, fileLockWait, sliceShift, initSize, fixedSize) 14 | return ReadOnlyVolume(volume) 15 | } 16 | 17 | override fun handlesReadonly(): Boolean { 18 | return true 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/jsr166Tests/CollectionImplementation.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.jsr166Tests;/* 2 | * Written by Doug Lea and Martin Buchholz with assistance from 3 | * members of JCP JSR-166 Expert Group and released to the public 4 | * domain, as explained at 5 | * http://creativecommons.org/publicdomain/zero/1.0/ 6 | */ 7 | 8 | import java.util.Collection; 9 | 10 | /** Allows tests to work with different Collection implementations. */ 11 | public interface CollectionImplementation { 12 | /** Returns the Collection class. */ 13 | public Class klazz(); 14 | /** Returns an empty collection. */ 15 | public Collection emptyCollection(); 16 | public Object makeElement(int i); 17 | public boolean isConcurrent(); 18 | public boolean permitsNulls(); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerIllegalAccess.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerIllegalAccess extends GroupSerializerObjectArray { 13 | @Override 14 | public void serialize(DataOutput2 out, Object value) throws IOException { 15 | throw new IllegalAccessError(); 16 | } 17 | 18 | @Override 19 | public Object deserialize(DataInput2 in, int available) throws IOException { 20 | throw new IllegalAccessError(); 21 | } 22 | 23 | @Override 24 | public boolean isTrusted() { 25 | return true; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/StoreTxTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Test 4 | import org.junit.Assert.* 5 | 6 | abstract class StoreTxTest{ 7 | 8 | abstract fun open():StoreTx 9 | 10 | @Test fun rollback_void(){ 11 | val s = open() 12 | val recid = s.put("aaa", Serializer.STRING) 13 | s.rollback() 14 | TT.assertFailsWith(DBException.GetVoid::class.java){ 15 | s.get(recid, Serializer.STRING) 16 | } 17 | s.close() 18 | } 19 | 20 | 21 | @Test fun rollback_change(){ 22 | val s = open() 23 | val recid = s.put("aaa", Serializer.STRING) 24 | s.commit() 25 | s.update(recid, "bbb", Serializer.STRING) 26 | s.rollback() 27 | assertEquals("aaa", s.get(recid, Serializer.STRING)) 28 | s.close() 29 | } 30 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMapNavigableSubMapInclusiveTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import java.util.NavigableMap; 4 | 5 | public class BTreeMapNavigableSubMapInclusiveTest extends BTreeMapNavigable2Test{ 6 | 7 | public static class Outside extends BTreeMapNavigableSubMapInclusiveTest{ 8 | @Override protected NavigableMap newMap() { 9 | return DBMaker.memoryDB().make().treeMap("map", Serializer.INTEGER, Serializer.STRING).create(); 10 | } 11 | } 12 | 13 | 14 | @Override 15 | public void setUp() throws Exception { 16 | super.setUp(); 17 | map.put(0,"zero"); 18 | map.put(11,"eleven"); 19 | map = map.subMap(1,true,10,true); 20 | } 21 | 22 | 23 | @Override 24 | public void testPut(){ 25 | //this test is not run on submaps 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/volume/FileLockTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | import org.mapdb.* 4 | import org.junit.Assert.* 5 | import org.junit.Test 6 | 7 | class FileLockTest{ 8 | 9 | @Test fun lock_disable(){ 10 | val f = TT.tempFile() 11 | val c = FileChannelVol.FACTORY.makeVolume(f.path, false) 12 | val c2 = FileChannelVol.FACTORY.makeVolume(f.path, false, -1) 13 | f.delete() 14 | } 15 | 16 | 17 | @Test(timeout=10000L) 18 | fun lock_wait(){ 19 | val f = TT.tempFile() 20 | val c = FileChannelVol.FACTORY.makeVolume(f.path, false) 21 | TT.fork{ 22 | Thread.sleep(2000) 23 | c.close() 24 | } 25 | val c2 = FileChannelVol.FACTORY.makeVolume(f.path, false, Long.MAX_VALUE) 26 | c2.close() 27 | f.delete() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerBigInteger.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.math.BigInteger; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerBigInteger extends GroupSerializerObjectArray { 14 | @Override 15 | public void serialize(DataOutput2 out, BigInteger value) throws IOException { 16 | BYTE_ARRAY.serialize(out, value.toByteArray()); 17 | } 18 | 19 | @Override 20 | public BigInteger deserialize(DataInput2 in, int available) throws IOException { 21 | return new BigInteger(BYTE_ARRAY.deserialize(in, available)); 22 | } 23 | 24 | @Override 25 | public boolean isTrusted() { 26 | return true; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMap_ConcurrentSkipListSubMapTest_JSR166Test.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Parameterized 5 | import org.mapdb.jsr166Tests.ConcurrentSkipListSubMapTest 6 | import java.util.concurrent.ConcurrentNavigableMap 7 | 8 | @RunWith(Parameterized::class) 9 | class BTreeMap_ConcurrentSkipListSubMapTest_JSR166Test( 10 | val mapMaker:(generic:Boolean)-> ConcurrentNavigableMap 11 | ) : ConcurrentSkipListSubMapTest() 12 | { 13 | 14 | override fun emptyMap(): ConcurrentNavigableMap? { 15 | return mapMaker(false) 16 | } 17 | 18 | 19 | companion object { 20 | @Parameterized.Parameters 21 | @JvmStatic 22 | fun params(): Iterable { 23 | return BTreeMap_ConcurrentMap_GuavaTest.params() 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerByte.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerByte extends GroupSerializerObjectArray { 13 | @Override 14 | public void serialize(DataOutput2 out, Byte value) throws IOException { 15 | out.writeByte(value); 16 | } 17 | 18 | @Override 19 | public Byte deserialize(DataInput2 in, int available) throws IOException { 20 | return in.readByte(); 21 | } 22 | 23 | //TODO value array operations 24 | 25 | @Override 26 | public int fixedSize() { 27 | return 1; 28 | } 29 | 30 | @Override 31 | public boolean isTrusted() { 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerChar.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerChar extends GroupSerializerObjectArray { 13 | @Override 14 | public void serialize(DataOutput2 out, Character value) throws IOException { 15 | out.writeChar(value.charValue()); 16 | } 17 | 18 | @Override 19 | public Character deserialize(DataInput2 in, int available) throws IOException { 20 | return in.readChar(); 21 | } 22 | 23 | @Override 24 | public int fixedSize() { 25 | return 2; 26 | } 27 | 28 | @Override 29 | public boolean isTrusted() { 30 | return true; 31 | } 32 | 33 | //TODO value array 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerShort.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerShort extends GroupSerializerObjectArray { 13 | @Override 14 | public void serialize(DataOutput2 out, Short value) throws IOException { 15 | out.writeShort(value.shortValue()); 16 | } 17 | 18 | @Override 19 | public Short deserialize(DataInput2 in, int available) throws IOException { 20 | return in.readShort(); 21 | } 22 | 23 | //TODO value array operations 24 | 25 | @Override 26 | public int fixedSize() { 27 | return 2; 28 | } 29 | 30 | @Override 31 | public boolean isTrusted() { 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/HTreeMap_JSR166Test.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Parameterized 5 | import org.mapdb.jsr166Tests.ConcurrentHashMapTest 6 | import java.util.concurrent.ConcurrentMap 7 | 8 | @RunWith(Parameterized::class) 9 | class HTreeMap_JSR166Test( 10 | val mapMaker:(generic:Boolean)-> ConcurrentMap 11 | ) : ConcurrentHashMapTest() 12 | { 13 | 14 | override fun makeGenericMap(): ConcurrentMap? { 15 | return mapMaker(true) 16 | } 17 | 18 | override fun makeMap(): ConcurrentMap? { 19 | return mapMaker(false) as ConcurrentMap 20 | } 21 | 22 | companion object { 23 | @Parameterized.Parameters 24 | @JvmStatic 25 | fun params(): Iterable { 26 | return HTreeMap_GuavaTest.params() 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerRecidArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataIO; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerRecidArray extends SerializerLongArray{ 13 | 14 | @Override 15 | public void serialize(DataOutput2 out, long[] value) throws IOException { 16 | out.packInt(value.length); 17 | for (long recid : value) { 18 | DataIO.packRecid(out, recid); 19 | } 20 | } 21 | 22 | @Override 23 | public long[] deserialize(DataInput2 in, int available) throws IOException { 24 | int size = in.unpackInt(); 25 | long[] ret = new long[size]; 26 | for (int i = 0; i < size; i++) { 27 | ret[i] = DataIO.unpackRecid(in); 28 | } 29 | return ret; 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerStringIntern.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | import org.mapdb.Serializer; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerStringIntern extends GroupSerializerObjectArray { 14 | @Override 15 | public void serialize(DataOutput2 out, String value) throws IOException { 16 | out.writeUTF(value); 17 | } 18 | 19 | @Override 20 | public String deserialize(DataInput2 in, int available) throws IOException { 21 | return in.readUTF().intern(); 22 | } 23 | 24 | @Override 25 | public boolean isTrusted() { 26 | return true; 27 | } 28 | 29 | @Override 30 | public int hashCode(@NotNull String s, int seed) { 31 | return STRING.hashCode(s, seed); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerBigDecimal.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.math.BigDecimal; 9 | import java.math.BigInteger; 10 | 11 | /** 12 | * Created by jan on 2/28/16. 13 | */ 14 | public class SerializerBigDecimal extends GroupSerializerObjectArray { 15 | @Override 16 | public void serialize(DataOutput2 out, BigDecimal value) throws IOException { 17 | BYTE_ARRAY.serialize(out, value.unscaledValue().toByteArray()); 18 | out.packInt(value.scale()); 19 | } 20 | 21 | @Override 22 | public BigDecimal deserialize(DataInput2 in, int available) throws IOException { 23 | return new BigDecimal(new BigInteger( 24 | BYTE_ARRAY.deserialize(in, -1)), 25 | in.unpackInt()); 26 | } 27 | 28 | @Override 29 | public boolean isTrusted() { 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMapNavigableSubMapExclusiveTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import java.util.NavigableMap; 4 | 5 | public class BTreeMapNavigableSubMapExclusiveTest extends BTreeMapNavigable2Test{ 6 | 7 | public static class Outside extends BTreeMapNavigableSubMapExclusiveTest{ 8 | @Override protected NavigableMap newMap() { 9 | return DBMaker.memoryDB().make() 10 | .treeMap("map", Serializer.INTEGER, Serializer.STRING) 11 | //TODO enable once values outside nodes work 12 | //.valuesOutsideNodesEnable() 13 | .create(); 14 | } 15 | 16 | } 17 | 18 | @Override 19 | public void setUp() throws Exception { 20 | super.setUp(); 21 | map.put(-1,"-one"); 22 | map.put(0,"zero"); 23 | map.put(11,"eleven"); 24 | map.put(12,"twelve"); 25 | map = map.subMap(0,false,11,false); 26 | } 27 | 28 | 29 | @Override 30 | public void testPut(){ 31 | //this test is not run on submaps 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/UtilsTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | import org.mapdb.TT.assertFailsWith 6 | 7 | 8 | class UtilsTest{ 9 | 10 | 11 | @Test fun single_entry_lock(){ 12 | val lock = Utils.singleEntryLock() 13 | lock.lock() 14 | lock.unlock() 15 | 16 | lock.lock() 17 | assertFailsWith(IllegalMonitorStateException::class.java){ 18 | lock.lock() 19 | } 20 | lock.unlock() 21 | assertFailsWith(IllegalMonitorStateException::class.java){ 22 | lock.unlock() 23 | } 24 | } 25 | 26 | @Test fun single_entry_read_write_lock(){ 27 | val lock = Utils.SingleEntryReadWriteLock().writeLock() 28 | lock.lock() 29 | lock.unlock() 30 | 31 | lock.lock() 32 | assertFailsWith(IllegalMonitorStateException::class.java){ 33 | lock.lock() 34 | } 35 | lock.unlock() 36 | assertFailsWith(IllegalMonitorStateException::class.java){ 37 | lock.unlock() 38 | } 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMap_ConcurrentSkipListMapTest_JSR166Test.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Parameterized 5 | import org.mapdb.jsr166Tests.ConcurrentHashMapTest 6 | import org.mapdb.jsr166Tests.ConcurrentSkipListMapTest 7 | import java.util.concurrent.ConcurrentMap 8 | import java.util.concurrent.ConcurrentNavigableMap 9 | 10 | @RunWith(Parameterized::class) 11 | class BTreeMap_ConcurrentSkipListMapTest_JSR166Test( 12 | val mapMaker:(generic:Boolean?)-> ConcurrentNavigableMap 13 | ) : ConcurrentSkipListMapTest() 14 | { 15 | 16 | override fun emptyMap(): ConcurrentNavigableMap? { 17 | return mapMaker(false) 18 | } 19 | 20 | override fun emptyIntMap(): ConcurrentNavigableMap? { 21 | return mapMaker(null) as ConcurrentNavigableMap 22 | } 23 | 24 | companion object { 25 | @Parameterized.Parameters 26 | @JvmStatic 27 | fun params(): Iterable { 28 | return BTreeMap_ConcurrentMap_GuavaTest.params() 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/issues/Issue697.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.issues; 2 | 3 | import org.junit.Test; 4 | import org.mapdb.CC; 5 | import org.mapdb.Serializer; 6 | import org.mapdb.SortedTableMap; 7 | import org.mapdb.TT; 8 | import org.mapdb.volume.MappedFileVol; 9 | import org.mapdb.volume.Volume; 10 | 11 | import java.io.File; 12 | import java.util.Map; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | 16 | /** 17 | * Created by jan on 5/2/16. 18 | */ 19 | public class Issue697 { 20 | @Test 21 | public void test(){ 22 | 23 | SortedTableMap.Sink sink = SortedTableMap.create( 24 | CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false), 25 | Serializer.INTEGER, 26 | Serializer.STRING) 27 | .createFromSink(); 28 | 29 | for (int i = 0; i < 10; i++) 30 | { 31 | sink.put(i, "value" + i); 32 | } 33 | 34 | Map m = sink.create(); 35 | for (int i = 0; i < 10; i++) 36 | { 37 | assertEquals("value" + i, m.get(i)); 38 | } 39 | 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/DataOutput2Test.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.assertEquals; 6 | 7 | 8 | public class DataOutput2Test { 9 | 10 | //TODO more tests here for compability between DataIO.ByteArrayDataOutput and other DataInputs 11 | 12 | DataOutput2 out = new DataOutput2(); 13 | 14 | DataInput2.ByteArray in(){ 15 | return new DataInput2.ByteArray(out.buf); 16 | } 17 | 18 | @Test 19 | public void testWriteFloat() throws Exception { 20 | float f = 12.1239012093e-19F; 21 | out.writeFloat(f); 22 | DataInput2.ByteArray in = in(); 23 | assertEquals(Float.floatToIntBits(f),Float.floatToIntBits(in.readFloat())); 24 | assertEquals(4,in.pos); 25 | } 26 | 27 | @Test 28 | public void testWriteDouble() throws Exception { 29 | double f = 12.123933423523012093e-199; 30 | out.writeDouble(f); 31 | DataInput2.ByteArray in = in(); 32 | assertEquals(Double.doubleToLongBits(f),Double.doubleToLongBits(in.readDouble())); 33 | assertEquals(8,in.pos); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/volume/XXHashTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | import net.jpountz.xxhash.XXHashFactory 4 | import org.junit.Test 5 | import java.util.* 6 | import org.junit.Assert.assertEquals 7 | 8 | /** 9 | * Tests XXHashing 10 | */ 11 | class XXHashTest{ 12 | 13 | @Test fun stream_compatible(){ 14 | val b = ByteArray(1000) 15 | Random().nextBytes(b) 16 | val seed = 1L 17 | 18 | val s = XXHashFactory.safeInstance().newStreamingHash64(seed) 19 | val h = XXHashFactory.safeInstance().hash64() 20 | 21 | //general compatibility 22 | val totalHash = h.hash(b,0,b.size,seed); 23 | s.update(b, 0, b.size) 24 | assertEquals(totalHash, s.value) 25 | 26 | //split in middle 27 | s.reset() 28 | s.update(b, 0, 500) 29 | s.update(b, 500, b.size-500) 30 | assertEquals(totalHash, s.value) 31 | 32 | //update 10 bytes at a time 33 | s.reset() 34 | for(offset in 0 until b.size step 10){ 35 | s.update(b, offset, 10) 36 | } 37 | assertEquals(totalHash, s.value) 38 | 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerDouble.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerDouble extends SerializerEightByte { 13 | @Override 14 | protected Double unpack(long l) { 15 | return new Double(Double.longBitsToDouble(l)); 16 | } 17 | 18 | @Override 19 | protected long pack(Double l) { 20 | return Double.doubleToLongBits(l); 21 | } 22 | 23 | @Override 24 | public int valueArraySearch(Object keys, Double key) { 25 | //TODO PERF this can be optimized, but must take care of NaN 26 | return Arrays.binarySearch(valueArrayToArray(keys), key); 27 | } 28 | 29 | @Override 30 | public void serialize(DataOutput2 out, Double value) throws IOException { 31 | out.writeDouble(value); 32 | } 33 | 34 | @Override 35 | public Double deserialize(DataInput2 in, int available) throws IOException { 36 | return new Double(in.readDouble()); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerFloat.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerFloat extends SerializerFourByte { 13 | 14 | @Override 15 | protected Float unpack(int l) { 16 | return new Float(Float.intBitsToFloat(l)); 17 | } 18 | 19 | @Override 20 | protected int pack(Float l) { 21 | return Float.floatToIntBits(l); 22 | } 23 | 24 | 25 | @Override 26 | public void serialize(DataOutput2 out, Float value) throws IOException { 27 | out.writeFloat(value); 28 | } 29 | 30 | @Override 31 | public Float deserialize(DataInput2 in, int available) throws IOException { 32 | return new Float(in.readFloat()); 33 | } 34 | 35 | 36 | @Override 37 | public int valueArraySearch(Object keys, Float key) { 38 | //TODO PERF this can be optimized, but must take care of NaN 39 | return Arrays.binarySearch(valueArrayToArray(keys), key); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerDate.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | import java.util.Date; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerDate extends SerializerEightByte { 14 | 15 | @Override 16 | public void serialize(DataOutput2 out, Date value) throws IOException { 17 | out.writeLong(value.getTime()); 18 | } 19 | 20 | @Override 21 | public Date deserialize(DataInput2 in, int available) throws IOException { 22 | return new Date(in.readLong()); 23 | } 24 | 25 | @Override 26 | protected Date unpack(long l) { 27 | return new Date(l); 28 | } 29 | 30 | @Override 31 | protected long pack(Date l) { 32 | return l.getTime(); 33 | } 34 | 35 | @Override 36 | final public int valueArraySearch(Object keys, Date key) { 37 | //TODO valueArraySearch versus comparator test 38 | long time = key.getTime(); 39 | return Arrays.binarySearch((long[])keys, time); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/JUnitRunListener.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.runner.Description 4 | import org.junit.runner.notification.RunListener 5 | import java.util.concurrent.ConcurrentHashMap 6 | import java.util.concurrent.TimeUnit 7 | 8 | /** 9 | * Prints currently running tests into console every 5 minutes. 10 | * Is used to monitor integration tests which may run for several hours. 11 | */ 12 | class JUnitRunListener: RunListener() { 13 | 14 | val runningTests = ConcurrentHashMap() 15 | val period = 5*60*1000L 16 | 17 | val exec = TT.executor() 18 | init{ 19 | exec.scheduleAtFixedRate({ 20 | println("Running tests: ") 21 | runningTests.forEach {name, time -> 22 | println(" $name - " + (System.currentTimeMillis()-time)/(60*1000)) 23 | } 24 | }, period, period, TimeUnit.MILLISECONDS) 25 | } 26 | 27 | 28 | 29 | override fun testStarted(description: Description?) { 30 | runningTests.put(description!!.displayName!!, System.currentTimeMillis()) 31 | } 32 | 33 | override fun testFinished(description: Description?) { 34 | runningTests.remove(description!!.displayName) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMapParTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Test 4 | 5 | import java.util.concurrent.Callable 6 | import java.util.concurrent.ConcurrentMap 7 | import java.util.concurrent.atomic.AtomicLong 8 | 9 | import org.junit.Assert.assertEquals 10 | 11 | class BTreeMapParTest { 12 | 13 | 14 | internal var scale = TT.testScale() 15 | internal val threadNum = 6 * scale 16 | internal val max = 1e6.toInt() * scale 17 | 18 | @Test 19 | @Throws(InterruptedException::class) 20 | fun parInsert() { 21 | if (scale == 0) 22 | return 23 | 24 | 25 | val m = DBMaker.memoryDB().make().treeMap("test").valueSerializer(Serializer.LONG).keySerializer(Serializer.LONG).make() 26 | 27 | val t = System.currentTimeMillis() 28 | val counter = AtomicLong() 29 | 30 | TT.fork(threadNum, {core-> 31 | var n: Long = core.toLong() 32 | while (n < max) { 33 | m.put(n, n) 34 | n += threadNum.toLong() 35 | } 36 | }) 37 | 38 | // System.out.printf(" Threads %d, time %,d\n",threadNum,System.currentTimeMillis()-t); 39 | 40 | 41 | assertEquals(max.toLong(), m.size.toLong()) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/volume/FileCrashTestr.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | import org.mapdb.crash.CrashJVM 6 | import org.mapdb.TT 7 | import java.io.File 8 | 9 | /** 10 | * Created by jan on 3/10/16. 11 | */ 12 | class FileCrashTestr: CrashJVM(){ 13 | 14 | 15 | override fun verifySeed(startSeed: Long, endSeed: Long, params:String): Long { 16 | val seed = endSeed 17 | assertTrue(File(getTestDir(), "" + seed).exists()) 18 | val f = File(getTestDir(), "/" + seed) 19 | assertTrue(f.exists()) 20 | 21 | return Math.max(startSeed,endSeed)+1; 22 | } 23 | 24 | override fun doInJVM(startSeed: Long, params:String) { 25 | var seed = startSeed; 26 | 27 | while(true){ 28 | seed++ 29 | startSeed(seed) 30 | 31 | val f = File(getTestDir(), "/" + seed) 32 | f.createNewFile() 33 | commitSeed(seed) 34 | } 35 | } 36 | 37 | @Test fun test(){ 38 | val runtime = 4000L + TT.testScale()*60*1000; 39 | val start = System.currentTimeMillis() 40 | Companion.run(this, time=runtime, killDelay = 200) 41 | assertTrue(System.currentTimeMillis() - start >= runtime) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerStringOrigHash.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.mapdb.DataIO; 5 | import org.mapdb.DataInput2; 6 | import org.mapdb.DataOutput2; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerStringOrigHash extends SerializerString { 14 | @Override 15 | public void serialize(DataOutput2 out, String value) throws IOException { 16 | out.writeUTF(value); 17 | } 18 | 19 | @Override 20 | public String deserialize(DataInput2 in, int available) throws IOException { 21 | return in.readUTF(); 22 | } 23 | 24 | @Override 25 | public boolean isTrusted() { 26 | return true; 27 | } 28 | 29 | 30 | // @Override 31 | // public BTreeKeySerializer getBTreeKeySerializer(Comparator comparator) { 32 | // if(comparator!=null && comparator!=Fun.COMPARATOR) { 33 | // return super.getBTreeKeySerializer(comparator); 34 | // } 35 | // return BTreeKeySerializer.STRING; 36 | // } 37 | 38 | 39 | @Override 40 | public int hashCode(@NotNull String s, int seed) { 41 | return DataIO.intHash(s.hashCode() + seed); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerStringNoSize.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.nio.charset.Charset; 9 | import java.util.Comparator; 10 | 11 | /** 12 | * Created by jan on 2/28/16. 13 | */ 14 | public class SerializerStringNoSize implements Serializer { 15 | 16 | private final Charset UTF8_CHARSET = Charset.forName("UTF8"); 17 | 18 | @Override 19 | public void serialize(DataOutput2 out, String value) throws IOException { 20 | final byte[] bytes = value.getBytes(UTF8_CHARSET); 21 | out.write(bytes); 22 | } 23 | 24 | 25 | @Override 26 | public String deserialize(DataInput2 in, int available) throws IOException { 27 | if (available == -1) throw new IllegalArgumentException("STRING_NOSIZE does not work with collections."); 28 | byte[] bytes = new byte[available]; 29 | in.readFully(bytes); 30 | return new String(bytes, UTF8_CHARSET); 31 | } 32 | 33 | @Override 34 | public boolean isTrusted() { 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean needsAvailableSizeHint() { 40 | return true; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/HTreeMapConcTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Test 4 | import org.junit.Assert.* 5 | import org.junit.runner.RunWith 6 | import org.junit.runners.Parameterized 7 | import java.io.IOException 8 | import java.util.concurrent.ConcurrentMap 9 | 10 | /** 11 | * Concurrent tests for HTreeMap 12 | */ 13 | @RunWith(Parameterized::class) 14 | class HTreeMapConcTest(val mapMaker:(generic:Boolean)-> ConcurrentMap) { 15 | 16 | companion object { 17 | @Parameterized.Parameters 18 | @JvmStatic 19 | fun params(): Iterable { 20 | return HTreeMap_GuavaTest.params() 21 | } 22 | } 23 | @Test fun basicTest(){ 24 | val map = mapMaker(false); 25 | var max = 10000; 26 | if(map is HTreeMap && map.keySerializer == Serializer.INTEGER) 27 | max += 1e6.toInt()*TT.testScale() 28 | val threadCount = 16 29 | 30 | TT.fork(threadCount){i-> 31 | for(key in i until max step threadCount){ 32 | map.put(key, "aa"+key) 33 | } 34 | } 35 | if(map is HTreeMap) 36 | map.stores.toSet().forEach{it.verify()} 37 | 38 | assertEquals(max, map.size) 39 | for(key in 0 until max){ 40 | assertEquals("aa"+key, map[key]) 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/Store.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | 4 | /** 5 | * Stores records 6 | */ 7 | interface StoreImmutable{ 8 | 9 | fun get(recid: Long, serializer: Serializer): R? 10 | 11 | fun getAllRecids(): LongIterator 12 | } 13 | 14 | /** 15 | * Stores records, mutable version 16 | */ 17 | interface Store: StoreImmutable, Verifiable, 18 | ConcurrencyAware { //TODO put assertions for underlying collections and Volumes 19 | 20 | fun preallocate():Long; 21 | 22 | fun put(record: R?, serializer: Serializer):Long 23 | fun update(recid: Long, record: R?, serializer: Serializer) 24 | fun compareAndSwap(recid: Long, 25 | expectedOldRecord: R?, 26 | newRecord: R?, 27 | serializer: Serializer 28 | ): Boolean 29 | 30 | fun delete(recid: Long, serializer: Serializer) 31 | 32 | fun commit(); 33 | fun compact() 34 | 35 | fun close(); 36 | val isClosed:Boolean; 37 | 38 | override fun verify() 39 | 40 | val isReadOnly: Boolean 41 | } 42 | 43 | /** 44 | * Stores records, transactional version 45 | */ 46 | interface StoreTx:Store{ 47 | fun rollback(); 48 | } 49 | 50 | interface StoreBinary:Store{ 51 | 52 | fun getBinaryLong(recid:Long, f:StoreBinaryGetLong):Long 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMap_HashMap_JSR166Test.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Parameterized 5 | import org.mapdb.jsr166Tests.ConcurrentHashMapTest 6 | import java.util.concurrent.ConcurrentMap 7 | 8 | @RunWith(Parameterized::class) 9 | class BTreeMap_HashMap_JSR166Test( 10 | val mapMaker:(generic:Boolean)-> ConcurrentMap 11 | ) : ConcurrentHashMapTest() 12 | { 13 | 14 | override fun makeGenericMap(): ConcurrentMap? { 15 | return mapMaker(true) 16 | } 17 | 18 | override fun makeMap(): ConcurrentMap? { 19 | return mapMaker(false) as ConcurrentMap 20 | } 21 | 22 | companion object { 23 | @Parameterized.Parameters 24 | @JvmStatic 25 | fun params(): Iterable { 26 | return BTreeMap_ConcurrentMap_GuavaTest.params() 27 | } 28 | } 29 | 30 | 31 | override fun testGenericComparable() { 32 | //ignored test, must be comparable 33 | } 34 | 35 | override fun testGenericComparable2() { 36 | //ignored test, must be comparable 37 | } 38 | 39 | override fun testMixedComparable() { 40 | //ignored test, must be comparable 41 | } 42 | 43 | override fun testComparableFamily() { 44 | //ignored test, must be comparable 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/jsr166Tests/CollectionTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.jsr166Tests;/* 2 | * Written by Doug Lea and Martin Buchholz with assistance from 3 | * members of JCP JSR-166 Expert Group and released to the public 4 | * domain, as explained at 5 | * http://creativecommons.org/publicdomain/zero/1.0/ 6 | */ 7 | 8 | import junit.framework.Test; 9 | 10 | /** 11 | * Contains tests applicable to all Collection implementations. 12 | */ 13 | public abstract class CollectionTest extends JSR166TestCase { 14 | final CollectionImplementation impl; 15 | 16 | /** Tests are parameterized by a Collection implementation. */ 17 | CollectionTest(CollectionImplementation impl, String methodName) { 18 | super(methodName); 19 | this.impl = impl; 20 | } 21 | 22 | public static Test testSuite(CollectionImplementation impl) { 23 | return newTestSuite 24 | (parameterizedTestSuite(CollectionTest.class, 25 | CollectionImplementation.class, 26 | impl), 27 | jdk8ParameterizedTestSuite(CollectionTest.class, 28 | CollectionImplementation.class, 29 | impl)); 30 | } 31 | 32 | /** A test of the CollectionImplementation implementation ! */ 33 | public void testEmptyMeansEmpty() { 34 | assertTrue(impl.emptyCollection().isEmpty()); 35 | assertEquals(0, impl.emptyCollection().size()); 36 | } 37 | 38 | // public void testCollectionDebugFail() { fail(); } 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/MapExtraTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Test 4 | import org.junit.Assert.* 5 | import java.util.* 6 | 7 | abstract class MapExtraTest{ 8 | 9 | abstract fun makeMap(): MapExtra 10 | 11 | val map = makeMap() 12 | 13 | 14 | @Test fun forEach(){ 15 | for(i in 1 ..100) 16 | map.put(i, "aa"+i) 17 | 18 | val ref = HashMap() 19 | map.forEach { key, value -> 20 | ref.put(key,value) 21 | } 22 | assertEquals(100, ref.size) 23 | for(i in 1 ..100) 24 | assertEquals("aa"+i, ref[i]) 25 | } 26 | 27 | 28 | @Test fun forEachKey(){ 29 | for(i in 1 ..100) 30 | map.put(i, "aa"+i) 31 | 32 | val ref = ArrayList() 33 | map.forEachKey { key-> 34 | ref.add(key) 35 | } 36 | assertEquals(100, ref.size) 37 | for(i in 1 ..100) 38 | assertTrue(ref.contains(i)) 39 | } 40 | 41 | @Test fun forEachValue(){ 42 | for(i in 1 ..100) 43 | map.put(i, "aa"+i) 44 | 45 | val ref = ArrayList() 46 | map.forEachValue { value-> 47 | ref.add(value) 48 | } 49 | assertEquals(100, ref.size) 50 | for(i in 1 ..100) 51 | assertTrue(ref.contains("aa"+i)) 52 | } 53 | 54 | class HTreeMapExtraTest:MapExtraTest(){ 55 | override fun makeMap(): MapExtra = HTreeMap.make( 56 | keySerializer = Serializer.INTEGER, valueSerializer = Serializer.STRING) 57 | 58 | } 59 | 60 | } 61 | 62 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/volume/VolumeFactory.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.jetbrains.annotations.Nullable; 5 | import org.mapdb.CC; 6 | 7 | /** 8 | * Created by jan on 2/29/16. 9 | */ 10 | public abstract class VolumeFactory { 11 | public abstract Volume makeVolume(String file, boolean readOnly, long fileLockWait, 12 | int sliceShift, long initSize, boolean fixedSize); 13 | 14 | public Volume makeVolume(String file, boolean readOnly) { 15 | return makeVolume(file, readOnly, 0L); 16 | } 17 | 18 | 19 | public Volume makeVolume(String file, boolean readOnly, long fileLockWait) { 20 | return makeVolume(file, readOnly, fileLockWait, CC.PAGE_SHIFT, 0, false); 21 | } 22 | 23 | @NotNull 24 | abstract public boolean exists(@Nullable String file); 25 | 26 | @NotNull 27 | public static VolumeFactory wrap(@NotNull final Volume volume, final boolean exists) { 28 | return new VolumeFactory() { 29 | @Override 30 | public Volume makeVolume(String file, boolean readOnly, long fileLockWait, int sliceShift, long initSize, boolean fixedSize) { 31 | return volume; 32 | } 33 | 34 | @NotNull 35 | @Override 36 | public boolean exists(@Nullable String file) { 37 | return exists; 38 | } 39 | 40 | @Override 41 | public boolean handlesReadonly() { 42 | return false; 43 | } 44 | }; 45 | } 46 | 47 | 48 | public abstract boolean handlesReadonly(); 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/crash/UnplugFileOutputStreamCrash.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.crash 2 | 3 | import org.mapdb.* 4 | import java.io.DataInputStream 5 | import java.io.File 6 | import java.io.FileInputStream 7 | import java.io.FileOutputStream 8 | import java.nio.file.Paths 9 | 10 | /** 11 | * Tests crash resistance by manually unplugging the drive. 12 | * 13 | */ 14 | 15 | fun waitUntilAvailable(file:File){ 16 | if(file.exists().not()) 17 | println("File not available, waiting until it exist again.") 18 | while(file.exists().not()) 19 | Thread.sleep(100) 20 | } 21 | 22 | fun main(args : Array) { 23 | // local directory, this is permanent storage 24 | val d = TT.tempDir() 25 | // file on storage which can be unpluged 26 | val file = File(args[0]) 27 | waitUntilAvailable(file.parentFile) 28 | file.delete() 29 | file.createNewFile() 30 | var out = FileOutputStream(file) 31 | val b = ByteArray(8) 32 | 33 | var a = 0L 34 | while(true){ 35 | a++ 36 | if(file.exists().not()){ 37 | break 38 | } 39 | try { 40 | File(d, "$a").createNewFile() 41 | DataIO.putLong(b, 0, 8) 42 | out.write(b) 43 | out.flush() 44 | }catch(e:Exception){ 45 | 46 | } 47 | } 48 | 49 | println("Storage gone, progress is $a"); 50 | waitUntilAvailable(file) 51 | 52 | //replay file 53 | val ins = DataInputStream(FileInputStream(file)) 54 | try{ 55 | while(true){ 56 | a = ins.readLong() 57 | } 58 | }catch(e:Exception){ 59 | } 60 | println("Replayed $a") 61 | file.delete() 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerInteger.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | import java.util.Comparator; 9 | 10 | public class SerializerInteger extends SerializerFourByte { 11 | 12 | 13 | @Override 14 | public void serialize(DataOutput2 out, Integer value) throws IOException { 15 | out.writeInt(value); 16 | } 17 | 18 | @Override 19 | public Integer deserialize(DataInput2 in, int available) throws IOException { 20 | return new Integer(in.readInt()); 21 | } 22 | @Override 23 | protected Integer unpack(int l) { 24 | return new Integer(l); 25 | } 26 | 27 | @Override 28 | protected int pack(Integer l) { 29 | return l; 30 | } 31 | 32 | @Override 33 | public int valueArraySearch(Object keys, Integer key) { 34 | return Arrays.binarySearch((int[]) keys, key); 35 | } 36 | 37 | 38 | @Override 39 | public int valueArrayBinarySearch(Integer key, DataInput2 input, int keysLen, Comparator comparator) throws IOException { 40 | if (comparator != this) 41 | return super.valueArrayBinarySearch(key, input, keysLen, comparator); 42 | final int key2 = key; 43 | for (int pos = 0; pos < keysLen; pos++) { 44 | int from = input.readInt(); 45 | 46 | if (key2 <= from) { 47 | input.skipBytes((keysLen-pos-1)*4); 48 | return (key2 == from) ? pos : -(pos + 1); 49 | } 50 | } 51 | 52 | //not found 53 | return -(keysLen + 1); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerStringAscii.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | import org.mapdb.Serializer; 7 | 8 | import java.io.IOException; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerStringAscii extends GroupSerializerObjectArray { 14 | @Override 15 | public void serialize(DataOutput2 out, String value) throws IOException { 16 | int size = value.length(); 17 | out.packInt(size); 18 | for (int i = 0; i < size; i++) { 19 | out.write(value.charAt(i)); 20 | } 21 | } 22 | 23 | @Override 24 | public String deserialize(DataInput2 in, int available) throws IOException { 25 | int size = in.unpackInt(); 26 | StringBuilder result = new StringBuilder(size); 27 | for (int i = 0; i < size; i++) { 28 | result.append((char) in.readUnsignedByte()); 29 | } 30 | return result.toString(); 31 | } 32 | 33 | @Override 34 | public boolean isTrusted() { 35 | return true; 36 | } 37 | 38 | @Override 39 | public int hashCode(@NotNull String s, int seed) { 40 | return STRING.hashCode(s, seed); 41 | } 42 | 43 | // @Override 44 | // public BTreeKeySerializer getBTreeKeySerializer(Comparator comparator) { 45 | // if(comparator!=null && comparator!=Fun.COMPARATOR) { 46 | // return super.getBTreeKeySerializer(comparator); 47 | // } 48 | // return BTreeKeySerializer.STRING; //PERF ascii specific serializer? 49 | // } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerByteArrayNoSize.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | 11 | /** 12 | * Created by jan on 2/28/16. 13 | */ 14 | public class SerializerByteArrayNoSize implements Serializer { 15 | 16 | @Override 17 | public void serialize(DataOutput2 out, byte[] value) throws IOException { 18 | out.write(value); 19 | } 20 | 21 | @Override 22 | public byte[] deserialize(DataInput2 in, int available) throws IOException { 23 | byte[] ret = new byte[available]; 24 | in.readFully(ret); 25 | return ret; 26 | } 27 | 28 | @Override 29 | public boolean isTrusted() { 30 | return true; 31 | } 32 | 33 | @Override 34 | public boolean equals(byte[] a1, byte[] a2) { 35 | return Arrays.equals(a1, a2); 36 | } 37 | 38 | @Override 39 | public int hashCode(byte[] bytes, int seed) { 40 | return BYTE_ARRAY.hashCode(bytes, seed); 41 | } 42 | 43 | @Override 44 | public boolean needsAvailableSizeHint() { 45 | return true; 46 | } 47 | 48 | @Override 49 | public int compare(byte[] o1, byte[] o2) { 50 | if (o1 == o2) return 0; 51 | final int len = Math.min(o1.length, o2.length); 52 | for (int i = 0; i < len; i++) { 53 | int b1 = o1[i] & 0xFF; 54 | int b2 = o2[i] & 0xFF; 55 | if (b1 != b2) 56 | return b1 - b2; 57 | } 58 | return o1.length - o2.length; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerClass.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DBException; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Serialier for class. It takes a class loader as constructor param, by default it uses 11 | * {@code Thread.currentThread().getContextClassLoader()} 12 | */ 13 | public class SerializerClass extends GroupSerializerObjectArray> { 14 | 15 | protected final ClassLoader classLoader; 16 | 17 | public SerializerClass(ClassLoader classLoader) { 18 | this.classLoader = classLoader; 19 | } 20 | 21 | public SerializerClass(){ 22 | this(Thread.currentThread().getContextClassLoader()); 23 | } 24 | 25 | @Override 26 | public void serialize(DataOutput2 out, Class value) throws IOException { 27 | out.writeUTF(value.getName()); 28 | } 29 | 30 | @Override 31 | public Class deserialize(DataInput2 in, int available) throws IOException { 32 | try { 33 | return classLoader.loadClass(in.readUTF()); 34 | } catch (ClassNotFoundException e) { 35 | throw new DBException.SerializationError(e); 36 | } 37 | } 38 | 39 | @Override 40 | public boolean isTrusted() { 41 | return true; 42 | } 43 | 44 | @Override 45 | public boolean equals(Class a1, Class a2) { 46 | return a1 == a2 || (a1.toString().equals(a2.toString())); 47 | } 48 | 49 | @Override 50 | public int hashCode(Class aClass, int seed) { 51 | //class does not override identity hash code 52 | return aClass.toString().hashCode(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerLong.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | import java.util.Comparator; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerLong extends SerializerEightByte { 14 | 15 | @Override 16 | public void serialize(DataOutput2 out, Long value) throws IOException { 17 | out.writeLong(value); 18 | } 19 | 20 | @Override 21 | public Long deserialize(DataInput2 in, int available) throws IOException { 22 | return new Long(in.readLong()); 23 | } 24 | 25 | 26 | @Override 27 | protected Long unpack(long l) { 28 | return new Long(l); 29 | } 30 | 31 | @Override 32 | protected long pack(Long l) { 33 | return l.longValue(); 34 | } 35 | 36 | @Override 37 | public int valueArraySearch(Object keys, Long key) { 38 | return Arrays.binarySearch((long[])keys, key); 39 | } 40 | 41 | 42 | @Override 43 | public int valueArrayBinarySearch(Long key, DataInput2 input, int keysLen, Comparator comparator) throws IOException { 44 | if (comparator != this) 45 | return super.valueArrayBinarySearch(key, input, keysLen, comparator); 46 | long key2 = key; 47 | for (int pos = 0; pos < keysLen; pos++) { 48 | long from = input.readLong(); 49 | 50 | if (key2 <= from) { 51 | input.skipBytes((keysLen-pos-1)*8); 52 | return (key2 == from) ? pos : -(pos + 1); 53 | } 54 | } 55 | 56 | //not found 57 | return -(keysLen + 1); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /logger.properties: -------------------------------------------------------------------------------- 1 | # 2 | # An example of logger config file used for debugging. 3 | # 4 | # MapDB is compiled without logging messages by default. 5 | # Make sure you enable them in CC.java 6 | # 7 | # You must enable this file by passing system property before JVM starts 8 | # 9 | # >java -Djava.util.logging.config.file=logger.properties 10 | # 11 | 12 | handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler 13 | 14 | # Default global logging level. 15 | # Loggers and Handlers may override this level 16 | .level=FINEST 17 | 18 | # Loggers 19 | # ------------------------------------------ 20 | # Loggers are usually attached to packages. 21 | # Here, the level for each package is specified. 22 | # The global level is used by default, so levels 23 | # specified here simply act as an override. 24 | org.mapdb.level=ALL 25 | 26 | #some other filtering options 27 | myapp.business.level=CONFIG 28 | myapp.data.level=SEVERE 29 | 30 | # Handlers 31 | java.util.logging.ConsoleHandler.level=ALL 32 | java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter 33 | 34 | # --- FileHandler --- 35 | java.util.logging.FileHandler.level=ALL 36 | 37 | # Naming style for the output file: 38 | # (The output file is placed in the directory 39 | # defined by the "user.home" System property.) 40 | java.util.logging.FileHandler.pattern=%h/java%u.log 41 | 42 | # Limiting size of output file in bytes: 43 | java.util.logging.FileHandler.limit=500000 44 | 45 | # Number of output files to cycle through, by appending an 46 | # integer to the base file name: 47 | java.util.logging.FileHandler.count=1 48 | 49 | # Style of output (Simple or XML): 50 | java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter -------------------------------------------------------------------------------- /src/test/java/org/mapdb/issues/IssueFromDatumbox.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.issues; 2 | 3 | import org.junit.Test; 4 | import org.mapdb.Atomic; 5 | import org.mapdb.DB; 6 | import org.mapdb.DBMaker; 7 | import org.mapdb.TT; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | import java.io.Serializable; 12 | 13 | import static org.junit.Assert.assertEquals; 14 | 15 | public class IssueFromDatumbox { 16 | 17 | public static class SomeOtherClass { 18 | 19 | } 20 | 21 | public static class SomeObject implements Serializable { 22 | int someValue = 1; 23 | Class someClass; 24 | } 25 | 26 | @Test public void main() throws IOException { 27 | 28 | //Pick one of the following lines to get a different error 29 | String f = TT.tempFile().getPath(); //fails every time - throws java.lang.NullPointerException 30 | //File f = File.createTempFile("mapdb","db"); //fails every time - throws java.io.EOFException exception 31 | //String f = "/tmp/constantName"; //fails only in the first execution but NOT in any subsequent execution - throws java.lang.NullPointerException 32 | 33 | SomeObject x = new SomeObject(); 34 | x.someValue = 10; 35 | x.someClass = SomeOtherClass.class; 36 | 37 | DB db = DBMaker.fileDB(f).make(); 38 | Atomic.Var atomicVar = db.atomicVar("test").createOrOpen(); 39 | 40 | atomicVar.set(x); 41 | db.close(); 42 | 43 | db = DBMaker.fileDB(f).make(); 44 | 45 | atomicVar = db.atomicVar("test").createOrOpen(); 46 | x = (SomeObject) atomicVar.get(); 47 | assertEquals(10, x.someValue); 48 | assertEquals(SomeOtherClass.class, x.someClass); 49 | 50 | db.close(); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BTreeMap_SortedMap_GuavaTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Parameterized 5 | import org.mapdb.guavaTests.SortedMapInterfaceTest 6 | import java.util.* 7 | import java.util.concurrent.ConcurrentMap 8 | 9 | /** 10 | * Created by jan on 1/29/16. 11 | */ 12 | @RunWith(Parameterized::class) 13 | class BTreeMap_SortedMap_GuavaTest(val mapMaker:(generic:Boolean)-> ConcurrentMap) : 14 | SortedMapInterfaceTest( 15 | false, // boolean allowsNullKeys, 16 | false, // boolean allowsNullValues, 17 | true, // boolean supportsPut, 18 | true, // boolean supportsRemove, 19 | true // boolean supportsClear, 20 | ) { 21 | 22 | companion object { 23 | @Parameterized.Parameters 24 | @JvmStatic 25 | fun params(): Iterable { 26 | return BTreeMap_ConcurrentMap_GuavaTest.params() 27 | } 28 | } 29 | 30 | 31 | override fun getKeyNotInPopulatedMap(): Int = -10 32 | 33 | override fun getValueNotInPopulatedMap(): String = "-120" 34 | 35 | open override fun makeEmptyMap(): NavigableMap { 36 | return mapMaker(false) as NavigableMap 37 | } 38 | 39 | override fun makePopulatedMap(): NavigableMap? { 40 | val ret = makeEmptyMap() 41 | for(i in 0 until 30) { 42 | ret.put(i, "aa"+i) 43 | } 44 | return ret; 45 | } 46 | 47 | 48 | override fun supportsValuesHashCode(map: MutableMap?): Boolean { 49 | // keySerializer returns wrong hash on purpose for this test, so pass it 50 | return false; 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/volume/ByteBufferMemoryVolSingle.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume; 2 | 3 | import java.io.File; 4 | import java.nio.ByteBuffer; 5 | import java.nio.MappedByteBuffer; 6 | 7 | /** 8 | * Created by jan on 3/13/16. 9 | */ 10 | public final class ByteBufferMemoryVolSingle extends ByteBufferVolSingle { 11 | 12 | protected final boolean useDirectBuffer; 13 | 14 | @Override 15 | public String toString() { 16 | return super.toString() + ",direct=" + useDirectBuffer; 17 | } 18 | 19 | public ByteBufferMemoryVolSingle(final boolean useDirectBuffer, final long maxSize, boolean cleanerHackEnabled) { 20 | super(false, maxSize, cleanerHackEnabled); 21 | this.useDirectBuffer = useDirectBuffer; 22 | this.buffer = useDirectBuffer ? 23 | ByteBuffer.allocateDirect((int) maxSize) : 24 | ByteBuffer.allocate((int) maxSize); 25 | } 26 | 27 | @Override 28 | public void truncate(long size) { 29 | //TODO truncate 30 | } 31 | 32 | @Override 33 | synchronized public void close() { 34 | if (closed) 35 | return; 36 | 37 | if (cleanerHackEnabled && buffer instanceof MappedByteBuffer) { 38 | ByteBufferVol.unmap((MappedByteBuffer) buffer); 39 | } 40 | buffer = null; 41 | closed = true; 42 | } 43 | 44 | @Override 45 | public void sync() { 46 | } 47 | 48 | @Override 49 | public long length() { 50 | return maxSize; 51 | } 52 | 53 | @Override 54 | public boolean isReadOnly() { 55 | return false; 56 | } 57 | 58 | @Override 59 | public File getFile() { 60 | return null; 61 | } 62 | 63 | @Override 64 | public boolean getFileLocked() { 65 | return false; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/issues/Issue418Test.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.issues; 2 | 3 | import org.junit.Test; 4 | import org.mapdb.*; 5 | 6 | import java.io.File; 7 | import java.util.Set; 8 | 9 | import static org.junit.Assert.assertTrue; 10 | 11 | public class Issue418Test { 12 | 13 | @Test 14 | public void test(){ 15 | final File tmp = TT.tempFile(); 16 | 17 | long[] expireHeads = null; 18 | long[] expireTails = null; 19 | for (int o = 0; o < 2; o++) { 20 | final DB db = DBMaker.fileDB(tmp).make(); 21 | final HTreeMap map = db.hashMap("foo").expireMaxSize(100).createOrOpen(); 22 | // TODO reenable following assertion? 23 | // if(expireHeads!=null) 24 | // assertTrue(Serializer.LONG_ARRAY.equals(expireHeads, map.expireHeads)); 25 | // else 26 | // expireHeads = map.expireHeads; 27 | // 28 | // if(expireTails!=null) 29 | // assertTrue(Serializer.LONG_ARRAY.equals(expireTails, map.expireTails)); 30 | // else 31 | // expireTails = map.expireTails; 32 | // 33 | 34 | 35 | for (int i = 0; i < TT.testScale()*10000; i++) 36 | map.put("foo" + i, "bar" + i); 37 | 38 | 39 | db.commit(); 40 | db.close(); 41 | } 42 | } 43 | 44 | 45 | @Test 46 | public void test_set(){ 47 | final File tmp = TT.tempFile(); 48 | 49 | for (int o = 0; o < 2; o++) { 50 | final DB db = DBMaker.fileDB(tmp).make(); 51 | final Set map = db.hashSet("foo").expireMaxSize(100).createOrOpen(); 52 | 53 | for (int i = 0; i < TT.testScale()*10000; i++) 54 | map.add("foo" + i); 55 | 56 | db.commit(); 57 | db.close(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/StoreReadOnlyWrapper.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | /** 4 | * Wraps Store and throws `UnsupportedOperationException("Read-only")` on operations which would modify it 5 | */ 6 | class StoreReadOnlyWrapper(protected val store:Store):Store{ 7 | 8 | override fun close() { 9 | store.close() 10 | } 11 | 12 | override fun commit() { 13 | throw UnsupportedOperationException("Read-only") 14 | } 15 | 16 | override fun compact() { 17 | throw UnsupportedOperationException("Read-only") 18 | } 19 | 20 | override fun compareAndSwap(recid: Long, expectedOldRecord: R?, newRecord: R?, serializer: Serializer): Boolean { 21 | throw UnsupportedOperationException("Read-only") 22 | } 23 | 24 | override fun delete(recid: Long, serializer: Serializer) { 25 | throw UnsupportedOperationException("Read-only") 26 | } 27 | 28 | override val isClosed: Boolean 29 | get() = store.isClosed 30 | 31 | override val isThreadSafe: Boolean 32 | get() = store.isThreadSafe 33 | 34 | override val isReadOnly = true 35 | 36 | override fun preallocate(): Long { 37 | throw UnsupportedOperationException("Read-only") 38 | } 39 | 40 | override fun put(record: R?, serializer: Serializer): Long { 41 | throw UnsupportedOperationException("Read-only") 42 | } 43 | 44 | override fun update(recid: Long, record: R?, serializer: Serializer) { 45 | throw UnsupportedOperationException("Read-only") 46 | } 47 | 48 | override fun verify() { 49 | store.verify() 50 | } 51 | 52 | override fun get(recid: Long, serializer: Serializer): R? { 53 | return store.get(recid, serializer) 54 | } 55 | 56 | override fun getAllRecids(): LongIterator { 57 | return store.getAllRecids() 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerFloatArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerFloatArray extends GroupSerializerObjectArray { 14 | @Override 15 | public void serialize(DataOutput2 out, float[] value) throws IOException { 16 | out.packInt(value.length); 17 | for (float v : value) { 18 | out.writeFloat(v); 19 | } 20 | } 21 | 22 | @Override 23 | public float[] deserialize(DataInput2 in, int available) throws IOException { 24 | float[] ret = new float[in.unpackInt()]; 25 | for (int i = 0; i < ret.length; i++) { 26 | ret[i] = in.readFloat(); 27 | } 28 | return ret; 29 | } 30 | 31 | @Override 32 | public boolean isTrusted() { 33 | return true; 34 | } 35 | 36 | @Override 37 | public boolean equals(float[] a1, float[] a2) { 38 | return Arrays.equals(a1, a2); 39 | } 40 | 41 | @Override 42 | public int hashCode(float[] floats, int seed) { 43 | for (float element : floats) 44 | seed = (-1640531527) * seed + Float.floatToIntBits(element); 45 | return seed; 46 | } 47 | 48 | @Override 49 | public int compare(float[] o1, float[] o2) { 50 | if (o1 == o2) return 0; 51 | final int len = Math.min(o1.length, o2.length); 52 | for (int i = 0; i < len; i++) { 53 | if (o1[i] == o2[i]) 54 | continue; 55 | if (o1[i] > o2[i]) 56 | return 1; 57 | return -1; 58 | } 59 | return SerializerUtils.compareInt(o1.length, o2.length); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/HTreeMap_Expiration_Multithreaded.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | 4 | import org.junit.Test 5 | import java.util.Random 6 | import java.util.UUID 7 | import java.util.concurrent.TimeUnit 8 | 9 | class HTreeMap_Expiration_Multithreaded { 10 | 11 | internal val duration = 10 * 60 * 1000.toLong() 12 | internal var b = ByteArray(100) 13 | 14 | @Test fun expireUUID() { 15 | if (TT.shortTest()) 16 | return 17 | 18 | val endTime = duration + System.currentTimeMillis() 19 | 20 | val db = DBMaker.memoryDB().make() 21 | val m = db.hashMap("aa") 22 | .keySerializer(Serializer.UUID) 23 | .valueSerializer(Serializer.BYTE_ARRAY) 24 | .expireAfterCreate(20, TimeUnit.SECONDS) 25 | .expireExecutor(TT.executor(3)) 26 | .create() 27 | 28 | TT.fork(10) { 29 | var r = Random(1) 30 | run { 31 | var i = 0 32 | while (i < 2e5){ 33 | val u = UUID(r.nextLong(), r.nextLong()) 34 | m.put(u, b) 35 | i++ 36 | } 37 | } 38 | 39 | while (System.currentTimeMillis() < endTime) { 40 | r = Random(1) 41 | run { 42 | var i = 0 43 | while (i < 1e5){ 44 | val u = UUID(r.nextLong(), r.nextLong()) 45 | m.get(u) 46 | m.put(u, b) 47 | i++ 48 | } 49 | } 50 | var i = 1e5.toInt() 51 | while (i < 2e5){ 52 | val u = UUID(r.nextLong(), r.nextLong()) 53 | m[u] 54 | i++ 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/volume/FileChannelCrashTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | import org.mapdb.crash.CrashJVM 6 | import org.mapdb.TT 7 | import java.io.File 8 | import java.io.RandomAccessFile 9 | import java.nio.ByteBuffer 10 | import java.nio.channels.FileChannel 11 | import java.nio.file.StandardOpenOption.* 12 | 13 | 14 | class FileChannelCrashTest: CrashJVM(){ 15 | 16 | override fun verifySeed(startSeed: Long, endSeed: Long, params:String): Long { 17 | println("verify") 18 | val seed = endSeed 19 | assertTrue(File(getTestDir(), "" + seed+"aa").exists()) 20 | val r = RandomAccessFile(getTestDir().path + "/" + seed+"aa","r") 21 | r.seek(0) 22 | val v = r.readLong() 23 | assertEquals(seed, v) 24 | r.close() 25 | 26 | 27 | return Math.max(startSeed,endSeed)+1; 28 | } 29 | 30 | override fun doInJVM(startSeed: Long, params:String) { 31 | var seed = startSeed; 32 | 33 | while(true){ 34 | seed++ 35 | startSeed(seed) 36 | val bb = ByteBuffer.allocate(8); 37 | bb.putLong(seed) 38 | 39 | val f = File(getTestDir(), "/" + seed+"aa") 40 | val c = FileChannel.open(f.toPath(), 41 | CREATE, READ, WRITE) 42 | var pos = 0; 43 | while(pos!=8) { 44 | pos+=c.write(bb, 0L) 45 | } 46 | c.force(false) 47 | c.close() 48 | assertEquals(8, f.length()) 49 | commitSeed(seed) 50 | } 51 | } 52 | 53 | @Test fun test(){ 54 | val runtime = 4000L + TT.testScale()*60*1000; 55 | val start = System.currentTimeMillis() 56 | Companion.run(this, time=runtime, killDelay = 200) 57 | assertTrue(System.currentTimeMillis() - start >= runtime) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/crash/WALChannelCrashTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.crash 2 | 3 | import org.junit.Test 4 | import java.io.* 5 | import java.nio.ByteBuffer 6 | import java.nio.channels.FileChannel 7 | import java.nio.file.StandardOpenOption 8 | import org.junit.Assert.* 9 | import org.mapdb.DataIO 10 | import org.mapdb.TT 11 | 12 | 13 | /** 14 | * Created by jan on 3/16/16. 15 | */ 16 | class WALChannelCrashTest: CrashJVM(){ 17 | 18 | 19 | override fun doInJVM(startSeed: Long, params: String) { 20 | val f = File(getTestDir().path, "aaa") 21 | val out = FileChannel.open(f.toPath(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE) 22 | val b = ByteBuffer.allocate(8) 23 | var seed = startSeed 24 | while(true){ 25 | seed++ 26 | startSeed(seed) 27 | b.rewind() 28 | b.putLong(seed) 29 | var written = 0; 30 | while(written<8){ 31 | written+=out.write(b) 32 | } 33 | out.force(false) 34 | commitSeed(seed) 35 | } 36 | 37 | } 38 | 39 | override fun verifySeed(startSeed: Long, endSeed: Long, params: String): Long { 40 | val f = getTestDir().path+"/aaa" 41 | val ins = BufferedInputStream(FileInputStream(f)) 42 | val b = ByteArray(8) 43 | var lastSeed = 0L 44 | while(true){ 45 | try{ 46 | DataIO.readFully(ins, b) 47 | lastSeed = DataIO.getLong(b,0) 48 | }catch(e: IOException){ 49 | break 50 | } 51 | } 52 | assertTrue(lastSeed == endSeed || lastSeed==endSeed+1) 53 | 54 | File(f).delete() 55 | return endSeed+10 56 | } 57 | 58 | @Test fun run(){ 59 | if(TT.shortTest()) 60 | return 61 | run(this, killDelay = 300) 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerJava.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.CC; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | import org.mapdb.Serializer; 7 | 8 | import java.io.IOException; 9 | import java.io.ObjectInputStream; 10 | import java.io.ObjectOutputStream; 11 | import java.io.OutputStream; 12 | 13 | /** 14 | * Created by jan on 2/28/16. 15 | */ 16 | public class SerializerJava extends GroupSerializerObjectArray { 17 | @Override 18 | public void serialize(DataOutput2 out, Object value) throws IOException { 19 | ObjectOutputStream out2 = new ObjectOutputStream((OutputStream) out); 20 | out2.writeObject(value); 21 | out2.flush(); 22 | } 23 | 24 | @Override 25 | public Object deserialize(DataInput2 in, int available) throws IOException { 26 | try { 27 | ObjectInputStream in2 = new ObjectInputStream(new DataInput2.DataInputToStream(in)); 28 | return in2.readObject(); 29 | } catch (ClassNotFoundException e) { 30 | throw new IOException(e); 31 | } 32 | } 33 | 34 | @Override 35 | public Object[] valueArrayDeserialize(DataInput2 in, int size) throws IOException { 36 | try { 37 | ObjectInputStream in2 = new ObjectInputStream(new DataInput2.DataInputToStream(in)); 38 | Object ret = in2.readObject(); 39 | if(CC.PARANOID && size!=valueArraySize(ret)) 40 | throw new AssertionError(); 41 | return (Object[]) ret; 42 | } catch (ClassNotFoundException e) { 43 | throw new IOException(e); 44 | } 45 | } 46 | 47 | @Override 48 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 49 | ObjectOutputStream out2 = new ObjectOutputStream((OutputStream) out); 50 | out2.writeObject(vals); 51 | out2.flush(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/volume/RAFCrashtest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | import org.junit.Ignore 4 | import org.junit.Test 5 | import java.io.File 6 | import java.io.RandomAccessFile 7 | import java.util.* 8 | import org.junit.Assert.* 9 | import org.mapdb.crash.CrashJVM 10 | import org.mapdb.TT 11 | 12 | 13 | class RAFCrashtest: CrashJVM(){ 14 | 15 | val max = 8L//4L*1024*1024 16 | val count = 100; 17 | fun fileForSeed(seed:Long) = getTestDir().toString()+"/"+seed; 18 | 19 | override fun doInJVM(startSeed: Long, params: String) { 20 | var seed = startSeed 21 | while (true) { 22 | seed++ 23 | val file = fileForSeed(seed) 24 | val raf = RandomAccessFile(file, "rw") 25 | raf.setLength(max) 26 | 27 | val random = Random(seed) 28 | for(i in 0 until count) { 29 | //raf.seek(random.nextInt(max.toInt() - 8).toLong()) 30 | raf.seek(0) 31 | raf.writeLong(random.nextLong()) 32 | } 33 | raf.fd.sync() 34 | raf.close() 35 | commitSeed(seed) 36 | //delete prev file to keep disk space usage low 37 | File(fileForSeed(seed - 1)).delete() 38 | 39 | } 40 | } 41 | 42 | override fun verifySeed(startSeed: Long, endSeed: Long, params: String): Long { 43 | val file = fileForSeed(endSeed) 44 | val raf = RandomAccessFile(file, "r") 45 | assertEquals(max, raf.length()) 46 | val random = Random(endSeed) 47 | for(i in 0 until count-1) { 48 | random.nextLong() 49 | // raf.seek(random.nextInt(max.toInt() - 8).toLong()) 50 | } 51 | assertEquals(random.nextLong(), raf.readLong()) 52 | 53 | raf.close() 54 | return endSeed+10 55 | } 56 | 57 | 58 | @Test 59 | fun run() { 60 | run(this, time = TT.testRuntime(10)) 61 | } 62 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/crash/StoreCrashTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.crash 2 | 3 | import org.junit.Test 4 | import java.io.File 5 | import org.junit.Assert.* 6 | import org.mapdb.* 7 | import org.mapdb.crash.CrashJVM 8 | 9 | /** 10 | * Check of commits are durable and survive JVM crash (kill PID -9) 11 | */ 12 | abstract class StoreCrashTest: CrashJVM(){ 13 | abstract fun openStore(file: File): Store; 14 | 15 | 16 | override fun doInJVM(startSeed: Long, params:String) { 17 | val store = openStore(File(getTestDir(), "store")) 18 | 19 | val recid = params.toLong() 20 | var seed = startSeed; 21 | while (true) { 22 | seed++; 23 | startSeed(seed) 24 | store.update(recid, seed, Serializer.LONG) 25 | store.commit() 26 | commitSeed(seed) 27 | } 28 | } 29 | 30 | override fun verifySeed(startSeed: Long, endSeed: Long, params:String): Long { 31 | val recid = params.toLong() 32 | val store = openStore(File(getTestDir(), "store")) 33 | val seed = store.get(recid, Serializer.LONG)!! 34 | store.close() 35 | assertTrue(seed<=startSeed) 36 | assertTrue(endSeed==-1L || seed>=endSeed); 37 | 38 | return seed; 39 | } 40 | 41 | @Test fun crashTest(){ 42 | val store = openStore(File(getTestDir(), "store")) 43 | val recid = store.put(0L, Serializer.LONG) 44 | store.commit() 45 | store.close() 46 | run(this, time = TT.testRuntime(6), params = recid.toString()) 47 | } 48 | } 49 | 50 | class StoreTrivialCrashTest: StoreCrashTest(){ 51 | 52 | override fun openStore(file: File): Store { 53 | return StoreTrivialTx(file); 54 | } 55 | 56 | 57 | 58 | } 59 | 60 | 61 | class StoreWALCrashTest: StoreCrashTest(){ 62 | 63 | override fun openStore(file: File): Store { 64 | return StoreWAL.make(file=file.path); 65 | } 66 | 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/crash/WALCrashTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.crash 2 | 3 | import org.mapdb.volume.Volume 4 | import org.junit.Assert.* 5 | import org.junit.Test 6 | import org.mapdb.TT 7 | import org.mapdb.* 8 | 9 | class WALCrashTest: CrashJVM(){ 10 | 11 | override fun doInJVM(startSeed: Long, params: String) { 12 | val file = getTestDir().path+"/wal" 13 | val wal = WriteAheadLog(file, CC.DEFAULT_FILE_VOLUME_FACTORY, 0L) 14 | var seed = startSeed; 15 | while(true){ 16 | seed++ 17 | startSeed(seed) 18 | val bb = TT.randomByteArray(31,seed.toInt()) 19 | wal.walPutLong(8L,seed) 20 | wal.walPutByteArray(16L, bb, 0, bb.size) 21 | commitSeed(seed) 22 | } 23 | } 24 | 25 | override fun verifySeed(startSeed: Long, endSeed: Long, params: String): Long { 26 | val file = getTestDir().path+"/wal" 27 | val wal = WriteAheadLog(file, CC.DEFAULT_FILE_VOLUME_FACTORY, 0L) 28 | var lastLong:Long?=null 29 | var lastBB:ByteArray?=null 30 | wal.replayWAL(object: WriteAheadLog.WALReplay by WriteAheadLog.NOREPLAY{ 31 | override fun writeLong(offset: Long, value: Long) { 32 | lastLong=value 33 | } 34 | 35 | override fun writeRecord(recid: Long, walId: Long, vol: Volume, volOffset: Long, length: Int) { 36 | val bb = ByteArray(length) 37 | vol.getData(volOffset,bb,0,bb.size) 38 | lastBB = bb 39 | } 40 | }) 41 | 42 | if(lastLong==null){ 43 | assertNull(lastBB) 44 | return endSeed+10 45 | } 46 | 47 | assertTrue(lastLong!! in endSeed-1..endSeed) 48 | assertArrayEquals(TT.randomByteArray(31,lastLong!!.toInt()), lastBB) 49 | 50 | return endSeed+10 51 | } 52 | 53 | @Test fun run(){ 54 | if(TT.shortTest()) 55 | return 56 | run(this) 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerRecid.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataIO; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerRecid extends SerializerEightByte { 14 | 15 | @Override 16 | public void serialize(DataOutput2 out, Long value) throws IOException { 17 | DataIO.packRecid(out, value); 18 | } 19 | 20 | @Override 21 | public Long deserialize(DataInput2 in, int available) throws IOException { 22 | return new Long(DataIO.unpackRecid(in)); 23 | } 24 | 25 | @Override 26 | public int fixedSize() { 27 | return -1; 28 | } 29 | 30 | @Override 31 | protected Long unpack(long l) { 32 | return new Long(l); 33 | } 34 | 35 | @Override 36 | protected long pack(Long l) { 37 | return l; 38 | } 39 | 40 | @Override 41 | public boolean isTrusted() { 42 | return true; 43 | } 44 | 45 | 46 | @Override 47 | public int valueArraySearch(Object keys, Long key) { 48 | return Arrays.binarySearch((long[])keys, key); 49 | } 50 | 51 | @Override 52 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 53 | for (long o : (long[]) vals) { 54 | DataIO.packRecid(out, o); 55 | } 56 | } 57 | 58 | @Override 59 | public long[] valueArrayDeserialize(DataInput2 in, int size) throws IOException { 60 | long[] ret = new long[size]; 61 | for (int i = 0; i < size; i++) { 62 | ret[i] = DataIO.unpackRecid(in); 63 | } 64 | return ret; 65 | } 66 | 67 | @Override 68 | public Long valueArrayBinaryGet(DataInput2 input, int keysLen, int pos) throws IOException { 69 | input.unpackLongSkip(pos); 70 | return deserialize(input,-1); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/SortedTableMap_ConcurrentMap_Guava.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.mapdb.guavaTests.ConcurrentMapInterfaceTest 4 | import java.util.concurrent.ConcurrentMap 5 | 6 | class SortedTableMap_ConcurrentMap_Guava: 7 | ConcurrentMapInterfaceTest( 8 | false, // boolean allowsNullKeys, 9 | false, // boolean allowsNullValues, 10 | false, // boolean supportsPut, 11 | false, // boolean supportsRemove, 12 | false, // boolean supportsClear, 13 | false // boolean supportsIteratorRemove 14 | ){ 15 | override fun getKeyNotInPopulatedMap(): Int? { 16 | return 51 17 | } 18 | 19 | override fun getValueNotInPopulatedMap(): String? { 20 | return "511" 21 | } 22 | 23 | override fun getSecondValueNotInPopulatedMap(): String? { 24 | return "521" 25 | } 26 | 27 | override fun makeEmptyMap(): ConcurrentMap? { 28 | val consumer = SortedTableMap.createFromSink( 29 | keySerializer = Serializer.INTEGER, 30 | valueSerializer = Serializer.STRING, 31 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false) 32 | ) 33 | return consumer.create() 34 | } 35 | 36 | override fun makePopulatedMap(): ConcurrentMap? { 37 | val consumer = SortedTableMap.createFromSink( 38 | keySerializer = Serializer.INTEGER, 39 | valueSerializer = Serializer.STRING, 40 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false) 41 | ) 42 | for(i in 1..100){ 43 | consumer.put(Pair(i*2, ""+i*10)) 44 | } 45 | 46 | return consumer.create() 47 | } 48 | 49 | override fun supportsValuesHashCode(map: MutableMap?): Boolean { 50 | // keySerializer returns wrong hash on purpose for this test, so pass it 51 | return false; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerDoubleArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerDoubleArray extends GroupSerializerObjectArray { 14 | 15 | @Override 16 | public void serialize(DataOutput2 out, double[] value) throws IOException { 17 | out.packInt(value.length); 18 | for (double c : value) { 19 | out.writeDouble(c); 20 | } 21 | } 22 | 23 | @Override 24 | public double[] deserialize(DataInput2 in, int available) throws IOException { 25 | final int size = in.unpackInt(); 26 | double[] ret = new double[size]; 27 | for (int i = 0; i < size; i++) { 28 | ret[i] = in.readDouble(); 29 | } 30 | return ret; 31 | } 32 | 33 | 34 | @Override 35 | public boolean isTrusted() { 36 | return true; 37 | } 38 | 39 | @Override 40 | public boolean equals(double[] a1, double[] a2) { 41 | return Arrays.equals(a1, a2); 42 | } 43 | 44 | @Override 45 | public int hashCode(double[] bytes, int seed) { 46 | for (double element : bytes) { 47 | long bits = Double.doubleToLongBits(element); 48 | seed = (-1640531527) * seed + (int) (bits ^ (bits >>> 32)); 49 | } 50 | return seed; 51 | } 52 | 53 | @Override 54 | public int compare(double[] o1, double[] o2) { 55 | if (o1 == o2) return 0; 56 | final int len = Math.min(o1.length, o2.length); 57 | for (int i = 0; i < len; i++) { 58 | if (o1[i] == o2[i]) 59 | continue; 60 | if (o1[i] > o2[i]) 61 | return 1; 62 | return -1; 63 | } 64 | return SerializerUtils.compareInt(o1.length, o2.length); 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerLongPacked.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Comparator; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerLongPacked extends SerializerLong { 13 | @Override 14 | public void serialize(DataOutput2 out, Long value) throws IOException { 15 | out.packLong(value); 16 | } 17 | 18 | @Override 19 | public Long deserialize(DataInput2 in, int available) throws IOException { 20 | return new Long(in.unpackLong()); 21 | } 22 | 23 | @Override 24 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 25 | for (long o : (long[])vals) { 26 | out.packLong(o); 27 | } 28 | } 29 | 30 | @Override 31 | public long[] valueArrayDeserialize(DataInput2 in, int size) throws IOException { 32 | long[] ret = new long[size]; 33 | in.unpackLongArray(ret, 0, size); 34 | return ret; 35 | } 36 | 37 | @Override 38 | public int fixedSize() { 39 | return -1; 40 | } 41 | 42 | @Override 43 | public int valueArrayBinarySearch(Long key, DataInput2 input, int keysLen, Comparator comparator) throws IOException { 44 | if (comparator != this) 45 | return super.valueArrayBinarySearch(key, input, keysLen, comparator); 46 | long key2 = key; 47 | for (int pos = 0; pos < keysLen; pos++) { 48 | long from = input.unpackLong(); 49 | 50 | if (key2 <= from) { 51 | input.unpackLongSkip(keysLen - pos - 1); 52 | return (key2 == from) ? pos : -(pos + 1); 53 | } 54 | } 55 | 56 | //not found 57 | return -(keysLen + 1); 58 | } 59 | 60 | @Override 61 | public Long valueArrayBinaryGet(DataInput2 input, int keysLen, int pos) throws IOException { 62 | input.unpackLongSkip(pos); 63 | return input.unpackLong(); 64 | } 65 | 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerIntegerPacked.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Comparator; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerIntegerPacked extends SerializerInteger { 13 | @Override 14 | public void serialize(DataOutput2 out, Integer value) throws IOException { 15 | out.packInt(value); 16 | } 17 | 18 | @Override 19 | public Integer deserialize(DataInput2 in, int available) throws IOException { 20 | return new Integer(in.unpackInt()); 21 | } 22 | 23 | @Override 24 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 25 | for (int o : (int[])vals) { 26 | out.packIntBigger(o); 27 | } 28 | } 29 | 30 | @Override 31 | public int[] valueArrayDeserialize(DataInput2 in, int size) throws IOException { 32 | int[] ret = new int[size]; 33 | in.unpackIntArray(ret, 0, size); 34 | return ret; 35 | } 36 | 37 | @Override 38 | public int fixedSize() { 39 | return -1; 40 | } 41 | 42 | @Override 43 | public int valueArrayBinarySearch(Integer key, DataInput2 input, int keysLen, Comparator comparator) throws IOException { 44 | if (comparator != this) 45 | return super.valueArrayBinarySearch(key, input, keysLen, comparator); 46 | int key2 = key; 47 | for (int pos = 0; pos < keysLen; pos++) { 48 | int from = input.unpackInt(); 49 | 50 | if (key2 <= from) { 51 | input.unpackLongSkip(keysLen-pos-1); 52 | return (key2 == from) ? pos : -(pos + 1); 53 | } 54 | } 55 | 56 | //not found 57 | return -(keysLen + 1); 58 | } 59 | 60 | @Override 61 | public Integer valueArrayBinaryGet(DataInput2 input, int keysLen, int pos) throws IOException { 62 | input.unpackLongSkip(pos); 63 | return input.unpackInt(); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/PumpTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.fest.reflect.core.Reflection 4 | import org.junit.Test 5 | import org.junit.Assert.* 6 | 7 | class PumpTest{ 8 | 9 | val Pump.Sink<*,*>.rootRecidRecid: Long 10 | get() = Reflection.method("getRootRecidRecid").`in`(this).invoke() as Long 11 | 12 | 13 | @Test fun single(){ 14 | check((1..6).map{Pair(it, it*2)}) 15 | } 16 | 17 | @Test fun cent(){ 18 | check((1..100).map{Pair(it, it*2)}) 19 | } 20 | 21 | @Test fun kilo(){ 22 | check((1..1000).map{Pair(it, it*2)}) 23 | } 24 | 25 | @Test fun multi(){ 26 | if(TT.shortTest()) 27 | return 28 | for(limit in 0 .. 1000) { 29 | check((0 .. limit).map { Pair(it, it * 2) }) 30 | } 31 | } 32 | 33 | 34 | @Test fun mega(){ 35 | check((1..1000000).map{Pair(it, it*2)}) 36 | } 37 | 38 | @Test(expected = DBException.NotSorted::class) 39 | fun notSorted(){ 40 | check((6 downTo 1).map{Pair(it, it*2)}) 41 | } 42 | 43 | private fun check(source: List>) { 44 | val store = StoreTrivial() 45 | val taker = Pump.treeMap( 46 | store = store, 47 | keySerializer = Serializer.INTEGER, 48 | valueSerializer = Serializer.INTEGER, 49 | dirNodeSize = 10, 50 | leafNodeSize = 10 51 | ) 52 | taker.putAll(source) 53 | taker.create() 54 | 55 | val root = taker.rootRecidRecid 56 | ?: throw AssertionError() 57 | assertNotEquals(0L, root) 58 | 59 | val map = BTreeMap.make( 60 | store = store, 61 | rootRecidRecid = root, 62 | valueSerializer = Serializer.INTEGER, 63 | keySerializer = Serializer.INTEGER) 64 | // map.printStructure(System.out) 65 | map.verify() 66 | 67 | assertEquals(source.size, map.size) 68 | source.forEach { 69 | assertEquals(it.second, map[it.first]) 70 | } 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/StoreDirectJava.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | /** 4 | * Low level utilities for StoreDirect 5 | */ 6 | final class StoreDirectJava { 7 | 8 | static final long MAX_RECORD_SIZE = 0xFFFF-15; 9 | static final long NULL_RECORD_SIZE = 0xFFFF; 10 | static final long DELETED_RECORD_SIZE = 0xFFFF-1; 11 | 12 | 13 | static final long MOFFSET = 0x0000FFFFFFFFFFF0L; 14 | static final long MLINKED = 0x8L; 15 | static final long MUNUSED = 0x4L; 16 | static final long MARCHIVE = 0x2L; 17 | 18 | static final int HEAD_CHECKSUM_SEED = 1142099053; 19 | 20 | static final long HEADER_CHECKSUM = 2*8; //TODO benchmarks 21 | static final long DATA_TAIL_OFFSET = 3*8; 22 | static final long INDEX_TAIL_OFFSET = 4*8; 23 | static final long FILE_TAIL_OFFSET = 5*8; 24 | 25 | 26 | // static final long LONG_STACK_UNUSED1 = 64; 27 | // static final long LONG_STACK_UNUSED16 = LONG_STACK_UNUSED1+16*8; 28 | 29 | static final long RECID_LONG_STACK = 8*8; 30 | 31 | static final long NUMBER_OF_SPACE_SLOTS = 1+MAX_RECORD_SIZE/16; 32 | 33 | static final long UNUSED1_LONG_STACK = 8L * NUMBER_OF_SPACE_SLOTS + RECID_LONG_STACK; 34 | static final long UNUSED2_LONG_STACK = UNUSED1_LONG_STACK+8; 35 | static final long UNUSED3_LONG_STACK = UNUSED2_LONG_STACK+8; 36 | static final long UNUSED4_LONG_STACK = UNUSED3_LONG_STACK+8; 37 | static final long HEAD_END = UNUSED4_LONG_STACK+8; 38 | static final long ZERO_PAGE_LINK = HEAD_END; 39 | 40 | protected final static long LONG_STACK_PREF_SIZE = 160; 41 | protected final static long LONG_STACK_MIN_SIZE = 16; 42 | protected final static long LONG_STACK_MAX_SIZE = 256; 43 | 44 | 45 | static final long RECIDS_PER_INDEX_PAGE = (CC.PAGE_SIZE-16)/8; 46 | static final long RECIDS_PER_ZERO_INDEX_PAGE = (CC.PAGE_SIZE-HEAD_END-16)/8; 47 | 48 | static long indexValToSize(long ival){ 49 | return ival>>>48; 50 | } 51 | 52 | 53 | 54 | static long indexValToOffset(long ival){ 55 | return ival&MOFFSET; 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerCharArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerCharArray extends GroupSerializerObjectArray { 13 | 14 | @Override 15 | public void serialize(DataOutput2 out, char[] value) throws IOException { 16 | out.packInt(value.length); 17 | for (char c : value) { 18 | out.writeChar(c); 19 | } 20 | } 21 | 22 | @Override 23 | public char[] deserialize(DataInput2 in, int available) throws IOException { 24 | final int size = in.unpackInt(); 25 | char[] ret = new char[size]; 26 | for (int i = 0; i < size; i++) { 27 | ret[i] = in.readChar(); 28 | } 29 | return ret; 30 | } 31 | 32 | @Override 33 | public boolean isTrusted() { 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean equals(char[] a1, char[] a2) { 39 | return Arrays.equals(a1, a2); 40 | } 41 | 42 | @Override 43 | public int hashCode(char[] chars, int seed) { 44 | int res = 0; 45 | for (char c : chars) { 46 | res = (res + c) * -1640531527 ; 47 | } 48 | return res; 49 | } 50 | 51 | @Override 52 | public int compare(char[] o1, char[] o2) { 53 | final int len = Math.min(o1.length, o2.length); 54 | for (int i = 0; i < len; i++) { 55 | int b1 = o1[i]; 56 | int b2 = o2[i]; 57 | if (b1 != b2) 58 | return b1 - b2; 59 | } 60 | return SerializerUtils.compareInt(o1.length, o2.length); 61 | } 62 | 63 | @Override 64 | public char[] nextValue(char[] value) { 65 | value = value.clone(); 66 | 67 | for (int i = value.length-1; ;i--) { 68 | char b1 = value[i]; 69 | if(b1==Character.MAX_VALUE){ 70 | if(i==0) 71 | return null; 72 | value[i]=Character.MIN_VALUE; 73 | continue; 74 | } 75 | value[i] = (char) (b1+1); 76 | return value; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerShortArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerShortArray extends GroupSerializerObjectArray { 13 | @Override 14 | public void serialize(DataOutput2 out, short[] value) throws IOException { 15 | out.packInt(value.length); 16 | for (short v : value) { 17 | out.writeShort(v); 18 | } 19 | } 20 | 21 | @Override 22 | public short[] deserialize(DataInput2 in, int available) throws IOException { 23 | short[] ret = new short[in.unpackInt()]; 24 | for (int i = 0; i < ret.length; i++) { 25 | ret[i] = in.readShort(); 26 | } 27 | return ret; 28 | } 29 | 30 | @Override 31 | public boolean isTrusted() { 32 | return true; 33 | } 34 | 35 | @Override 36 | public boolean equals(short[] a1, short[] a2) { 37 | return Arrays.equals(a1, a2); 38 | } 39 | 40 | @Override 41 | public int hashCode(short[] shorts, int seed) { 42 | for (short element : shorts) 43 | seed = (-1640531527) * seed + element; 44 | return seed; 45 | } 46 | 47 | @Override 48 | public int compare(short[] o1, short[] o2) { 49 | if (o1 == o2) return 0; 50 | final int len = Math.min(o1.length, o2.length); 51 | for (int i = 0; i < len; i++) { 52 | if (o1[i] == o2[i]) 53 | continue; 54 | if (o1[i] > o2[i]) 55 | return 1; 56 | return -1; 57 | } 58 | return SerializerUtils.compareInt(o1.length, o2.length); 59 | } 60 | 61 | @Override 62 | public short[] nextValue(short[] value) { 63 | value = value.clone(); 64 | 65 | for (int i = value.length-1; ;i--) { 66 | short b1 = value[i]; 67 | if(b1==Short.MAX_VALUE){ 68 | if(i==0) 69 | return null; 70 | value[i]=Short.MIN_VALUE; 71 | continue; 72 | } 73 | value[i] = (short) (b1+1); 74 | return value; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerByteArrayDelta.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | 8 | /** 9 | * Created by jan on 2/29/16. 10 | */ 11 | public class SerializerByteArrayDelta extends SerializerByteArray { 12 | 13 | //TODO PERF char[][] versus Object[] 14 | 15 | @Override 16 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 17 | byte[][] chars = (byte[][]) vals; 18 | //write lengths 19 | for(byte[] b:chars){ 20 | out.packInt(b.length); 21 | } 22 | //$DELAY$ 23 | //find common prefix 24 | int prefixLen = commonPrefixLen(chars); 25 | out.packInt(prefixLen); 26 | out.write(chars[0], 0, prefixLen); 27 | //$DELAY$ 28 | for(byte[] b:chars){ 29 | out.write(b,prefixLen,b.length-prefixLen); 30 | } 31 | 32 | 33 | } 34 | 35 | @Override 36 | public byte[][] valueArrayDeserialize(DataInput2 in, int size) throws IOException { 37 | byte[][] ret = new byte[size][]; 38 | 39 | //read lengths and init arrays 40 | for(int i=0;i { 14 | 15 | @Override 16 | public void serialize(DataOutput2 out, int[] value) throws IOException { 17 | out.packInt(value.length); 18 | for (int c : value) { 19 | out.writeInt(c); 20 | } 21 | } 22 | 23 | @Override 24 | public int[] deserialize(DataInput2 in, int available) throws IOException { 25 | final int size = in.unpackInt(); 26 | int[] ret = new int[size]; 27 | for (int i = 0; i < size; i++) { 28 | ret[i] = in.readInt(); 29 | } 30 | return ret; 31 | } 32 | 33 | @Override 34 | public boolean isTrusted() { 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean equals(int[] a1, int[] a2) { 40 | return Arrays.equals(a1, a2); 41 | } 42 | 43 | @Override 44 | public int hashCode(int[] bytes, int seed) { 45 | for (int i : bytes) { 46 | seed = (-1640531527) * seed + i; 47 | } 48 | return seed; 49 | } 50 | 51 | @Override 52 | public int compare(int[] o1, int[] o2) { 53 | if (o1 == o2) return 0; 54 | final int len = Math.min(o1.length, o2.length); 55 | for (int i = 0; i < len; i++) { 56 | if (o1[i] == o2[i]) 57 | continue; 58 | if (o1[i] > o2[i]) 59 | return 1; 60 | return -1; 61 | } 62 | return SerializerUtils.compareInt(o1.length, o2.length); 63 | } 64 | 65 | @Override 66 | public int[] nextValue(int[] value) { 67 | value = value.clone(); 68 | 69 | for (int i = value.length-1; ;i--) { 70 | int b1 = value[i]; 71 | if(b1==Integer.MAX_VALUE){ 72 | if(i==0) 73 | return null; 74 | value[i]=Integer.MIN_VALUE; 75 | continue; 76 | } 77 | value[i] = b1+1; 78 | return value; 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerLongArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | 6 | import java.io.IOException; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * Created by jan on 2/28/16. 11 | */ 12 | public class SerializerLongArray extends GroupSerializerObjectArray { 13 | 14 | @Override 15 | public void serialize(DataOutput2 out, long[] value) throws IOException { 16 | out.packInt(value.length); 17 | for (long c : value) { 18 | out.writeLong(c); 19 | } 20 | } 21 | 22 | @Override 23 | public long[] deserialize(DataInput2 in, int available) throws IOException { 24 | final int size = in.unpackInt(); 25 | long[] ret = new long[size]; 26 | for (int i = 0; i < size; i++) { 27 | ret[i] = in.readLong(); 28 | } 29 | return ret; 30 | } 31 | 32 | 33 | @Override 34 | public boolean isTrusted() { 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean equals(long[] a1, long[] a2) { 40 | return Arrays.equals(a1, a2); 41 | } 42 | 43 | @Override 44 | public int hashCode(long[] bytes, int seed) { 45 | for (long element : bytes) { 46 | int elementHash = (int) (element ^ (element >>> 32)); 47 | seed = (-1640531527) * seed + elementHash; 48 | } 49 | return seed; 50 | } 51 | 52 | @Override 53 | public int compare(long[] o1, long[] o2) { 54 | if (o1 == o2) return 0; 55 | final int len = Math.min(o1.length, o2.length); 56 | for (int i = 0; i < len; i++) { 57 | if (o1[i] == o2[i]) 58 | continue; 59 | if (o1[i] > o2[i]) 60 | return 1; 61 | return -1; 62 | } 63 | return SerializerUtils.compareInt(o1.length, o2.length); 64 | } 65 | 66 | @Override 67 | public long[] nextValue(long[] value) { 68 | value = value.clone(); 69 | 70 | for (int i = value.length-1; ;i--) { 71 | long b1 = value[i]; 72 | if(b1==Long.MAX_VALUE){ 73 | if(i==0) 74 | return null; 75 | value[i]=Long.MIN_VALUE; 76 | continue; 77 | } 78 | value[i] = b1+1L; 79 | return value; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/StoreWALTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | import org.mapdb.StoreAccess.volume 6 | import java.io.File 7 | import java.io.RandomAccessFile 8 | 9 | /** 10 | * Created by jan on 3/22/16. 11 | */ 12 | class StoreWALTest: StoreDirectAbstractTest() { 13 | 14 | override fun openStore(file: File): StoreWAL { 15 | return StoreWAL.make(file=file.path) 16 | } 17 | 18 | override fun openStore(): StoreWAL { 19 | return StoreWAL.make() 20 | } 21 | 22 | 23 | @Test override fun delete_after_close(){ 24 | val dir = TT.tempDir() 25 | val store = StoreWAL.make(dir.path+"/aa",deleteFilesAfterClose = true) 26 | store.put(11, Serializer.INTEGER) 27 | store.commit() 28 | store.put(11, Serializer.INTEGER) 29 | store.commit() 30 | assertNotEquals(0, dir.listFiles().size) 31 | store.close() 32 | assertEquals(0, dir.listFiles().size) 33 | } 34 | 35 | @Test(expected=DBException.WrongConfiguration::class) 36 | fun checksum_disabled(){ 37 | StoreWAL.make(checksum=true) 38 | } 39 | 40 | @Test fun no_head_checksum(){ 41 | var store = StoreWAL.make(checksumHeader = false) 42 | assertEquals(0, store.volume.getInt(16)) //features 43 | assertEquals(0, store.volume.getInt(20)) //checksum 44 | 45 | store = StoreWAL.make(checksumHeader = true) 46 | assertEquals(1, store.volume.getInt(16)) //features 47 | assertNotEquals(0, store.volume.getInt(20)) //checksum 48 | 49 | } 50 | 51 | @Test fun headers2(){ 52 | val f = TT.tempFile() 53 | val store = openStore(f) 54 | store.put(TT.randomByteArray(1000000),Serializer.BYTE_ARRAY) 55 | 56 | val raf = RandomAccessFile(f.path, "r"); 57 | raf.seek(0) 58 | assertEquals(CC.FILE_HEADER.toInt(), raf.readUnsignedByte()) 59 | assertEquals(CC.FILE_TYPE_STOREDIRECT.toInt(), raf.readUnsignedByte()) 60 | assertEquals(0, raf.readChar().toInt()) 61 | raf.close() 62 | 63 | val wal = RandomAccessFile(f.path + ".wal.0", "r"); 64 | wal.seek(0) 65 | assertEquals(CC.FILE_HEADER.toInt(), wal.readUnsignedByte()) 66 | assertEquals(CC.FILE_TYPE_STOREWAL_WAL.toInt(), wal.readUnsignedByte()) 67 | assertEquals(0, wal.readChar().toInt()) 68 | wal.close() 69 | f.delete() 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerLongDelta.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.CC; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | 7 | import java.io.IOException; 8 | import java.util.Comparator; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerLongDelta extends SerializerLong { 14 | @Override 15 | public void serialize(DataOutput2 out, Long value) throws IOException { 16 | out.packLong(value); 17 | } 18 | 19 | @Override 20 | public Long deserialize(DataInput2 in, int available) throws IOException { 21 | return new Long(in.unpackLong()); 22 | } 23 | 24 | @Override 25 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 26 | long[] keys = (long[]) vals; 27 | long prev = keys[0]; 28 | out.packLong(prev); 29 | for (int i = 1; i < keys.length; i++) { 30 | long curr = keys[i]; 31 | //$DELAY$ 32 | out.packLong(curr - prev); 33 | if (CC.ASSERT && curr < prev) 34 | throw new AssertionError("not sorted"); 35 | prev = curr; 36 | } 37 | } 38 | 39 | @Override 40 | public long[] valueArrayDeserialize(DataInput2 in, int size) throws IOException { 41 | return in.unpackLongArrayDeltaCompression(size); 42 | } 43 | 44 | 45 | @Override 46 | public Long valueArrayBinaryGet(DataInput2 input, int keysLen, int pos) throws IOException { 47 | long a = 0; 48 | while (pos-- >= 0) { 49 | a += input.unpackLong(); 50 | } 51 | return a; 52 | } 53 | 54 | @Override 55 | public int valueArrayBinarySearch(Long key, DataInput2 input, int keysLen, Comparator comparator) throws IOException { 56 | if (comparator != this) 57 | return super.valueArrayBinarySearch(key, input, keysLen, comparator); 58 | long key2 = key; 59 | long from = 0; 60 | for (int pos = 0; pos < keysLen; pos++) { 61 | from += input.unpackLong(); 62 | 63 | if (key2 <= from) { 64 | input.unpackLongSkip(keysLen-pos-1); 65 | return (key2 == from) ? pos : -(pos + 1); 66 | } 67 | } 68 | 69 | //not found 70 | return -(keysLen + 1); 71 | } 72 | 73 | 74 | @Override 75 | public int fixedSize() { 76 | return -1; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/GroupSerializer.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Comparator; 9 | 10 | /** 11 | * Created by jan on 2/29/16. 12 | */ 13 | public interface GroupSerializer extends Serializer { 14 | 15 | default A valueArrayBinaryGet(DataInput2 input, int keysLen, int pos) throws IOException { 16 | Object keys = valueArrayDeserialize(input, keysLen); 17 | return valueArrayGet(keys, pos); 18 | // A a=null; 19 | // while(pos-- >= 0){ 20 | // a = deserialize(input, -1); 21 | // } 22 | // return a; 23 | } 24 | 25 | 26 | 27 | default int valueArrayBinarySearch(A key, DataInput2 input, int keysLen, Comparator comparator) throws IOException { 28 | Object keys = valueArrayDeserialize(input, keysLen); 29 | return valueArraySearch(keys, key, comparator); 30 | // for(int pos=0; pos= 0) { 56 | a += input.unpackInt(); 57 | } 58 | return a; 59 | } 60 | 61 | 62 | @Override 63 | public int valueArrayBinarySearch(Integer key, DataInput2 input, int keysLen, Comparator comparator) throws IOException { 64 | if (comparator != this) 65 | return super.valueArrayBinarySearch(key, input, keysLen, comparator); 66 | int key2 = key; 67 | int from = 0; 68 | for (int pos = 0; pos < keysLen; pos++) { 69 | from += input.unpackInt(); 70 | 71 | if (key2 <= from) { 72 | input.unpackLongSkip(keysLen-pos-1); 73 | return (key2 == from) ? pos : -(pos + 1); 74 | } 75 | } 76 | 77 | //not found 78 | return -(keysLen + 1); 79 | } 80 | 81 | @Override 82 | public int fixedSize() { 83 | return -1; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/GroupSerializerObjectArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataIO; 4 | import org.mapdb.DataInput2; 5 | import org.mapdb.DataOutput2; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | 11 | /** 12 | * Created by jan on 2/29/16. 13 | */ 14 | public abstract class GroupSerializerObjectArray implements GroupSerializer { 15 | 16 | 17 | @Override public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 18 | for(Object o:(Object[])vals){ 19 | serialize(out, (A) o); 20 | } 21 | } 22 | 23 | @Override public Object[] valueArrayDeserialize(DataInput2 in, int size) throws IOException { 24 | Object[] ret = new Object[size]; 25 | for(int i=0;i)this); 68 | } 69 | 70 | @Override public Object[] valueArrayToArray(Object vals){ 71 | return (Object[]) vals; 72 | } 73 | @Override public int valueArraySearch(Object keys, A key, Comparator comparator){ 74 | if(comparator==this) 75 | return valueArraySearch(keys, key); 76 | return Arrays.binarySearch((Object[])keys, key, comparator); 77 | } 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerUtils.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.Serializer; 4 | 5 | import java.util.HashMap; 6 | 7 | import org.mapdb.Serializer; 8 | import static org.mapdb.Serializer.*; 9 | 10 | import java.math.BigDecimal; 11 | import java.math.BigInteger; 12 | import java.util.*; 13 | 14 | /** 15 | * Created by jan on 2/28/16. 16 | */ 17 | public final class SerializerUtils { 18 | 19 | private static Map SERIALIZER_FOR_CLASS = new HashMap(); 20 | 21 | static { 22 | SERIALIZER_FOR_CLASS.put(char.class, CHAR); 23 | SERIALIZER_FOR_CLASS.put(Character.class, CHAR); 24 | SERIALIZER_FOR_CLASS.put(String.class, STRING); 25 | SERIALIZER_FOR_CLASS.put(long.class, LONG); 26 | SERIALIZER_FOR_CLASS.put(Long.class, LONG); 27 | SERIALIZER_FOR_CLASS.put(int.class, INTEGER); 28 | SERIALIZER_FOR_CLASS.put(Integer.class, INTEGER); 29 | SERIALIZER_FOR_CLASS.put(boolean.class, BOOLEAN); 30 | SERIALIZER_FOR_CLASS.put(Boolean.class, BOOLEAN); 31 | SERIALIZER_FOR_CLASS.put(byte[].class, BYTE_ARRAY); 32 | SERIALIZER_FOR_CLASS.put(char[].class, CHAR_ARRAY); 33 | SERIALIZER_FOR_CLASS.put(int[].class, INT_ARRAY); 34 | SERIALIZER_FOR_CLASS.put(long[].class, LONG_ARRAY); 35 | SERIALIZER_FOR_CLASS.put(double[].class, DOUBLE_ARRAY); 36 | SERIALIZER_FOR_CLASS.put(UUID.class, UUID); 37 | SERIALIZER_FOR_CLASS.put(byte.class, BYTE); 38 | SERIALIZER_FOR_CLASS.put(Byte.class, BYTE); 39 | SERIALIZER_FOR_CLASS.put(float.class, FLOAT); 40 | SERIALIZER_FOR_CLASS.put(Float.class, FLOAT); 41 | SERIALIZER_FOR_CLASS.put(double.class, DOUBLE); 42 | SERIALIZER_FOR_CLASS.put(Double.class, DOUBLE); 43 | SERIALIZER_FOR_CLASS.put(short.class, SHORT); 44 | SERIALIZER_FOR_CLASS.put(Short.class, SHORT); 45 | SERIALIZER_FOR_CLASS.put(short[].class, SHORT_ARRAY); 46 | SERIALIZER_FOR_CLASS.put(float[].class, FLOAT_ARRAY); 47 | SERIALIZER_FOR_CLASS.put(BigDecimal.class, BIG_DECIMAL); 48 | SERIALIZER_FOR_CLASS.put(BigInteger.class, BIG_INTEGER); 49 | SERIALIZER_FOR_CLASS.put(Class.class, CLASS); 50 | SERIALIZER_FOR_CLASS.put(Date.class, DATE); 51 | 52 | } 53 | 54 | 55 | public static Serializer serializerForClass(Class clazz){ 56 | return SERIALIZER_FOR_CLASS.get(clazz); 57 | } 58 | 59 | public static int compareInt(int x, int y) { 60 | return (x < y) ? -1 : ((x == y) ? 0 : 1); 61 | } 62 | 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/SortedTableMap_ConcurrentSkipListSubMapTest_JSR166Test.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.runner.RunWith 4 | import org.junit.runners.Parameterized 5 | import org.mapdb.jsr166Tests.ConcurrentSkipListSubMapTest 6 | import org.mapdb.jsr166Tests.JSR166Test 7 | import org.mapdb.jsr166Tests.JSR166TestCase 8 | import java.util.concurrent.ConcurrentNavigableMap 9 | 10 | class SortedTableMap_ConcurrentSkipListSubMapTest_JSR166Test() 11 | : ConcurrentSkipListSubMapTest() 12 | { 13 | 14 | 15 | protected override fun map5(): ConcurrentNavigableMap<*, *>? { 16 | val consumer = SortedTableMap.createFromSink( 17 | keySerializer = Serializer.INTEGER, 18 | valueSerializer = Serializer.STRING_INTERN, 19 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false)) 20 | consumer.put(Pair(JSR166Test.zero, "Z")) 21 | consumer.put(Pair(JSR166Test.one, "A")) 22 | consumer.put(Pair(JSR166Test.two, "B")) 23 | consumer.put(Pair(JSR166Test.three, "C")) 24 | consumer.put(Pair(JSR166Test.four, "D")) 25 | consumer.put(Pair(JSR166Test.five, "E")) 26 | consumer.put(Pair(JSR166Test.seven, "F")) 27 | 28 | val map = consumer.create() 29 | assertFalse(map.isEmpty()) 30 | assertEquals(7, map.size.toLong()) 31 | return map.subMap(JSR166Test.one, true, JSR166Test.seven, false) 32 | } 33 | 34 | protected override fun dmap5(): ConcurrentNavigableMap<*, *>? { 35 | val consumer = SortedTableMap.createFromSink( 36 | keySerializer = Serializer.INTEGER, 37 | valueSerializer = Serializer.STRING_INTERN, 38 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false)) 39 | consumer.put(Pair(JSR166Test.m5, "E")) 40 | consumer.put(Pair(JSR166Test.m4, "D")) 41 | consumer.put(Pair(JSR166Test.m3, "C")) 42 | consumer.put(Pair(JSR166Test.m2, "B")) 43 | consumer.put(Pair(JSR166Test.m1, "A")) 44 | 45 | val map = consumer.create().descendingMap() 46 | assertFalse(map.isEmpty()) 47 | assertEquals(5, map.size.toLong()) 48 | return map 49 | } 50 | 51 | 52 | override fun emptyMap(): ConcurrentNavigableMap? { 53 | return SortedTableMap.createFromSink( 54 | keySerializer = Serializer.INTEGER, 55 | valueSerializer = Serializer.STRING_INTERN, 56 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false)) 57 | .create() 58 | } 59 | 60 | 61 | override protected fun isReadOnly(): Boolean { 62 | return true 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/CC.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import net.jpountz.xxhash.XXHashFactory; 4 | import org.mapdb.volume.ByteArrayVol; 5 | import org.mapdb.volume.RandomAccessFileVol; 6 | import org.mapdb.volume.VolumeFactory; 7 | 8 | /** 9 | * Compilation Configuration. Uses dead code elimination to remove `if(CONSTANT){code}` blocks 10 | */ 11 | public interface CC{ 12 | 13 | boolean LOG = true; 14 | 15 | /** compile MapDB with assertions enabled */ 16 | boolean ASSERT = true; 17 | /** compile MapDB with paranoid mode enabled */ 18 | boolean PARANOID = false; 19 | 20 | boolean ZEROS = false; 21 | 22 | boolean FAIR_LOCK = true; 23 | 24 | int PAGE_SHIFT = 20; // 1 MB 25 | long PAGE_SIZE = 1< extends SerializerArray { 13 | 14 | private static final long serialVersionUID = -930920902390439234L; 15 | 16 | 17 | public SerializerArrayDelta(Serializer serializer) { 18 | super(serializer); 19 | } 20 | 21 | @Override 22 | public void valueArraySerialize(DataOutput2 out, Object vals2) throws IOException { 23 | Object[] vals = (Object[]) vals2; 24 | if (vals.length == 0) 25 | return; 26 | //write first array 27 | Object[] prevKey = (Object[]) vals[0]; 28 | out.packInt(prevKey.length); 29 | for (Object key : prevKey) { 30 | serializer.serialize(out, (T) key); 31 | } 32 | 33 | //write remaining arrays 34 | for (int i = 1; i < vals.length; i++) { 35 | Object[] key = (Object[]) vals[i]; 36 | //calculate number of entries equal with prevKey 37 | int len = Math.min(key.length, prevKey.length); 38 | int pos = 0; 39 | while (pos < len && (key[pos] == prevKey[pos] || serializer.equals((T) key[pos], (T) prevKey[pos]))) { 40 | pos++; 41 | } 42 | out.packInt(pos); 43 | //write remaining bytes 44 | out.packInt(key.length - pos); 45 | for (; pos < key.length; pos++) { 46 | serializer.serialize(out, (T) key[pos]); 47 | } 48 | prevKey = key; 49 | } 50 | 51 | } 52 | 53 | @Override 54 | public Object[] valueArrayDeserialize(DataInput2 in, final int size) throws IOException { 55 | Object[] ret = new Object[size]; 56 | if (size == 0) 57 | return ret; 58 | int ss = in.unpackInt(); 59 | Object[] prevKey = new Object[ss]; 60 | for (int i = 0; i < ss; i++) { 61 | prevKey[i] = serializer.deserialize(in, -1); 62 | } 63 | ret[0] = prevKey; 64 | for (int i = 1; i < size; i++) { 65 | //number of items shared with prev 66 | int shared = in.unpackInt(); 67 | //number of items unique to this array 68 | int unq = in.unpackInt(); 69 | Object[] key = new Object[shared + unq]; 70 | //copy items from prev array 71 | System.arraycopy(prevKey, 0, key, 0, shared); 72 | //and read rest 73 | for (; shared < key.length; shared++) { 74 | key[shared] = serializer.deserialize(in, -1); 75 | } 76 | ret[i] = key; 77 | prevKey = key; 78 | } 79 | return ret; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/volume/VolumeSyncCrashTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet 4 | import org.junit.Ignore 5 | import org.junit.Test 6 | import org.junit.runner.RunWith 7 | import org.junit.runners.Parameterized 8 | import java.io.File 9 | import java.util.* 10 | import org.junit.Assert.* 11 | import org.mapdb.DataIO 12 | import org.mapdb.crash.CrashJVM 13 | import org.mapdb.volume.* 14 | 15 | /** 16 | * Checks if [Volume.sync()] really flushes disk cache, it should survive JVM crash... 17 | */ 18 | abstract class VolumeSyncCrashTest(val volfab: VolumeFactory) : CrashJVM(){ 19 | 20 | class RAF : VolumeSyncCrashTest(RandomAccessFileVol.FACTORY) 21 | class FileChan : VolumeSyncCrashTest(FileChannelVol.FACTORY) 22 | class MMAP : VolumeSyncCrashTest(MappedFileVol.FACTORY) 23 | 24 | val fileSize = 4 * 1024*1024 25 | val writeValues = 100; 26 | 27 | 28 | fun fileForSeed(seed:Long) = getTestDir().toString()+"/"+seed; 29 | 30 | override fun doInJVM(startSeed: Long, params: String) { 31 | var seed = startSeed 32 | while(true){ 33 | seed++ 34 | val vol = volfab.makeVolume(fileForSeed(seed), false) 35 | vol.ensureAvailable(fileSize.toLong()) 36 | startSeed(seed) 37 | val random = Random(seed) 38 | val used = LongHashSet(); 39 | for(i in 0 until writeValues){ 40 | val offset = DataIO.roundDown(random.nextInt(fileSize - 8 ),8).toLong() 41 | 42 | if(!used.add(offset)) 43 | continue; 44 | val value = random.nextLong(); 45 | vol.putLong(offset, value); 46 | } 47 | vol.sync() 48 | commitSeed(seed) 49 | //delete prev file to keep disk space usage low 50 | File(fileForSeed(seed - 1)).delete() 51 | } 52 | } 53 | 54 | override fun verifySeed(startSeed: Long, endSeed: Long, params: String): Long { 55 | if(endSeed==-1L) 56 | return startSeed+10; 57 | 58 | val file = fileForSeed(endSeed); 59 | val vol = volfab.makeVolume(file, true) 60 | 61 | val random = Random(endSeed) 62 | val used = LongHashSet(); 63 | for(i in 0 until writeValues){ 64 | val offset = DataIO.roundDown(random.nextInt(fileSize - 8 ),8).toLong() 65 | if(!used.add(offset)) 66 | continue; 67 | val value = random.nextLong(); 68 | assertEquals(value, vol.getLong(offset)); 69 | } 70 | 71 | vol.close() 72 | 73 | //delete old data 74 | getTestDir().listFiles().filter{ it.isFile }.forEach { it.delete() } 75 | 76 | return endSeed+10 77 | } 78 | 79 | @Test 80 | fun run(){ 81 | CrashJVM.Companion.run(this, time = org.mapdb.TT.testRuntime(10)) 82 | } 83 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/AtomicStringTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import junit.framework.TestCase; 4 | 5 | public class AtomicStringTest extends TestCase { 6 | 7 | DB db; 8 | Atomic.String ai; 9 | 10 | 11 | @Override 12 | protected void setUp() throws Exception { 13 | db = DBMaker.memoryDB().make(); 14 | ai = db.atomicString("test", "test").create(); 15 | } 16 | 17 | @Override 18 | protected void tearDown() throws Exception { 19 | db.close(); 20 | } 21 | 22 | 23 | /* 24 | * constructor initializes to given value 25 | */ 26 | public void testConstructor() { 27 | assertEquals("test", ai.get()); 28 | } 29 | 30 | /* 31 | * default constructed initializes to empty string 32 | */ 33 | public void testConstructor2() { 34 | Atomic.String ai = db.atomicString("test2").create(); 35 | assertEquals(null, ai.get()); 36 | } 37 | 38 | /* 39 | * get returns the last value set 40 | */ 41 | public void testGetSet() { 42 | assertEquals("test", ai.get()); 43 | ai.set("test2"); 44 | assertEquals("test2", ai.get()); 45 | ai.set("test3"); 46 | assertEquals("test3", ai.get()); 47 | 48 | } 49 | 50 | /* 51 | * compareAndSet succeeds in changing value if equal to expected else fails 52 | */ 53 | public void testCompareAndSet(){ 54 | assertTrue(ai.compareAndSet("test", "test2")); 55 | assertTrue(ai.compareAndSet("test2", "test3")); 56 | assertEquals("test3", ai.get()); 57 | assertFalse(ai.compareAndSet("test2", "test4")); 58 | assertNotSame("test5", ai.get()); 59 | assertTrue(ai.compareAndSet("test3", "test5")); 60 | assertEquals("test5", ai.get()); 61 | } 62 | 63 | /* 64 | * compareAndSet in one thread enables another waiting for value 65 | * to succeed 66 | */ 67 | public void testCompareAndSetInMultipleThreads() throws InterruptedException { 68 | Thread t = new Thread(new Runnable() { 69 | public void run() { 70 | while(!ai.compareAndSet("test2", "test3")) Thread.yield(); 71 | }}); 72 | 73 | t.start(); 74 | assertTrue(ai.compareAndSet("test", "test2")); 75 | t.join(0); 76 | assertFalse(t.isAlive()); 77 | assertEquals(ai.get(), "test3"); 78 | } 79 | 80 | /* 81 | * getAndSet returns previous value and sets to given value 82 | */ 83 | public void testGetAndSet(){ 84 | assertEquals("test", ai.getAndSet("test2")); 85 | assertEquals("test2", ai.getAndSet("test3")); 86 | assertEquals("test3", ai.getAndSet("test4")); 87 | } 88 | 89 | /* 90 | * toString returns current value. 91 | */ 92 | public void testToString() { 93 | assertEquals(ai.toString(), ai.get()); 94 | assertEquals(ai.toString(), "test"); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/AtomicVarTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import junit.framework.TestCase; 4 | 5 | public class AtomicVarTest extends TestCase { 6 | 7 | DB db; 8 | Atomic.Var ai; 9 | 10 | 11 | @Override 12 | protected void setUp() throws Exception { 13 | db = DBMaker.memoryDB().make(); 14 | ai = db.atomicVar("test", Serializer.STRING, "test").create(); 15 | } 16 | 17 | @Override 18 | protected void tearDown() throws Exception { 19 | db.close(); 20 | } 21 | 22 | 23 | /* 24 | * constructor initializes to given value 25 | */ 26 | public void testConstructor() { 27 | assertEquals("test", ai.get()); 28 | } 29 | 30 | /* 31 | * default constructed initializes to empty string 32 | */ 33 | public void testConstructor2() { 34 | Atomic.Var ai = db.atomicVar("test2", Serializer.STRING).create(); 35 | assertEquals(null, ai.get()); 36 | } 37 | 38 | /* 39 | * get returns the last value set 40 | */ 41 | public void testGetSet() { 42 | assertEquals("test", ai.get()); 43 | ai.set("test2"); 44 | assertEquals("test2", ai.get()); 45 | ai.set("test3"); 46 | assertEquals("test3", ai.get()); 47 | 48 | } 49 | 50 | /* 51 | * compareAndSet succeeds in changing value if equal to expected else fails 52 | */ 53 | public void testCompareAndSet(){ 54 | assertTrue(ai.compareAndSet("test", "test2")); 55 | assertTrue(ai.compareAndSet("test2", "test3")); 56 | assertEquals("test3", ai.get()); 57 | assertFalse(ai.compareAndSet("test2", "test4")); 58 | assertNotSame("test5", ai.get()); 59 | assertTrue(ai.compareAndSet("test3", "test5")); 60 | assertEquals("test5", ai.get()); 61 | } 62 | 63 | /* 64 | * compareAndSet in one thread enables another waiting for value 65 | * to succeed 66 | */ 67 | public void testCompareAndSetInMultipleThreads() throws InterruptedException { 68 | Thread t = new Thread(new Runnable() { 69 | public void run() { 70 | while(!ai.compareAndSet("test2", "test3")) Thread.yield(); 71 | }}); 72 | 73 | t.start(); 74 | assertTrue(ai.compareAndSet("test", "test2")); 75 | t.join(0); 76 | assertFalse(t.isAlive()); 77 | assertEquals(ai.get(), "test3"); 78 | } 79 | 80 | /* 81 | * getAndSet returns previous value and sets to given value 82 | */ 83 | public void testGetAndSet(){ 84 | assertEquals("test", ai.getAndSet("test2")); 85 | assertEquals("test2", ai.getAndSet("test3")); 86 | assertEquals("test3", ai.getAndSet("test4")); 87 | } 88 | 89 | /* 90 | * toString returns current value. 91 | */ 92 | public void testToString() { 93 | assertEquals(ai.toString(), ai.get()); 94 | assertEquals(ai.toString(), "test"); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/IndexTreeListJavaTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | import java.io.IOException 6 | import java.nio.ByteBuffer 7 | import java.util.* 8 | 9 | class IndexTreeListJavaTest{ 10 | 11 | internal fun swap(d: DataOutput2): DataInput2.ByteBuffer { 12 | val b = d.copyBytes() 13 | return DataInput2.ByteBuffer(ByteBuffer.wrap(b), 0) 14 | } 15 | 16 | 17 | @Test 18 | fun testDirSerializer() { 19 | var dir = IndexTreeListJava.dirEmpty() 20 | 21 | var slot = 1 22 | while (slot < 127) { 23 | dir = IndexTreeListJava.dirPut(dir, slot, slot * 1111L, slot*2222L) 24 | slot += 1 + slot / 5 25 | } 26 | 27 | val out = DataOutput2() 28 | IndexTreeListJava.dirSer.serialize(out, dir) 29 | 30 | val input = swap(out) 31 | val dir2 = IndexTreeListJava.dirSer.deserialize(input, -1); 32 | assertTrue(Arrays.equals(dir, dir2)) 33 | 34 | slot = 1 35 | while (slot < 127) { 36 | val offset = IndexTreeListJava.dirOffsetFromSlot(dir, slot) 37 | assertEquals(slot * 1111L, dir[offset]) 38 | assertEquals(slot * 2222L, dir[offset+1]) 39 | slot += 1 + slot / 5 40 | } 41 | } 42 | 43 | @Test fun delete_notcollapsesNode(){ 44 | val dir = IndexTreeListJava.dirEmpty(); 45 | val store =StoreTrivial() 46 | val root = store.put(dir, IndexTreeListJava.dirSer) 47 | 48 | assertEquals(1, store.getAllRecids().asSequence().count()) 49 | 50 | //single element without expansion 51 | IndexTreeListJava.treePut(4,root, store,3, 1L, 111L) 52 | assertEquals(1, store.getAllRecids().asSequence().count()) 53 | 54 | //extra element near will expand all four levels 55 | IndexTreeListJava.treePut(4,root, store,3, 2L, 222L) 56 | assertEquals(4, store.getAllRecids().asSequence().count()) 57 | 58 | //remove element, that should collapse nodes 59 | IndexTreeListJava.treeRemove(4,root,store, 3, 2L, null) 60 | assertEquals(4, store.getAllRecids().asSequence().count()) 61 | } 62 | 63 | 64 | @Test fun delete_collapsesNode(){ 65 | val dir = IndexTreeListJava.dirEmpty(); 66 | val store =StoreTrivial() 67 | val root = store.put(dir, IndexTreeListJava.dirSer) 68 | 69 | assertEquals(1, store.getAllRecids().asSequence().count()) 70 | 71 | //single element without expansion 72 | IndexTreeListJava.treePut(4,root, store,3, 1L, 111L) 73 | assertEquals(1, store.getAllRecids().asSequence().count()) 74 | 75 | //extra element near will expand all four levels 76 | IndexTreeListJava.treePut(4,root, store,3, 2L, 222L) 77 | assertEquals(4, store.getAllRecids().asSequence().count()) 78 | 79 | //remove element, that should collapse nodes 80 | IndexTreeListJava.treeRemoveCollapsing(4,root,store, 3, true, 2L, null) 81 | assertEquals(1, store.getAllRecids().asSequence().count()) 82 | 83 | } 84 | 85 | 86 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | MapDB: database engine 4 | ======================= 5 | [![Build Status](https://travis-ci.org/jankotek/mapdb.svg?branch=master)](https://travis-ci.org/jankotek/mapdb) 6 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.mapdb/mapdb/badge.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.mapdb%22%20AND%20a%3Amapdb) 7 | [![Join the chat at https://gitter.im/jankotek/mapdb](https://badges.gitter.im/jankotek/mapdb.svg)](https://gitter.im/jankotek/mapdb?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 8 | 9 | 10 | MapDB combines embedded database engine and Java collections. 11 | It is free under Apache 2 license. MapDB is flexible and can be used in many roles: 12 | 13 | * Drop-in replacement for Maps, Lists, Queues and other collections. 14 | * Off-heap collections not affected by Garbage Collector 15 | * Multilevel cache with expiration and disk overflow. 16 | * RDBMs replacement with transactions, MVCC, incremental backups etc… 17 | * Local data processing and filtering. MapDB has utilities to process huge quantities of data in reasonable time. 18 | 19 | Hello world 20 | ------------------- 21 | 22 | Maven snippet, VERSION is [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.mapdb/mapdb/badge.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.mapdb%22%20AND%20a%3Amapdb) 23 | 24 | 25 | org.mapdb 26 | mapdb 27 | VERSION 28 | 29 | 30 | 31 | Hello world: 32 | 33 | //import org.mapdb.* 34 | DB db = DBMaker.memoryDB().make(); 35 | ConcurrentMap map = db.hashMap("map").make(); 36 | map.put("something", "here"); 37 | 38 | Continue at [Quick Start](http://www.mapdb.org/doc/quick-start/) or at [Documentation](http://www.mapdb.org/doc/). 39 | 40 | Support 41 | ------------ 42 | 43 | More [details](http://www.mapdb.org/support/). 44 | 45 | Development 46 | -------------------- 47 | 48 | MapDB is written in Kotlin. You will need Intellij Idea 15 Community Edition to edit it. 49 | 50 | Use Maven to build MapDB: `mvn install` 51 | 52 | You might experience problem with `mapdb-jcache-tck-test` module. 53 | It expects ``mapdb-jcache`` module to be already installed in local maven repo. 54 | Source code module dependency does not work. To run all tests use command: `mvn install test` 55 | 56 | MapDB comes with extensive unit tests, by default only tiny fraction is executed, so build finishes under 10 minutes. 57 | Full test suite has over million test cases and runs several hours/days. 58 | To run full test suite set `-Dmdbtest=1` property. 59 | It is recommended to run tests in parallel: `-DthreadCount=16`. 60 | It is also possible to override temporary folder with `-Djava.io.tmpdir=/path` directive. 61 | 62 | An example to run full acceptance tests: 63 | 64 | ``` 65 | mvn clean install test -Dmdbtest=1 -DthreadCount=16 -Djava.io.tmpdir=/mnt/big 66 | ``` 67 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/volume/VolumeCrashTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.volume 2 | 3 | import org.eclipse.collections.impl.set.mutable.primitive.LongHashSet 4 | import org.junit.Test 5 | import java.io.File 6 | import java.io.RandomAccessFile 7 | import java.util.* 8 | import org.junit.Assert.* 9 | import org.mapdb.CC 10 | import org.mapdb.crash.CrashJVM 11 | import org.mapdb.DataIO 12 | import org.mapdb.TT 13 | 14 | 15 | class VolumeCrashTest(): CrashJVM(){ 16 | val fabs = mapOf>( 17 | Pair("fileChannel",{file -> FileChannelVol(File(file), false, 0L, CC.PAGE_SHIFT, 0L)}), 18 | Pair("raf",{file -> RandomAccessFileVol(File(file), false, 0L, 0L) }), 19 | Pair("mapped",{file -> MappedFileVol(File(file), false, 0L, CC.PAGE_SHIFT, false, 0L, false) }), 20 | Pair("mappedSingle",{file -> MappedFileVolSingle(File(file), false, 0L, 4e7.toLong(), false) }) 21 | ) 22 | 23 | val max = 4*1024*1024 24 | val count = 100; 25 | fun fileForSeed(seed:Long) = getTestDir().toString()+"/"+seed; 26 | 27 | override fun doInJVM(startSeed: Long, params: String) { 28 | var seed = startSeed 29 | while (true) { 30 | seed++ 31 | val file = fileForSeed(seed) 32 | val v = fabs[params]!!(file); 33 | v.ensureAvailable(max.toLong()) 34 | 35 | val random = Random(seed) 36 | val alreadyWritten = LongHashSet(); 37 | for(i in 0 until count) { 38 | val offset = DataIO.roundDown(random.nextInt(max-8).toLong(),8) 39 | if(!alreadyWritten.add(offset)) 40 | continue 41 | v.putLong(offset, random.nextLong()) 42 | } 43 | v.sync() 44 | v.close() 45 | commitSeed(seed) 46 | //delete prev file to keep disk space usage low 47 | File(fileForSeed(seed - 1)).delete() 48 | 49 | } 50 | } 51 | 52 | override fun verifySeed(startSeed: Long, endSeed: Long, params: String): Long { 53 | val file = fileForSeed(endSeed) 54 | val raf = RandomAccessFile(file, "r") 55 | assertTrue(raf.length()>=8) 56 | val random = Random(endSeed) 57 | val alreadyWritten = LongHashSet(); 58 | for(i in 0 until count) { 59 | val offset = DataIO.roundDown(random.nextInt(max-8).toLong(),8) 60 | if(!alreadyWritten.add(offset)) 61 | continue 62 | raf.seek(offset) 63 | assertEquals(random.nextLong(), raf.readLong()) 64 | } 65 | 66 | 67 | raf.close() 68 | return endSeed+10 69 | } 70 | 71 | @Test 72 | fun fileChannel() { 73 | run(this, time = TT.testRuntime(10), params="fileChannel") 74 | } 75 | 76 | @Test 77 | fun raf() { 78 | run(this, time = TT.testRuntime(10), params="raf") 79 | } 80 | 81 | @Test 82 | fun mapped() { 83 | run(this, time = TT.testRuntime(10), params="mapped") 84 | } 85 | 86 | @Test 87 | fun mappedSingle() { 88 | run(this, time = TT.testRuntime(10), params="mappedSingle") 89 | } 90 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/issues/ParallelMaps.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb.issues 2 | 3 | import java.util.stream.IntStream 4 | 5 | import org.junit.Test 6 | 7 | import org.junit.Assert.assertEquals 8 | import org.mapdb.* 9 | import java.io.Closeable 10 | import java.util.* 11 | import org.mapdb.DBMaker.StoreType.* 12 | 13 | @org.junit.runner.RunWith(org.junit.runners.Parameterized::class) 14 | class ParallelMaps(val fab:()-> MutableMap) { 15 | 16 | companion object { 17 | 18 | @org.junit.runners.Parameterized.Parameters 19 | @JvmStatic 20 | fun params(): Iterable { 21 | val ret = ArrayList() 22 | val bools = booleanArrayOf(true, false) 23 | 24 | for(store in DBMaker.StoreType.values()) 25 | for(intSer in bools) 26 | for(counter in bools) 27 | for(externalVals in bools) { 28 | 29 | val db = {when (store) { 30 | fileMMap -> DBMaker.tempFileDB().fileMmapEnable() 31 | fileRaf -> DBMaker.tempFileDB() 32 | fileChannel -> DBMaker.tempFileDB().fileChannelEnable() 33 | onheap -> DBMaker.heapDB() 34 | bytearray -> DBMaker.memoryDB() 35 | directbuffer -> DBMaker.memoryDirectDB() 36 | }.make()} 37 | 38 | // hashMap 39 | ret.add({ 40 | var maker = db().hashMap("aa") 41 | if(intSer) 42 | maker.keySerializer(Serializer.INTEGER).valueSerializer(Serializer.INTEGER) 43 | if(counter) 44 | maker.counterEnable() 45 | maker.create() 46 | }) 47 | for(nodeSize in intArrayOf(4,6,12,32,128,1024)){ 48 | ret.add({ 49 | var maker = db().treeMap("map").maxNodeSize(nodeSize) 50 | if(intSer) 51 | maker.keySerializer(Serializer.INTEGER).valueSerializer(Serializer.INTEGER) 52 | if(counter) 53 | maker.counterEnable() 54 | maker.create() 55 | }) 56 | } 57 | 58 | } 59 | return ret.map{arrayOf(it)} 60 | } 61 | } 62 | 63 | @Test 64 | fun main() { 65 | if (TT.shortTest()) 66 | return 67 | 68 | for (i in 0..99) { 69 | testing() 70 | } 71 | } 72 | 73 | private fun testing() { 74 | 75 | val tmp = fab(); 76 | 77 | if(tmp is ConcurrencyAware) 78 | tmp.checkThreadSafe() 79 | 80 | val size = 1000 81 | IntStream.rangeClosed(1, size).parallel().forEach { i -> tmp.put(i, 11) } 82 | 83 | assertEquals(size, tmp.size) 84 | 85 | if(tmp is Verifiable) 86 | tmp.verify() 87 | if(tmp is BTreeMap) 88 | tmp.store.verify() 89 | if(tmp is HTreeMap) 90 | tmp.stores.toSet().forEach { it.verify() } 91 | 92 | if(tmp is Closeable) 93 | tmp.close() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/BrokenDBTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.* 4 | import org.mapdb.volume.RandomAccessFileVol 5 | import org.mapdb.volume.Volume 6 | 7 | import java.io.* 8 | import java.util.Arrays 9 | 10 | class BrokenDBTest { 11 | internal var index: File? = null 12 | internal var log: File? = null 13 | 14 | @Before 15 | @Throws(IOException::class) 16 | fun before() { 17 | index = TT.tempFile() 18 | log = File(index!!.path + "wal.0") 19 | } 20 | 21 | /* 22 | * Verify that DB files are properly closed when opening the database fails, allowing an 23 | * application to recover by purging the database and starting over. 24 | * 25 | * @throws FileNotFoundException 26 | * @throws IOException 27 | */ 28 | @Test 29 | @Throws(FileNotFoundException::class, IOException::class) 30 | fun canDeleteDBOnBrokenIndex() { 31 | for (f in Arrays.asList(index, log)) { 32 | val fos = FileOutputStream(f) 33 | fos.write("Some Junk".toByteArray()) 34 | fos.close() 35 | } 36 | 37 | try { 38 | DBMaker.fileDB(index!!).make() 39 | Assert.fail("Expected exception not thrown") 40 | } catch (e: DBException.WrongFormat) { 41 | // will fail! 42 | Assert.assertTrue("Wrong message", e.message!!.contains("Wrong file header, not MapDB file")) 43 | } 44 | 45 | index!!.delete() 46 | log!!.delete() 47 | 48 | // assert that we can delete the db files 49 | Assert.assertFalse("Can't delete index", index!!.exists()) 50 | Assert.assertFalse("Can't delete log", log!!.exists()) 51 | } 52 | 53 | /* 54 | * Verify that DB files are properly closed when opening the database fails, allowing an 55 | * application to recover by purging the database and starting over. 56 | * 57 | * @throws FileNotFoundException 58 | * @throws IOException 59 | */ 60 | @Ignore //TODO header checksums @Test 61 | @Throws(IOException::class) 62 | fun canDeleteDBOnBrokenLog() { 63 | // init empty, but valid DB 64 | DBMaker.fileDB(index!!).make().close() 65 | 66 | // corrupt file 67 | val physVol = RandomAccessFileVol(index, false, 0L, 0L) 68 | physVol.ensureAvailable(32) 69 | physVol.putLong(16, 123456789L) 70 | physVol.sync() 71 | physVol.close() 72 | 73 | try { 74 | DBMaker.fileDB(index!!).make() 75 | Assert.fail("Expected exception not thrown") 76 | } catch (e: DBException.WrongFormat) { 77 | // expected 78 | } 79 | 80 | index!!.delete() 81 | log!!.delete() 82 | 83 | // assert that we can delete the db files 84 | Assert.assertFalse("Can't delete index", index!!.exists()) 85 | Assert.assertFalse("Can't delete log", log!!.exists()) 86 | } 87 | 88 | @After 89 | @Throws(IOException::class) 90 | fun after() { 91 | if (index != null) 92 | index!!.deleteOnExit() 93 | if (log != null) 94 | log!!.deleteOnExit() 95 | } 96 | 97 | 98 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/DBBrokenTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import org.junit.*; 4 | import org.mapdb.volume.RandomAccessFileVol; 5 | import org.mapdb.volume.Volume; 6 | 7 | import java.io.*; 8 | import java.util.Arrays; 9 | 10 | 11 | public class DBBrokenTest { 12 | File index; 13 | File log; 14 | 15 | @Before 16 | public void before() throws IOException { 17 | index = TT.tempFile(); 18 | log = new File(index.getPath() + "wal.0"); 19 | } 20 | 21 | /* 22 | * Verify that DB files are properly closed when opening the database fails, allowing an 23 | * application to recover by purging the database and starting over. 24 | * 25 | * @throws FileNotFoundException 26 | * @throws IOException 27 | */ 28 | @Test 29 | @Ignore //TODO index checksum 30 | public void canDeleteDBOnBrokenIndex() throws IOException { 31 | for (final File f : Arrays.asList(index, log)) { 32 | final FileOutputStream fos = new FileOutputStream(f); 33 | fos.write("Some Junk".getBytes()); 34 | fos.close(); 35 | } 36 | 37 | try { 38 | DBMaker.fileDB(index.getPath()).make(); 39 | Assert.fail("Expected exception not thrown"); 40 | } catch (final DBException.WrongConfiguration e) { 41 | // will fail! 42 | Assert.assertTrue("Wrong message", e.getMessage().contains("This is not MapDB file")); 43 | } 44 | 45 | index.delete(); 46 | log.delete(); 47 | 48 | // assert that we can delete the db files 49 | Assert.assertFalse("Can't delete index", index.exists()); 50 | Assert.assertFalse("Can't delete log", log.exists()); 51 | } 52 | 53 | /* 54 | * Verify that DB files are properly closed when opening the database fails, allowing an 55 | * application to recover by purging the database and starting over. 56 | * 57 | * @throws FileNotFoundException 58 | * @throws IOException 59 | */ 60 | @Test 61 | @Ignore //TODO index checksum 62 | public void canDeleteDBOnBrokenLog() throws IOException { 63 | // init empty, but valid DB 64 | DBMaker.fileDB(index.getPath()).make().close(); 65 | 66 | // corrupt file 67 | Volume physVol = new RandomAccessFileVol(index, false, 0L, 0L); 68 | physVol.ensureAvailable(32); 69 | physVol.putLong(16, 123456789L); 70 | physVol.sync(); 71 | physVol.close(); 72 | 73 | try { 74 | DBMaker.fileDB(index.getPath()).make(); 75 | Assert.fail("Expected exception not thrown"); 76 | } catch (final DBException.WrongFormat e) { 77 | // expected 78 | } 79 | 80 | index.delete(); 81 | log.delete(); 82 | 83 | // assert that we can delete the db files 84 | Assert.assertFalse("Can't delete index", index.exists()); 85 | Assert.assertFalse("Can't delete log", log.exists()); 86 | } 87 | 88 | @After 89 | public void after() throws IOException { 90 | if (index != null) 91 | index.deleteOnExit(); 92 | if (log != null) 93 | log.deleteOnExit(); 94 | } 95 | 96 | 97 | 98 | } -------------------------------------------------------------------------------- /src/test/java/org/mapdb/AtomicBooleanTest.java: -------------------------------------------------------------------------------- 1 | package org.mapdb;/* 2 | * Written by Doug Lea with assistance from members of JCP JSR-166 3 | * Expert Group and released to the public domain, as explained at 4 | * http://creativecommons.org/licenses/publicdomain 5 | * Other contributors include Andrew Wright, Jeffrey Hayes, 6 | * Pat Fisher, Mike Judd. 7 | */ 8 | 9 | import junit.framework.TestCase; 10 | 11 | public class AtomicBooleanTest extends TestCase{ 12 | 13 | DB db; 14 | Atomic.Boolean ai; 15 | 16 | @Override 17 | protected void setUp() throws Exception { 18 | db = DBMaker.memoryDB().make(); 19 | ai= db.atomicBoolean("test", true).create(); 20 | } 21 | 22 | @Override 23 | protected void tearDown() throws Exception { 24 | db.close(); 25 | } 26 | 27 | 28 | /* 29 | * constructor initializes to given value 30 | */ 31 | public void testConstructor() { 32 | assertEquals(true,ai.get()); 33 | } 34 | 35 | /* 36 | * default constructed initializes to false 37 | */ 38 | public void testConstructor2() { 39 | Atomic.Boolean ai = db.atomicBoolean("test2").create(); 40 | assertEquals(false,ai.get()); 41 | } 42 | 43 | /* 44 | * get returns the last value set 45 | */ 46 | public void testGetSet() { 47 | 48 | assertEquals(true,ai.get()); 49 | ai.set(false); 50 | assertEquals(false,ai.get()); 51 | ai.set(true); 52 | assertEquals(true,ai.get()); 53 | 54 | } 55 | 56 | /* 57 | * compareAndSet succeeds in changing value if equal to expected else fails 58 | */ 59 | public void testCompareAndSet() { 60 | 61 | assertTrue(ai.compareAndSet(true,false)); 62 | assertEquals(false,ai.get()); 63 | assertTrue(ai.compareAndSet(false,false)); 64 | assertEquals(false,ai.get()); 65 | assertFalse(ai.compareAndSet(true,false)); 66 | assertFalse((ai.get())); 67 | assertTrue(ai.compareAndSet(false,true)); 68 | assertEquals(true,ai.get()); 69 | } 70 | 71 | /* 72 | * compareAndSet in one thread enables another waiting for value 73 | * to succeed 74 | */ 75 | public void testCompareAndSetInMultipleThreads() throws InterruptedException { 76 | Thread t = new Thread(new Runnable() { 77 | public void run() { 78 | while(!ai.compareAndSet(false, true)) Thread.yield(); 79 | }}); 80 | 81 | t.start(); 82 | assertTrue(ai.compareAndSet(true, false)); 83 | t.join(0); 84 | assertFalse(t.isAlive()); 85 | 86 | } 87 | 88 | /* 89 | * getAndSet returns previous value and sets to given value 90 | */ 91 | public void testGetAndSet() { 92 | assertEquals(true,ai.getAndSet(false)); 93 | assertEquals(false,ai.getAndSet(false)); 94 | assertEquals(false,ai.getAndSet(true)); 95 | assertEquals(true,ai.get()); 96 | } 97 | /* 98 | * toString returns current value. 99 | */ 100 | public void testToString() { 101 | Atomic.Boolean ai = db.atomicBoolean("test2").create(); 102 | assertEquals(ai.toString(), Boolean.toString(false)); 103 | ai.set(true); 104 | assertEquals(ai.toString(), Boolean.toString(true)); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/WALSequence.java: -------------------------------------------------------------------------------- 1 | package org.mapdb; 2 | 3 | import org.mapdb.volume.Volume; 4 | 5 | import java.util.LinkedList; 6 | 7 | import static org.junit.Assert.*; 8 | 9 | /** 10 | * Test if sequence is matching 11 | */ 12 | public class WALSequence implements WriteAheadLog.WALReplay { 13 | 14 | final java.util.LinkedList seq; 15 | 16 | 17 | 18 | static final String beforeReplayStart = "beforeReplayStart"; 19 | static final String writeLong = "writeLong"; 20 | static final String writeRecord = "writeRecord"; 21 | static final String writeByteArray = "writeByteArray"; 22 | static final String commit = "commit"; 23 | static final String rollback = "rollback"; 24 | static final String writeTombstone = "writeTombstone"; 25 | static final String writePreallocate = "writePreallocate"; 26 | 27 | public WALSequence(Object[]... params) { 28 | seq = new LinkedList(); 29 | for(Object[] p:params){ 30 | seq.add(p); 31 | } 32 | } 33 | 34 | @Override 35 | public void beforeReplayStart() { 36 | Object[] r = seq.remove(); 37 | assertEquals(beforeReplayStart, r[0]); 38 | assertEquals(1,r.length); 39 | } 40 | 41 | @Override 42 | public void writeLong(long offset, long value) { 43 | Object[] r = seq.remove(); 44 | assertEquals(writeLong, r[0]); 45 | assertEquals(offset,r[1]); 46 | assertEquals(value,r[2]); 47 | assertEquals(3,r.length); 48 | } 49 | 50 | @Override 51 | public void writeRecord(long recid, long walId, Volume vol, long volOffset, int length) { 52 | Object[] r = seq.remove(); 53 | 54 | byte[] data = new byte[length]; 55 | vol.getData(volOffset, data,0,data.length); 56 | 57 | assertEquals(writeRecord, r[0]); 58 | assertEquals(recid,r[1]); 59 | assertEquals(walId, r[2]); 60 | assertArrayEquals(data, (byte[]) r[3]); 61 | assertEquals(4,r.length); 62 | } 63 | 64 | @Override 65 | public void writeByteArray(long offset, long walId, Volume vol, long volOffset, int length) { 66 | Object[] r = seq.remove(); 67 | 68 | byte[] data = new byte[length]; 69 | vol.getData(volOffset, data,0,data.length); 70 | 71 | assertEquals(writeByteArray, r[0]); 72 | assertEquals(offset, r[1]); 73 | assertEquals(walId, r[2]); 74 | assertArrayEquals(data, (byte[]) r[3]); 75 | assertEquals(4,r.length); 76 | } 77 | 78 | @Override 79 | public void afterReplayFinished() { 80 | assertTrue(seq.isEmpty()); 81 | } 82 | 83 | @Override 84 | public void commit() { 85 | Object[] r = seq.remove(); 86 | assertEquals(commit, r[0]); 87 | assertEquals(1,r.length); 88 | } 89 | 90 | @Override 91 | public void rollback() { 92 | Object[] r = seq.remove(); 93 | assertEquals(rollback, r[0]); 94 | assertEquals(1,r.length); 95 | } 96 | 97 | @Override 98 | public void writeTombstone(long recid) { 99 | Object[] r = seq.remove(); 100 | assertEquals(writeTombstone, r[0]); 101 | assertEquals(recid, r[1]); 102 | assertEquals(2,r.length); 103 | } 104 | 105 | @Override 106 | public void writePreallocate(long recid) { 107 | Object[] r = seq.remove(); 108 | assertEquals(writePreallocate, r[0]); 109 | assertEquals(recid, r[1]); 110 | assertEquals(2,r.length); 111 | } 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/DBSerTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.fest.reflect.core.Reflection 4 | import org.junit.Test 5 | import org.junit.Assert.* 6 | import java.util.* 7 | 8 | /** 9 | * Tests Serialization abstraction in DB 10 | */ 11 | class DBSerTest{ 12 | 13 | fun DB.pojoSingletons() = 14 | Reflection.method("pojoSingletons") 15 | .`in`(this) 16 | .invoke() as Array 17 | 18 | 19 | @Test fun named(){ 20 | val f = TT.tempFile(); 21 | var db = DBMaker.fileDB(f).make() 22 | 23 | var atom = db.atomicInteger("atom").create() 24 | atom.set(1111) 25 | 26 | var map = db.hashMap("map").create() as MutableMap 27 | map.put(11, atom) 28 | db.close() 29 | 30 | db = DBMaker.fileDB(f).make() 31 | 32 | map = db.hashMap("map").open() as MutableMap 33 | val o = map[11] 34 | assertTrue(o is Atomic.Integer && o.get()==1111) 35 | 36 | atom = db.atomicInteger("atom").open() 37 | 38 | assertTrue(o===atom) 39 | db.close() 40 | f.delete() 41 | } 42 | 43 | fun dbClone(e:E, db:DB):E { 44 | return TT.clone(e, db.defaultSerializer) as E 45 | } 46 | 47 | @Test fun dbSingleton(){ 48 | val db = DBMaker.memoryDB().make() 49 | assertTrue(db===dbClone(db,db)) 50 | } 51 | 52 | @Test fun serializerSingleton(){ 53 | val db = DBMaker.memoryDB().make() 54 | for(f in Serializer::class.java.declaredFields){ 55 | f.isAccessible=true 56 | val v = f.get(null) 57 | assertTrue(f.name, v===dbClone(v,db)) 58 | } 59 | } 60 | 61 | @Test fun pojoSingletons1(){ 62 | val db = DBMaker.memoryDB().make() 63 | val singletons = db.pojoSingletons() 64 | 65 | //if DB.pojoSingletons changes, this method will have to be updated as well. 66 | // !!! DO NOT CHANGE INDEX OF EXISTING VALUE, just add to the END!!! 67 | val other = arrayOf( 68 | db, 69 | db.defaultSerializer, 70 | Serializer.CHAR, Serializer.STRING_ORIGHASH , Serializer.STRING, Serializer.STRING_DELTA, 71 | Serializer.STRING_DELTA2, Serializer.STRING_INTERN, Serializer.STRING_ASCII, Serializer.STRING_NOSIZE, 72 | Serializer.LONG, Serializer.LONG_PACKED, Serializer.LONG_DELTA, Serializer.INTEGER, 73 | Serializer.INTEGER_PACKED, Serializer.INTEGER_DELTA, Serializer.BOOLEAN, Serializer.RECID, 74 | Serializer.RECID_ARRAY, Serializer.ILLEGAL_ACCESS, Serializer.BYTE_ARRAY, Serializer.BYTE_ARRAY_DELTA, 75 | Serializer.BYTE_ARRAY_DELTA2, Serializer.BYTE_ARRAY_NOSIZE, Serializer.CHAR_ARRAY, Serializer.INT_ARRAY, 76 | Serializer.LONG_ARRAY, Serializer.DOUBLE_ARRAY, Serializer.JAVA, Serializer.ELSA, Serializer.UUID, 77 | Serializer.BYTE, Serializer.FLOAT, Serializer.DOUBLE, Serializer.SHORT, Serializer.SHORT_ARRAY, 78 | Serializer.FLOAT_ARRAY, Serializer.BIG_INTEGER, Serializer.BIG_DECIMAL, Serializer.CLASS, 79 | Serializer.DATE 80 | ) 81 | 82 | singletons.forEachIndexed { i, singleton -> 83 | assertTrue(other[i]===singleton) 84 | } 85 | } 86 | 87 | @Test fun pojoSingleton_no_dup(){ 88 | val db = DBMaker.memoryDB().make() 89 | val singletons = db.pojoSingletons() 90 | 91 | val map = IdentityHashMap(); 92 | singletons.forEach { map.put(it,"") } 93 | 94 | assertEquals(map.size, singletons.size) 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerStringDelta.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.*; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * Created by jan on 2/29/16. 9 | */ 10 | public class SerializerStringDelta extends SerializerString{ 11 | 12 | 13 | protected static int commonPrefixLen(char[][] chars) { 14 | //$DELAY$ 15 | for(int ret=0;;ret++){ 16 | if(chars[0].length==ret) { 17 | return ret; 18 | } 19 | char byt = chars[0][ret]; 20 | for(int i=1;i params() throws IOException { 32 | List ret = new ArrayList(); 33 | int inc = TT.shortTest()?200:20; 34 | 35 | for(int commitNum=1;commitNum<1000;commitNum+=inc){ 36 | for(int cutPointSeed=0;cutPointSeed<600;cutPointSeed+=inc){ 37 | ret.add(new Object[]{commitNum, cutPointSeed}); 38 | } 39 | } 40 | 41 | return ret; 42 | } 43 | 44 | @Test public void test(){ 45 | File f = TT.tempFile(); 46 | WriteAheadLog wal = new WriteAheadLog(f.getPath()); 47 | 48 | for(int i=0;i? { 22 | val consumer = SortedTableMap.createFromSink( 23 | keySerializer = Serializer.INTEGER, 24 | valueSerializer = Serializer.STRING_INTERN, 25 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false)) 26 | consumer.put(Pair(JSR166TestCase.one, "A")) 27 | consumer.put(Pair(JSR166TestCase.two, "B")) 28 | consumer.put(Pair(JSR166TestCase.three, "C")) 29 | consumer.put(Pair(JSR166TestCase.four, "D")) 30 | consumer.put(Pair(JSR166TestCase.five, "E")) 31 | return consumer.create() 32 | } 33 | 34 | override fun emptyMap(): ConcurrentNavigableMap? { 35 | return SortedTableMap.createFromSink( 36 | keySerializer = Serializer.INTEGER, 37 | valueSerializer = Serializer.STRING_INTERN, 38 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false)) 39 | .create() 40 | } 41 | 42 | override fun emptyIntMap(): ConcurrentNavigableMap? { 43 | throw AssertionError() 44 | } 45 | 46 | override fun testEquals() 47 | { 48 | val map1 = map5() 49 | val map2 = map5() 50 | assertEquals(map1, map2) 51 | assertEquals(map2, map1) 52 | } 53 | 54 | override fun testPutIfAbsent() {} 55 | override fun testPutIfAbsent2() {} 56 | override fun testClear() {} 57 | override fun testPollLastEntry() {} 58 | override fun testPollFirstEntry() {} 59 | override fun testRemove3() {throw NullPointerException()} 60 | override fun testPutAll() {} 61 | override fun testPut1_NullPointerException() {} 62 | override fun testRemove() {} 63 | override fun testRemove2() {} 64 | override fun testRemove1_NullPointerException() {} 65 | override fun testRemove2_NullPointerException() {} 66 | override fun testReplace() {} 67 | override fun testReplace2() {} 68 | override fun testReplaceValue() {} 69 | override fun testReplaceValue2() {} 70 | override fun testReplaceValue_NullPointerException() {} 71 | override fun testReplace_NullPointerException() {} 72 | override fun testPutIfAbsent1_NullPointerException() {} 73 | 74 | override fun populatedIntMap(limit: Int): NavigableMap? { 75 | val consumer = SortedTableMap.createFromSink( 76 | keySerializer = Serializer.INTEGER, 77 | valueSerializer = Serializer.INTEGER, 78 | volume = CC.DEFAULT_MEMORY_VOLUME_FACTORY.makeVolume(null, false)) 79 | 80 | var i = 0 81 | val n = 2 * limit / 3 82 | val map = java.util.TreeMap() 83 | while (i < n) { 84 | val key = rnd.nextInt(limit) 85 | map.put(key,key*2) 86 | bs.set(key) 87 | i++ 88 | } 89 | map.forEach { k, v -> 90 | consumer.put(Pair(k, v)) 91 | } 92 | 93 | return consumer.create() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/MapExtra.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.eclipse.collections.api.block.procedure.Procedure 4 | import java.util.EventListener 5 | import java.util.concurrent.ConcurrentMap 6 | import java.util.concurrent.ConcurrentNavigableMap 7 | import java.util.function.BiConsumer 8 | 9 | /** 10 | * Extra methods for Map interface 11 | */ 12 | interface MapExtra : ConcurrentMap { 13 | 14 | 15 | 16 | /** map size as long number */ 17 | fun sizeLong(): Long 18 | 19 | 20 | /** 21 | * Atomically associates the specified key with the given value if it is 22 | * not already associated with a value. 23 | * 24 | * 25 | * This is equivalent to: 26 | * ` 27 | * if (!cache.containsKey(key)) {} 28 | * cache.put(key, value); 29 | * return true; 30 | * } else { 31 | * return false; 32 | * } 33 | ` * 34 | * except that the action is performed atomically. 35 | 36 | * @param key key with which the specified value is to be associated 37 | * 38 | * @param value value to be associated with the specified key 39 | * 40 | * @return true if a value was set. 41 | * 42 | * @throws NullPointerException if key is null or value is null 43 | * 44 | * @throws IllegalStateException if the cache is [.isClosed] 45 | * 46 | * @throws ClassCastException if the implementation is configured to perform 47 | * runtime-type-checking, and the key or value 48 | * types are incompatible with those that have been 49 | * configured with different serialziers 50 | * TODO link to JCache standard 51 | * TODO credits for javadoc 52 | */ 53 | fun putIfAbsentBoolean(key: K?, value: V?): Boolean 54 | 55 | 56 | fun isClosed(): Boolean 57 | 58 | fun forEachKey(procedure: (K)->Unit); 59 | 60 | fun forEachValue(procedure: (V)->Unit); 61 | 62 | override fun forEach(action: BiConsumer); 63 | 64 | val keySerializer:Serializer 65 | 66 | val valueSerializer:Serializer 67 | 68 | } 69 | 70 | 71 | interface ConcurrentNavigableMapExtra : ConcurrentNavigableMap, MapExtra, BTreeMapJava.ConcurrentNavigableMap2 { 72 | 73 | val hasValues:Boolean 74 | 75 | fun findHigher(key: K?, inclusive: Boolean): MutableMap.MutableEntry? 76 | 77 | fun findLower(key: K?, inclusive: Boolean): MutableMap.MutableEntry? 78 | 79 | fun findHigherKey(key: K?, inclusive: Boolean): K? 80 | 81 | fun findLowerKey(key: K?, inclusive: Boolean): K? 82 | 83 | fun keyIterator(): MutableIterator 84 | 85 | fun keyIterator(lo: K?, loInclusive: Boolean, hi: K?, hiInclusive: Boolean): MutableIterator 86 | 87 | fun valueIterator(lo: K?, loInclusive: Boolean, hi: K?, hiInclusive: Boolean): MutableIterator 88 | 89 | fun entryIterator(lo: K?, loInclusive: Boolean, hi: K?, hiInclusive: Boolean): MutableIterator> 90 | 91 | fun descendingKeyIterator(): MutableIterator 92 | 93 | fun descendingKeyIterator(lo: K?, loInclusive: Boolean, hi: K?, hiInclusive: Boolean): MutableIterator 94 | 95 | fun descendingValueIterator(): MutableIterator 96 | 97 | fun descendingValueIterator(lo: K?, loInclusive: Boolean, hi: K?, hiInclusive: Boolean): MutableIterator 98 | 99 | fun descendingEntryIterator(): MutableIterator> 100 | 101 | fun descendingEntryIterator(lo: K?, loInclusive: Boolean, hi: K?, hiInclusive: Boolean): MutableIterator> 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerArray.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.io.Serializable; 9 | 10 | /** 11 | * Created by jan on 2/28/16. 12 | */ 13 | public class SerializerArray extends GroupSerializerObjectArray{ 14 | 15 | private static final long serialVersionUID = -7443421486382532062L; 16 | protected final Serializer serializer; 17 | 18 | public SerializerArray(Serializer serializer) { 19 | if (serializer == null) 20 | throw new NullPointerException("null serializer"); 21 | this.serializer = serializer; 22 | } 23 | 24 | // /** used for deserialization */ 25 | // @SuppressWarnings("unchecked") 26 | // protected Array(SerializerBase serializerBase, DataInput2 is, SerializerBase.FastArrayList objectStack) throws IOException { 27 | // objectStack.add(this); 28 | // this.serializer = (Serializer) serializerBase.deserialize(is,objectStack); 29 | // } 30 | 31 | 32 | @Override 33 | public void serialize(DataOutput2 out, T[] value) throws IOException { 34 | out.packInt(value.length); 35 | for (T a : value) { 36 | serializer.serialize(out, a); 37 | } 38 | } 39 | 40 | @Override 41 | public T[] deserialize(DataInput2 in, int available) throws IOException { 42 | T[] ret = (T[]) new Object[in.unpackInt()]; 43 | for (int i = 0; i < ret.length; i++) { 44 | ret[i] = serializer.deserialize(in, -1); 45 | } 46 | return ret; 47 | 48 | } 49 | 50 | @Override 51 | public boolean isTrusted() { 52 | return serializer.isTrusted(); 53 | } 54 | 55 | @Override 56 | public boolean equals(T[] a1, T[] a2) { 57 | if (a1 == a2) 58 | return true; 59 | if (a1 == null || a1.length != a2.length) 60 | return false; 61 | 62 | for (int i = 0; i < a1.length; i++) { 63 | if (!serializer.equals(a1[i], a2[i])) 64 | return false; 65 | } 66 | return true; 67 | } 68 | 69 | @Override 70 | public int hashCode(T[] objects, int seed) { 71 | seed += objects.length; 72 | for (T a : objects) { 73 | seed = (-1640531527) * seed + serializer.hashCode(a, seed); 74 | } 75 | return seed; 76 | } 77 | 78 | @Override 79 | public boolean equals(Object o) { 80 | if (this == o) return true; 81 | if (o == null || getClass() != o.getClass()) return false; 82 | return serializer.equals(((SerializerArray) o).serializer); 83 | } 84 | 85 | @Override 86 | public int hashCode() { 87 | return serializer.hashCode(); 88 | } 89 | 90 | 91 | @Override 92 | public int compare(Object[] o1, Object[] o2) { 93 | int len = Math.min(o1.length, o2.length); 94 | int r; 95 | for (int i = 0; i < len; i++) { 96 | Object a1 = o1[i]; 97 | Object a2 = o2[i]; 98 | 99 | if (a1 == a2) { //this case handles both nulls 100 | r = 0; 101 | } else if (a1 == null) { 102 | r = 1; //null is positive infinity, always greater than anything else 103 | } else if (a2 == null) { 104 | r = -1; 105 | } else { 106 | r = serializer.compare((T) a1, (T) a2); 107 | ; 108 | } 109 | if (r != 0) 110 | return r; 111 | } 112 | return SerializerUtils.compareInt(o1.length, o2.length); 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerBoolean.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | 11 | /** 12 | * Created by jan on 2/28/16. 13 | */ 14 | public class SerializerBoolean implements GroupSerializer { 15 | 16 | @Override 17 | public void serialize(DataOutput2 out, Boolean value) throws IOException { 18 | out.writeBoolean(value); 19 | } 20 | 21 | @Override 22 | public Boolean deserialize(DataInput2 in, int available) throws IOException { 23 | return in.readBoolean(); 24 | } 25 | 26 | @Override 27 | public int fixedSize() { 28 | return 1; 29 | } 30 | 31 | @Override 32 | public boolean isTrusted() { 33 | return true; 34 | } 35 | 36 | 37 | @Override 38 | public int valueArraySearch(Object keys, Boolean key) { 39 | return Arrays.binarySearch(valueArrayToArray(keys), key); 40 | } 41 | 42 | @Override 43 | public int valueArraySearch(Object keys, Boolean key, Comparator comparator) { 44 | return Arrays.binarySearch(valueArrayToArray(keys), key, comparator); 45 | } 46 | 47 | @Override 48 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 49 | for (boolean b : ((boolean[]) vals)) { 50 | out.writeBoolean(b); 51 | } 52 | } 53 | 54 | @Override 55 | public Object valueArrayDeserialize(DataInput2 in, int size) throws IOException { 56 | boolean[] ret = new boolean[size]; 57 | for (int i = 0; i < size; i++) { 58 | ret[i] = in.readBoolean(); 59 | } 60 | return ret; 61 | } 62 | 63 | @Override 64 | public Boolean valueArrayGet(Object vals, int pos) { 65 | return ((boolean[]) vals)[pos]; 66 | } 67 | 68 | @Override 69 | public int valueArraySize(Object vals) { 70 | return ((boolean[]) vals).length; 71 | } 72 | 73 | @Override 74 | public Object valueArrayEmpty() { 75 | return new boolean[0]; 76 | } 77 | 78 | @Override 79 | public Object valueArrayPut(Object vals, int pos, Boolean newValue) { 80 | boolean[] array = (boolean[]) vals; 81 | final boolean[] ret = Arrays.copyOf(array, array.length + 1); 82 | if (pos < array.length) { 83 | System.arraycopy(array, pos, ret, pos + 1, array.length - pos); 84 | } 85 | ret[pos] = newValue; 86 | return ret; 87 | 88 | } 89 | 90 | @Override 91 | public Object valueArrayUpdateVal(Object vals, int pos, Boolean newValue) { 92 | boolean[] vals2 = ((boolean[]) vals).clone(); 93 | vals2[pos] = newValue; 94 | return vals2; 95 | 96 | } 97 | 98 | @Override 99 | public Object valueArrayFromArray(Object[] objects) { 100 | boolean[] ret = new boolean[objects.length]; 101 | for (int i = 0; i < ret.length; i++) { 102 | ret[i] = (Boolean) objects[i]; 103 | } 104 | return ret; 105 | } 106 | 107 | @Override 108 | public Object valueArrayCopyOfRange(Object vals, int from, int to) { 109 | return Arrays.copyOfRange((boolean[]) vals, from, to); 110 | } 111 | 112 | @Override 113 | public Object valueArrayDeleteValue(Object vals, int pos) { 114 | boolean[] valsOrig = (boolean[]) vals; 115 | boolean[] vals2 = new boolean[valsOrig.length - 1]; 116 | System.arraycopy(vals, 0, vals2, 0, pos - 1); 117 | System.arraycopy(vals, pos, vals2, pos - 1, vals2.length - (pos - 1)); 118 | return vals2; 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/jsr166Tests/Collection8Test.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.jsr166Tests;/* 2 | * Written by Doug Lea and Martin Buchholz with assistance from 3 | * members of JCP JSR-166 Expert Group and released to the public 4 | * domain, as explained at 5 | * http://creativecommons.org/publicdomain/zero/1.0/ 6 | */ 7 | 8 | import static java.util.concurrent.TimeUnit.MILLISECONDS; 9 | 10 | import java.util.ArrayList; 11 | import java.util.Collection; 12 | import java.util.Collections; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.ExecutorService; 15 | import java.util.concurrent.Future; 16 | import java.util.concurrent.atomic.AtomicBoolean; 17 | import java.util.concurrent.atomic.AtomicLong; 18 | import java.util.function.Consumer; 19 | 20 | import junit.framework.Test; 21 | 22 | /** 23 | * Contains tests applicable to all jdk8+ Collection implementations. 24 | * An extension of CollectionTest. 25 | */ 26 | public abstract class Collection8Test extends JSR166TestCase { 27 | final CollectionImplementation impl; 28 | 29 | /** Tests are parameterized by a Collection implementation. */ 30 | Collection8Test(CollectionImplementation impl, String methodName) { 31 | super(methodName); 32 | this.impl = impl; 33 | } 34 | 35 | public static Test testSuite(CollectionImplementation impl) { 36 | return parameterizedTestSuite(Collection8Test.class, 37 | CollectionImplementation.class, 38 | impl); 39 | } 40 | 41 | /** 42 | * stream().forEach returns elements in the collection 43 | */ 44 | public void testForEach() throws Throwable { 45 | final Collection c = impl.emptyCollection(); 46 | final AtomicLong count = new AtomicLong(0L); 47 | final Object x = impl.makeElement(1); 48 | final Object y = impl.makeElement(2); 49 | final ArrayList found = new ArrayList(); 50 | Consumer spy = (o) -> { found.add(o); }; 51 | c.stream().forEach(spy); 52 | assertTrue(found.isEmpty()); 53 | 54 | assertTrue(c.add(x)); 55 | c.stream().forEach(spy); 56 | assertEquals(Collections.singletonList(x), found); 57 | found.clear(); 58 | 59 | assertTrue(c.add(y)); 60 | c.stream().forEach(spy); 61 | assertEquals(2, found.size()); 62 | assertTrue(found.contains(x)); 63 | assertTrue(found.contains(y)); 64 | found.clear(); 65 | 66 | c.clear(); 67 | c.stream().forEach(spy); 68 | assertTrue(found.isEmpty()); 69 | } 70 | 71 | public void testForEachConcurrentStressTest() throws Throwable { 72 | if (!impl.isConcurrent()) return; 73 | final Collection c = impl.emptyCollection(); 74 | final long testDurationMillis = SHORT_DELAY_MS; 75 | final AtomicBoolean done = new AtomicBoolean(false); 76 | final Object elt = impl.makeElement(1); 77 | ExecutorService pool = Executors.newCachedThreadPool(); 78 | Runnable checkElt = () -> { 79 | while (!done.get()) 80 | c.stream().forEach((x) -> { assertSame(x, elt); }); }; 81 | Runnable addRemove = () -> { 82 | while (!done.get()) { 83 | assertTrue(c.add(elt)); 84 | assertTrue(c.remove(elt)); 85 | }}; 86 | Future f1 = pool.submit(checkElt); 87 | Future f2 = pool.submit(addRemove); 88 | Thread.sleep(testDurationMillis); 89 | done.set(true); 90 | pool.shutdown(); 91 | assertTrue(pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); 92 | assertNull(f1.get(LONG_DELAY_MS, MILLISECONDS)); 93 | assertNull(f2.get(LONG_DELAY_MS, MILLISECONDS)); 94 | } 95 | 96 | // public void testCollection8DebugFail() { fail(); } 97 | } 98 | -------------------------------------------------------------------------------- /src/test/java/org/mapdb/StoreReopenTest.kt: -------------------------------------------------------------------------------- 1 | package org.mapdb 2 | 3 | import org.junit.After 4 | import org.junit.Test 5 | import java.io.File 6 | import java.util.* 7 | import org.junit.Assert.* 8 | import org.mapdb.volume.RandomAccessFileVol 9 | import org.mapdb.TT.assertFailsWith 10 | 11 | abstract class StoreReopenTest(): StoreTest(){ 12 | val file = TT.tempFile(); 13 | 14 | abstract fun openStore(file: File): Store 15 | 16 | abstract val headerType:Long 17 | 18 | @After fun deleteFiles(){ 19 | TT.tempDelete(file); 20 | } 21 | 22 | @Test open fun headerType(){ 23 | val s = openStore(file) 24 | s.put(11L, Serializer.LONG) 25 | s.commit() 26 | s.close() 27 | val vol = RandomAccessFileVol.FACTORY.makeVolume(file.path, true) 28 | assertEquals(CC.FILE_HEADER,vol.getUnsignedByte(0L).toLong()) 29 | assertEquals(headerType, vol.getUnsignedByte(1L).toLong()) 30 | } 31 | 32 | 33 | 34 | @Test fun put_reopen_get() { 35 | var e = openStore(file) 36 | val l = 11231203099090L 37 | val recid = e.put(l, Serializer.LONG) 38 | e.commit() 39 | e.close() 40 | e = openStore(file) 41 | 42 | assertEquals(l, e.get(recid, Serializer.LONG)) 43 | e.close() 44 | } 45 | 46 | 47 | @Test fun put_reopen_get_large() { 48 | var e = openStore(file) 49 | 50 | val b = TT.randomByteArray(1000000) 51 | val recid = e.put(b, Serializer.BYTE_ARRAY_NOSIZE) 52 | e.commit() 53 | e.close() 54 | e = openStore(file) 55 | 56 | assertTrue(Arrays.equals(b, e.get(recid, Serializer.BYTE_ARRAY_NOSIZE))) 57 | e.verify() 58 | e.close() 59 | } 60 | 61 | @Test fun large_record_update2() { 62 | var e = openStore(file) 63 | val b = TT.randomByteArray(1000000) 64 | val recid = e.put(b, Serializer.BYTE_ARRAY_NOSIZE) 65 | e.update(recid, b, Serializer.BYTE_ARRAY_NOSIZE) 66 | var b2 = e.get(recid, Serializer.BYTE_ARRAY_NOSIZE) 67 | assertTrue(Arrays.equals(b, b2)) 68 | e.commit() 69 | e.close() 70 | e = openStore(file) 71 | 72 | b2 = e.get(recid, Serializer.BYTE_ARRAY_NOSIZE) 73 | assertTrue(Arrays.equals(b, b2)) 74 | e.verify() 75 | e.close() 76 | } 77 | 78 | @Test fun large_record_larger() { 79 | var e = openStore(file) 80 | val b = TT.randomByteArray(100000000) 81 | val recid = e.put(b, Serializer.BYTE_ARRAY_NOSIZE) 82 | var b2 = e.get(recid, Serializer.BYTE_ARRAY_NOSIZE) 83 | assertTrue(Arrays.equals(b, b2)) 84 | e.verify() 85 | e.commit() 86 | e.close() 87 | e = openStore(file) 88 | 89 | b2 = e.get(recid, Serializer.BYTE_ARRAY_NOSIZE) 90 | assertTrue(Arrays.equals(b, b2)) 91 | e.verify() 92 | e.close() 93 | } 94 | 95 | 96 | 97 | @Test fun test_store_reopen() { 98 | var e = openStore(file) 99 | val recid = e.put("aaa", Serializer.STRING) 100 | e.commit() 101 | e.commit() 102 | e.close() 103 | e = openStore(file) 104 | val aaa = e.get(recid, Serializer.STRING) 105 | assertEquals("aaa", aaa) 106 | e.verify() 107 | e.close() 108 | } 109 | 110 | 111 | @Test fun file_lock(){ 112 | var e = openStore(file) 113 | val recid = e.put("aaa", Serializer.STRING) 114 | 115 | assertFailsWith(DBException.FileLocked::class.java, { 116 | openStore(file) 117 | }) 118 | 119 | e.close() 120 | } 121 | 122 | @Test fun empty_rollback2(){ 123 | val e = openStore(file) 124 | if(e is StoreTx) 125 | e.rollback() 126 | e.close() 127 | } 128 | 129 | @Test fun empty_commit2(){ 130 | val e = openStore(file) 131 | e.commit() 132 | e.close() 133 | } 134 | 135 | 136 | 137 | } -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerEightByte.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | 11 | public abstract class SerializerEightByte implements GroupSerializer { 12 | 13 | protected abstract E unpack(long l); 14 | protected abstract long pack(E l); 15 | 16 | @Override 17 | public E valueArrayGet(Object vals, int pos){ 18 | return unpack(((long[]) vals)[pos]); 19 | } 20 | 21 | 22 | @Override 23 | public int valueArraySize(Object vals){ 24 | return ((long[])vals).length; 25 | } 26 | 27 | @Override 28 | public Object valueArrayEmpty(){ 29 | return new long[0]; 30 | } 31 | 32 | @Override 33 | public Object valueArrayPut(Object vals, int pos, E newValue) { 34 | 35 | long[] array = (long[]) vals; 36 | final long[] ret = Arrays.copyOf(array, array.length+1); 37 | if(pos>> 1; 123 | int compare = comparator.compare(key, unpack(array[mid])); 124 | 125 | if (compare == 0) 126 | return mid; 127 | else if (compare < 0) 128 | hi = mid - 1; 129 | else 130 | lo = mid + 1; 131 | } 132 | return -(lo + 1); 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerFourByte.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | 11 | /** 12 | * Created by jan on 2/28/16. 13 | */ 14 | public abstract class SerializerFourByte implements GroupSerializer { 15 | 16 | protected abstract E unpack(int l); 17 | 18 | protected abstract int pack(E l); 19 | 20 | @Override 21 | public boolean isTrusted() { 22 | return true; 23 | } 24 | 25 | @Override 26 | public int fixedSize() { 27 | return 4; 28 | } 29 | 30 | @Override 31 | public E valueArrayGet(Object vals, int pos) { 32 | return unpack(((int[]) vals)[pos]); 33 | } 34 | 35 | @Override 36 | public int valueArraySize(Object vals) { 37 | return ((int[]) vals).length; 38 | } 39 | 40 | @Override 41 | public Object valueArrayEmpty() { 42 | return new int[0]; 43 | } 44 | 45 | @Override 46 | public Object valueArrayPut(Object vals, int pos, E newValue) { 47 | 48 | int[] array = (int[]) vals; 49 | final int[] ret = Arrays.copyOf(array, array.length + 1); 50 | if (pos < array.length) { 51 | System.arraycopy(array, pos, ret, pos + 1, array.length - pos); 52 | } 53 | ret[pos] = pack(newValue); 54 | return ret; 55 | } 56 | 57 | @Override 58 | public Object valueArrayUpdateVal(Object vals, int pos, E newValue) { 59 | int[] vals2 = ((int[]) vals).clone(); 60 | vals2[pos] = pack(newValue); 61 | return vals2; 62 | } 63 | 64 | @Override 65 | public Object valueArrayFromArray(Object[] objects) { 66 | int[] ret = new int[objects.length]; 67 | int pos = 0; 68 | 69 | for (Object o : objects) { 70 | ret[pos++] = pack((E) o); 71 | } 72 | 73 | return ret; 74 | } 75 | 76 | @Override 77 | public Object valueArrayCopyOfRange(Object vals, int from, int to) { 78 | return Arrays.copyOfRange((int[]) vals, from, to); 79 | } 80 | 81 | @Override 82 | public Object valueArrayDeleteValue(Object vals, int pos) { 83 | int[] valsOrig = (int[]) vals; 84 | int[] vals2 = new int[valsOrig.length - 1]; 85 | System.arraycopy(vals, 0, vals2, 0, pos - 1); 86 | System.arraycopy(vals, pos, vals2, pos - 1, vals2.length - (pos - 1)); 87 | return vals2; 88 | } 89 | 90 | 91 | @Override 92 | public void valueArraySerialize(DataOutput2 out, Object vals) throws IOException { 93 | for (int o : (int[]) vals) { 94 | out.writeInt(o); 95 | } 96 | } 97 | 98 | @Override 99 | public Object valueArrayDeserialize(DataInput2 in, int size) throws IOException { 100 | int[] ret = new int[size]; 101 | for (int i = 0; i < size; i++) { 102 | ret[i] = in.readInt(); 103 | } 104 | return ret; 105 | } 106 | 107 | @Override 108 | final public int valueArraySearch(Object keys, E key, Comparator comparator) { 109 | if (comparator == this) 110 | return valueArraySearch(keys, key); 111 | int[] array = (int[]) keys; 112 | 113 | int lo = 0; 114 | int hi = array.length - 1; 115 | 116 | while (lo <= hi) { 117 | int mid = (lo + hi) >>> 1; 118 | int compare = comparator.compare(key, unpack(array[mid])); 119 | 120 | if (compare == 0) 121 | return mid; 122 | else if (compare < 0) 123 | hi = mid - 1; 124 | else 125 | lo = mid + 1; 126 | } 127 | return -(lo + 1); 128 | } 129 | 130 | @Override 131 | public E valueArrayBinaryGet(DataInput2 input, int keysLen, int pos) throws IOException { 132 | input.skipBytes(pos*4); 133 | return unpack(input.readInt()); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/org/mapdb/serializer/SerializerString.java: -------------------------------------------------------------------------------- 1 | package org.mapdb.serializer; 2 | 3 | import org.mapdb.DataInput2; 4 | import org.mapdb.DataOutput2; 5 | import org.mapdb.Serializer; 6 | 7 | import java.io.IOException; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | 11 | public class SerializerString implements GroupSerializer { 12 | 13 | @Override 14 | public void serialize(DataOutput2 out, String value) throws IOException { 15 | out.writeUTF(value); 16 | } 17 | 18 | @Override 19 | public String deserialize(DataInput2 in, int available) throws IOException { 20 | return in.readUTF(); 21 | } 22 | 23 | @Override 24 | public boolean isTrusted() { 25 | return true; 26 | } 27 | 28 | 29 | @Override 30 | public void valueArraySerialize(DataOutput2 out2, Object vals) throws IOException { 31 | for(char[] v:(char[][])vals){ 32 | out2.packInt(v.length); 33 | for(char c:v){ 34 | out2.packInt(c); 35 | } 36 | } 37 | } 38 | 39 | @Override 40 | public char[][] valueArrayDeserialize(DataInput2 in2, int size) throws IOException { 41 | char[][] ret = new char[size][]; 42 | for(int i=0;i>> 1; 67 | int compare = comparator.compare(key, new String(array[mid])); 68 | 69 | if (compare == 0) 70 | return mid; 71 | else if (compare < 0) 72 | hi = mid - 1; 73 | else 74 | lo = mid + 1; 75 | } 76 | return -(lo + 1); 77 | } 78 | 79 | @Override 80 | public String valueArrayGet(Object vals, int pos) { 81 | return new String(((char[][])vals)[pos]); 82 | } 83 | 84 | @Override 85 | public int valueArraySize(Object vals) { 86 | return ((char[][])vals).length; 87 | } 88 | 89 | @Override 90 | public char[][] valueArrayEmpty() { 91 | return new char[0][]; 92 | } 93 | 94 | @Override 95 | public char[][] valueArrayPut(Object vals, int pos, String newValue) { 96 | char[][] array = (char[][]) vals; 97 | final char[][] ret = Arrays.copyOf(array, array.length+1); 98 | if(pos