diff --git a/src/main/java/org/warp/cowdb/Database.java b/src/main/java/org/warp/cowdb/Database.java index 97ba2dc..795607b 100644 --- a/src/main/java/org/warp/cowdb/Database.java +++ b/src/main/java/org/warp/cowdb/Database.java @@ -5,7 +5,12 @@ import com.esotericsoftware.kryo.io.ByteBufferInput; import com.esotericsoftware.kryo.io.ByteBufferInputStream; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; +import it.unimi.dsi.fastutil.booleans.BooleanArrayList; +import it.unimi.dsi.fastutil.bytes.ByteArrayList; +import it.unimi.dsi.fastutil.chars.CharArrayList; +import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.longs.LongArrayList; +import it.unimi.dsi.fastutil.shorts.ShortArrayList; import org.apache.commons.lang3.reflect.FieldUtils; import org.warp.jcwdb.ann.*; @@ -20,8 +25,7 @@ import java.nio.channels.SeekableByteChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.*; import java.util.function.Supplier; import static org.warp.cowdb.IBlocksMetadata.EMPTY_BLOCK_ID; @@ -102,6 +106,10 @@ public class Database implements IDatabase { return root; } + protected void registerClass(Class type, int id) { + this.objectsIO.registerClass(type, id); + } + public static class DatabaseDataInitializer implements IDataInitializer { private final DatabaseObjectsIO objectsIO; @@ -203,6 +211,59 @@ public class Database implements IDatabase { private DatabaseObjectsIO(IDatabase database, DatabaseReferencesIO referencesIO) { this.database = database; this.referencesIO = referencesIO; + kryo.setRegistrationRequired(false); + int id = -90; + registerClass(boolean[].class, id++); + registerClass(byte[].class, id++); + registerClass(short[].class, id++); + registerClass(char[].class, id++); + registerClass(int[].class, id++); + registerClass(long[].class, id++); + registerClass(Boolean[].class, id++); + registerClass(Byte[].class, id++); + registerClass(Short[].class, id++); + registerClass(Character[].class, id++); + registerClass(Integer[].class, id++); + registerClass(Long[].class, id++); + registerClass(String.class, id++); + registerClass(String[].class, id++); + registerClass(Boolean.class, id++); + registerClass(Byte.class, id++); + registerClass(Short.class, id++); + registerClass(Character.class, id++); + registerClass(Integer.class, id++); + registerClass(Class.class, id++); + registerClass(Object.class, id++); + registerClass(Object[].class, id++); + registerClass(Long.class, id++); + registerClass(String.class, id++); + registerClass(String[].class, id++); + registerClass(boolean[][].class, id++); + registerClass(byte[][].class, id++); + registerClass(short[][].class, id++); + registerClass(char[][].class, id++); + registerClass(int[][].class, id++); + registerClass(long[][].class, id++); + registerClass(String[][].class, id++); + registerClass(List.class, id++); + registerClass(ArrayList.class, id++); + registerClass(LinkedList.class, id++); + registerClass(Set.class, id++); + registerClass(HashSet.class, id++); + registerClass(LinkedHashSet.class, id++); + registerClass(Map.class, id++); + registerClass(HashMap.class, id++); + registerClass(LinkedHashMap.class, id++); + registerClass(TreeMap.class, id++); + registerClass(BooleanArrayList.class, id++); + registerClass(ByteArrayList.class, id++); + registerClass(ShortArrayList.class, id++); + registerClass(CharArrayList.class, id++); + registerClass(IntArrayList.class, id++); + registerClass(LongArrayList.class, id++); + registerClass(TreeSet.class, id++); + registerClass(SortedSet.class, id++); + registerClass(SortedMap.class, id++); } @Override @@ -301,7 +362,7 @@ public class Database implements IDatabase { try { setData(objectFullInfo.getFieldReferences()[i], objectFullInfo.getFieldTypes()[i], objectFullInfo.getFields()[i].get(value)); } catch (IllegalAccessException e) { - throw new IOError(e); + throw new IOException(e); } } for (int i = 0; i < objectFullInfo.getPropertyReferences().length; i++) { @@ -483,6 +544,14 @@ public class Database implements IDatabase { obj.setProperty(propertyId, loadData(propertyType, propertyUID, property::getReturnType)); } + @Override + public void registerClass(Class type, int id) { + if (id < -100) { + throw new IllegalArgumentException(); + } + kryo.register(type, 100 + id); + } + private void preloadEnhancedObjectProperties(T obj, long[] propertyReferences) { // Declare the variables needed to get the biggest property Id Method[] unorderedPropertyGetters = obj.getPropertyGetters(); @@ -671,19 +740,17 @@ public class Database implements IDatabase { public static class DatabaseReferencesMetadata implements IReferencesMetadata { private final SeekableByteChannel metaFileChannel; private final int REF_META_BYTES_COUNT = Long.BYTES; - private long metaFileChannelSize; private long firstFreeReference; private DatabaseReferencesMetadata(Path refMetaFile) throws IOException { metaFileChannel = Files.newByteChannel(refMetaFile, StandardOpenOption.READ, StandardOpenOption.WRITE); - metaFileChannelSize = metaFileChannel.size(); - firstFreeReference = metaFileChannelSize / REF_META_BYTES_COUNT; + firstFreeReference = metaFileChannel.size() / REF_META_BYTES_COUNT; } @Override public long getReference(long reference) throws IOException { ByteBuffer buffer = ByteBuffer.allocate(REF_META_BYTES_COUNT); - if (reference >= firstFreeReference || reference * REF_META_BYTES_COUNT > metaFileChannelSize) { + if (reference >= firstFreeReference) { return EMPTY_BLOCK_ID; } SeekableByteChannel currentFileChannel = metaFileChannel.position(reference * REF_META_BYTES_COUNT); diff --git a/src/main/java/org/warp/cowdb/EnhancedObjectFullInfo.java b/src/main/java/org/warp/cowdb/EnhancedObjectFullInfo.java index 8cd28ea..6a1ce2c 100644 --- a/src/main/java/org/warp/cowdb/EnhancedObjectFullInfo.java +++ b/src/main/java/org/warp/cowdb/EnhancedObjectFullInfo.java @@ -12,7 +12,7 @@ public class EnhancedObjectFullInfo { private final DBDataType[] propertyTypes; private final Object[] loadedPropertyValues; - public EnhancedObjectFullInfo(long[] fieldReferences, DBDataType[] fieldTypes, Field[] fields, long[] propertyReferences, DBDataType[] propertyTypes, Object[] loadedPropertyValues) { + EnhancedObjectFullInfo(long[] fieldReferences, DBDataType[] fieldTypes, Field[] fields, long[] propertyReferences, DBDataType[] propertyTypes, Object[] loadedPropertyValues) { this.fieldReferences = fieldReferences; this.fieldTypes = fieldTypes; this.fields = fields; @@ -21,11 +21,11 @@ public class EnhancedObjectFullInfo { this.loadedPropertyValues = loadedPropertyValues; } - public long[] getFieldReferences() { + long[] getFieldReferences() { return fieldReferences; } - public DBDataType[] getFieldTypes() { + DBDataType[] getFieldTypes() { return fieldTypes; } @@ -33,15 +33,15 @@ public class EnhancedObjectFullInfo { return fields; } - public long[] getPropertyReferences() { + long[] getPropertyReferences() { return propertyReferences; } - public DBDataType[] getPropertyTypes() { + DBDataType[] getPropertyTypes() { return propertyTypes; } - public Object[] getLoadedPropertyValues() { + Object[] getLoadedPropertyValues() { return loadedPropertyValues; } } diff --git a/src/main/java/org/warp/cowdb/IObjectsIO.java b/src/main/java/org/warp/cowdb/IObjectsIO.java index ac0cb9c..39212a6 100644 --- a/src/main/java/org/warp/cowdb/IObjectsIO.java +++ b/src/main/java/org/warp/cowdb/IObjectsIO.java @@ -6,7 +6,7 @@ import org.warp.jcwdb.ann.DBDataType; import java.io.IOException; import java.lang.reflect.Method; -interface IObjectsIO { +public interface IObjectsIO { T loadEnhancedObject(long reference, Class objectType) throws IOException; T loadObject(long reference) throws IOException; @@ -106,4 +106,6 @@ interface IObjectsIO { } void loadProperty(EnhancedObject enhancedObject, int propertyId, Method propertyGetter, DBDataType propertyType, long propertyUID) throws IOException; + + void registerClass(Class type, int id); } diff --git a/src/main/java/org/warp/jcwdb/ann/DBArrayList.java b/src/main/java/org/warp/cowdb/lists/CowList.java similarity index 50% rename from src/main/java/org/warp/jcwdb/ann/DBArrayList.java rename to src/main/java/org/warp/cowdb/lists/CowList.java index 02907df..fcba1d4 100644 --- a/src/main/java/org/warp/jcwdb/ann/DBArrayList.java +++ b/src/main/java/org/warp/cowdb/lists/CowList.java @@ -1,85 +1,72 @@ -package org.warp.jcwdb.ann; +package org.warp.cowdb.lists; import it.unimi.dsi.fastutil.longs.LongArrayList; +import org.warp.cowdb.EnhancedObject; +import org.warp.cowdb.IDatabase; +import org.warp.jcwdb.ann.DBDataType; +import org.warp.jcwdb.ann.DBField; -import java.io.IOError; import java.io.IOException; import java.util.StringJoiner; -public abstract class DBArrayList extends DBObject { +public abstract class CowList extends EnhancedObject { private final Object indicesAccessLock = new Object(); - @DBField(id = 0, type = DBDataType.UID_LIST) + @DBField(id = 0, type = DBDataType.REFERENCES_LIST) private LongArrayList indices; - public DBArrayList() { - super(); + public CowList() { + } - public DBArrayList(JCWDatabase database) throws IOException { + public CowList(IDatabase database) throws IOException { super(database); } @Override - public void initialize() { + public void initialize() throws IOException { indices = new LongArrayList(); } - public T get(int index) { + public T get(int index) throws IOException { synchronized (indicesAccessLock) { - try { - long uid = indices.getLong(index); - return loadItem(uid); - } catch (IOException e) { - throw new IOError(e); - } + long uid = indices.getLong(index); + return loadItem(uid); } } - public void add(T value) { - long uid = database.getDataLoader().allocateNullValue(); + public void add(T value) throws IOException { + long uid = database.getObjectsIO().newNullObject(); synchronized (indicesAccessLock) { indices.add(uid); - try { - writeItemToDisk(uid, value); - } catch (IOException e) { - throw new IOError(e); - } + writeItemToDisk(uid, value); } } - public void update(int index, T value) { + public void update(int index, T value) throws IOException { synchronized (indicesAccessLock) { set(index, value); } } - public void set(int index, T value) { - long uid = database.getDataLoader().allocateNullValue(); + public void set(int index, T value) throws IOException { + long uid = database.getObjectsIO().newNullObject(); synchronized (indicesAccessLock) { indices.set(index, uid); - try { - writeItemToDisk(uid, value); - } catch (IOException e) { - throw new IOError(e); - } + writeItemToDisk(uid, value); } } - public void add(int index, T value) { - long uid = database.getDataLoader().allocateNullValue(); + public void add(int index, T value) throws IOException { + long uid = database.getObjectsIO().newNullObject(); synchronized (indicesAccessLock) { indices.add(index, uid); - try { - writeItemToDisk(uid, value); - } catch (IOException e) { - throw new IOError(e); - } + writeItemToDisk(uid, value); } } - public T getLast() { + public T getLast() throws IOException { synchronized (indicesAccessLock) { if (indices.size() > 0) { return get(indices.size() - 1); @@ -107,7 +94,7 @@ public abstract class DBArrayList extends DBObject { @Override public String toString() { - return new StringJoiner(", ", DBArrayList.class.getSimpleName() + "[", "]") + return new StringJoiner(", ", CowList.class.getSimpleName() + "[", "]") .add(indices.size() + " items") .toString(); } diff --git a/src/main/java/org/warp/cowdb/lists/EnhancedObjectCowList.java b/src/main/java/org/warp/cowdb/lists/EnhancedObjectCowList.java new file mode 100644 index 0000000..e35f22f --- /dev/null +++ b/src/main/java/org/warp/cowdb/lists/EnhancedObjectCowList.java @@ -0,0 +1,33 @@ +package org.warp.cowdb.lists; + +import org.warp.cowdb.EnhancedObject; +import org.warp.cowdb.IDatabase; +import org.warp.jcwdb.ann.DBDataType; +import org.warp.jcwdb.ann.DBField; + +import java.io.IOException; + +public class EnhancedObjectCowList extends CowList { + + @DBField(id = 1, type = DBDataType.OBJECT) + private Class type; + + public EnhancedObjectCowList() { + super(); + } + + public EnhancedObjectCowList(IDatabase database, Class type) throws IOException { + super(database); + this.type = type; + } + + @Override + protected T loadItem(long uid) throws IOException { + return database.getObjectsIO().loadEnhancedObject(uid, type); + } + + @Override + protected void writeItemToDisk(long uid, T item) throws IOException { + database.getObjectsIO().setEnhancedObject(uid, item); + } +} diff --git a/src/main/java/org/warp/cowdb/lists/ObjectCowList.java b/src/main/java/org/warp/cowdb/lists/ObjectCowList.java new file mode 100644 index 0000000..8902c27 --- /dev/null +++ b/src/main/java/org/warp/cowdb/lists/ObjectCowList.java @@ -0,0 +1,29 @@ +package org.warp.cowdb.lists; + +import org.warp.cowdb.EnhancedObject; +import org.warp.cowdb.IDatabase; +import org.warp.jcwdb.ann.DBDataType; +import org.warp.jcwdb.ann.DBField; + +import java.io.IOException; + +public class ObjectCowList extends CowList { + + public ObjectCowList() { + super(); + } + + public ObjectCowList(IDatabase database) throws IOException { + super(database); + } + + @Override + protected T loadItem(long uid) throws IOException { + return database.getObjectsIO().loadObject(uid); + } + + @Override + protected void writeItemToDisk(long uid, T item) throws IOException { + database.getObjectsIO().setObject(uid, item); + } +} diff --git a/src/main/java/org/warp/jcwdb/Castable.java b/src/main/java/org/warp/jcwdb/Castable.java deleted file mode 100644 index 23e04ed..0000000 --- a/src/main/java/org/warp/jcwdb/Castable.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.warp.jcwdb; - -public interface Castable { - T cast(); -} diff --git a/src/main/java/org/warp/jcwdb/Cleanable.java b/src/main/java/org/warp/jcwdb/Cleanable.java deleted file mode 100644 index 57af24c..0000000 --- a/src/main/java/org/warp/jcwdb/Cleanable.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.warp.jcwdb; - -public interface Cleanable { - /** - * Clean the object - * @return the approximated number of cleaned items - */ - public long clean(); -} diff --git a/src/main/java/org/warp/jcwdb/Cleaner.java b/src/main/java/org/warp/jcwdb/Cleaner.java deleted file mode 100644 index 58d792e..0000000 --- a/src/main/java/org/warp/jcwdb/Cleaner.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.warp.jcwdb; - -public class Cleaner { - - public static final boolean DISABLE_CLEANER = false; - public static final boolean ENABLE_CLEANER_LOGGING = false; - private static final double MAXIMUM_SLEEP_INTERVAL = 8d * 1000d; // 8 seconds - private static final double MINIMUM_SLEEP_INTERVAL = 1d * 1000d; // 1 second - private static final double NORMAL_REMOVED_ITEMS = 2500l; - private static final double REMOVED_ITEMS_RATIO = 2.5d; // 250% - - private final Cleanable[] objectsToClean; - private final Thread cleanerThread; - private int sleepInterval = (int) MINIMUM_SLEEP_INTERVAL; - private volatile boolean stopRequest = false; - - public Cleaner(Cleanable... objectsToClean) { - this.objectsToClean = objectsToClean; - this.cleanerThread = new Thread(new CleanLoop()); - this.cleanerThread.setName("Cleaner thread"); - this.cleanerThread.setDaemon(true); - } - - public void start() { - if (!DISABLE_CLEANER) { - this.cleanerThread.start(); - } - } - - /** - * Clean - * @return number of removed items - */ - private long clean() { - long cleanedItems = 0; - for (Cleanable cleanable : objectsToClean) { - cleanedItems += cleanable.clean(); - } - //System.gc(); - return cleanedItems; - } - - public void stop() { - if (cleanerThread != null) { - stopRequest = true; - while (cleanerThread.isAlive()) { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - - private class CleanLoop implements Runnable { - - @Override - public void run() { - while(!stopRequest) { - try { - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Waiting " + sleepInterval + "ms."); - sleepFor(sleepInterval); - final long time1 = System.currentTimeMillis(); - final double removedItems = clean(); - final long time2 = System.currentTimeMillis(); - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] CLEAN_TIME " + (time2 - time1)); - double suggestedExecutionTimeByItemsCalculations = (sleepInterval + MAXIMUM_SLEEP_INTERVAL) / 2; - - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] REMOVED_ITEMS: " + removedItems); - if (removedItems > 0) { - final double removedItemsRatio = removedItems / NORMAL_REMOVED_ITEMS; - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] REMOVED_ITEMS_RATIO: " + removedItemsRatio); - if (removedItemsRatio < 1d / REMOVED_ITEMS_RATIO || removedItemsRatio >= REMOVED_ITEMS_RATIO) { - suggestedExecutionTimeByItemsCalculations = sleepInterval / removedItemsRatio; - } - } - - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Items: SUGGESTING SLEEP_INTERVAL FROM " + sleepInterval + "ms TO " + suggestedExecutionTimeByItemsCalculations + "ms"); - - double newSleepInterval = suggestedExecutionTimeByItemsCalculations; - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Total: SUGGESTING SLEEP_INTERVAL FROM " + sleepInterval + "ms TO " + newSleepInterval + "ms"); - if (newSleepInterval > MAXIMUM_SLEEP_INTERVAL) { - sleepInterval = (int) MAXIMUM_SLEEP_INTERVAL; - } else if (newSleepInterval < MINIMUM_SLEEP_INTERVAL) { - sleepInterval = (int) MINIMUM_SLEEP_INTERVAL; - } else { - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] CHANGED SLEEP_INTERVAL FROM " + sleepInterval + "ms TO " + newSleepInterval + "ms"); - sleepInterval = (int) newSleepInterval; - } - - - if (ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] Cleaned " + removedItems + " items."); - }catch (InterruptedException e) { - - } - } - } - - private void sleepFor(int sleepInterval) throws InterruptedException { - int lastI = (int) Math.ceil(((double) sleepInterval) / 1000d); - for (int i = 0; i < lastI; i++) { - if (stopRequest) { - return; - } - if (i == lastI) { - Thread.sleep(sleepInterval % 1000); - } else { - Thread.sleep(lastI); - } - Thread.sleep(sleepInterval); - } - } - - } -} diff --git a/src/main/java/org/warp/jcwdb/DBReader.java b/src/main/java/org/warp/jcwdb/DBReader.java deleted file mode 100644 index dda81b3..0000000 --- a/src/main/java/org/warp/jcwdb/DBReader.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.warp.jcwdb; - -import com.esotericsoftware.kryo.io.Input; - -public interface DBReader { - T read(Input i, int size); -} diff --git a/src/main/java/org/warp/jcwdb/DBWriter.java b/src/main/java/org/warp/jcwdb/DBWriter.java deleted file mode 100644 index 4e9275e..0000000 --- a/src/main/java/org/warp/jcwdb/DBWriter.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.warp.jcwdb; - -import com.esotericsoftware.kryo.io.Output; - -public interface DBWriter { - void write(Output o); -} diff --git a/src/main/java/org/warp/jcwdb/FileAllocator.java b/src/main/java/org/warp/jcwdb/FileAllocator.java deleted file mode 100644 index afa9649..0000000 --- a/src/main/java/org/warp/jcwdb/FileAllocator.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.warp.jcwdb; - -import it.unimi.dsi.fastutil.longs.Long2IntLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2IntMap; - -import java.io.IOException; -import java.nio.channels.SeekableByteChannel; -import java.util.Collections; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; - -public class FileAllocator implements AutoCloseable { - private static final int MAXIMUM_UNALLOCATED_ENTRIES = 50000; - - private final SeekableByteChannel dataFileChannel; - private volatile long fileSize; - private volatile boolean closed; - private final Object closeLock = new Object(); - private final Object allocateLock = new Object(); - /** - * index -> free space size - */ - private final Long2IntMap freeBytes = new Long2IntLinkedOpenHashMap(); - - public FileAllocator(SeekableByteChannel dataFileChannel) throws IOException { - this.dataFileChannel = dataFileChannel; - this.fileSize = this.dataFileChannel.size(); - } - - public FileAllocator(SeekableByteChannel dataFileChannel, long fileSize, Long2IntMap freeBytes) { - this.dataFileChannel = dataFileChannel; - this.fileSize = fileSize; - this.freeBytes.putAll(freeBytes); - } - - /** - * TODO: not implemented - * - * @param size - * @return offset - */ - public long allocate(int size) { - checkClosed(); - synchronized (allocateLock) { - long offset; - if ((offset = allocateIntoUnusedParts(size)) != -1) { - if (offset + size > fileSize) { - fileSize = offset + size; - } - return offset; - } else { - return allocateToEnd(size); - } - } - } - - private long allocateIntoUnusedParts(int size) { - if (FileIndexManager.ALWAYS_ALLOCATE_NEW) return -1; - Stream> sorted = - freeBytes.entrySet().stream() - .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())); - final VariableWrapper holeOffset = new VariableWrapper<>(-1L); - final VariableWrapper holeSize = new VariableWrapper<>(0); - sorted.anyMatch((entry) -> { - int currentHoleSize = entry.getValue(); - if (currentHoleSize < size) { - return true; - } - holeOffset.var = entry.getKey(); - holeSize.var = currentHoleSize; - return false; - }); - if (holeOffset.var != -1L) { - freeBytes.remove(holeOffset.var); - if (holeSize.var > size) { - freeBytes.put(holeOffset.var + size, holeSize.var - size); - } - } - return holeOffset.var; - } - - private long allocateToEnd(int size) { - long allocatedOffset = fileSize; - fileSize += size; - return allocatedOffset; - } - - - public void close() throws IOException { - if (closed) { - return; - } - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - } - - /** - * Frees the unused bytes - * - * @param startPosition - * @param length - */ - public void markFree(long startPosition, int length) { - checkClosed(); - if (FileIndexManager.ALWAYS_ALLOCATE_NEW) return; - - if (freeBytes.containsKey(startPosition + length)) { - int secondLength = freeBytes.remove(startPosition + length); - freeBytes.put(startPosition, length + secondLength); - } else { - boolean addedToList = false; - for (Long2IntMap.Entry entry : freeBytes.long2IntEntrySet()) { - if (entry.getLongKey() + entry.getIntValue() == startPosition) { - freeBytes.put(entry.getLongKey(), entry.getIntValue() + length); - addedToList = true; - break; - } - } - if (!addedToList && length > 0) { - freeBytes.put(startPosition, length); - } - } - - if (startPosition + length >= fileSize) { - fileSize = startPosition; - } - - // Remove the smallest hole in the file - if (freeBytes.size() > MAXIMUM_UNALLOCATED_ENTRIES) { - Stream> sorted = - freeBytes.entrySet().stream() - .sorted(Map.Entry.comparingByValue()); - Optional> first = sorted.findFirst(); - if (first.isPresent()) { - freeBytes.remove(first.get().getKey()); - } - } - } - - - private void checkClosed() { - if (closed) { - throw new RuntimeException("Index Manager is closed."); - } - } -} diff --git a/src/main/java/org/warp/jcwdb/FileIndexManager.java b/src/main/java/org/warp/jcwdb/FileIndexManager.java deleted file mode 100644 index 4a089cd..0000000 --- a/src/main/java/org/warp/jcwdb/FileIndexManager.java +++ /dev/null @@ -1,495 +0,0 @@ -package org.warp.jcwdb; - -import com.esotericsoftware.kryo.io.Input; -import com.esotericsoftware.kryo.io.Output; -import it.unimi.dsi.fastutil.longs.*; -import it.unimi.dsi.fastutil.objects.ObjectIterator; -import org.warp.jcwdb.ann.DatabaseManager; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; - -public class FileIndexManager implements IndexManager { - public static final boolean ALWAYS_ALLOCATE_NEW = true; - private final SeekableByteChannel dataFileChannel, metadataFileChannel; - private volatile long metadataFileChannelSize; - private final FileAllocator fileAllocator; - private final ByteBuffer metadataByteBuffer = ByteBuffer.allocateDirect(IndexDetails.TOTAL_BYTES); - private final ByteBuffer maskByteBuffer = ByteBuffer.allocateDirect(Long.BYTES); - private volatile boolean closed; - private final Object closeLock = new Object(); - private final Object metadataByteBufferLock = new Object(); - private final Object maskByteBufferLock = new Object(); - private final Object indicesMapsAccessLock = new Object(); - - /** - * Edit this using editIndex() - * Get using getIndexMetadata() - * This hashmap must contain all indices. - */ - private final Long2ObjectMap loadedIndices; - /** - * Edit this using editIndex() - */ - private final LongSet dirtyLoadedIndices, removedIndices; - private long firstAllocableIndex; - - public FileIndexManager(Path dataFile, Path metadataFile) throws IOException { - if (Cleaner.DISABLE_CLEANER) { - loadedIndices = new Long2ObjectOpenHashMap<>(); - dirtyLoadedIndices = new LongOpenHashSet(); - removedIndices = new LongOpenHashSet(); - } else { - loadedIndices = new Long2ObjectLinkedOpenHashMap<>(); - dirtyLoadedIndices = new LongLinkedOpenHashSet(); - removedIndices = new LongLinkedOpenHashSet(); - } - if (Files.notExists(dataFile)) { - Files.createFile(dataFile); - } - if (Files.notExists(metadataFile)) { - Files.createFile(metadataFile); - } - dataFileChannel = Files.newByteChannel(dataFile, StandardOpenOption.READ, StandardOpenOption.WRITE); - metadataFileChannel = Files.newByteChannel(metadataFile, StandardOpenOption.READ, StandardOpenOption.WRITE); - metadataFileChannelSize = metadataFileChannel.size(); - fileAllocator = createFileAllocator(dataFileChannel, metadataFileChannel.position(0)); - firstAllocableIndex = getMetadataFileChannelSize() / (long) IndexDetails.TOTAL_BYTES; - } - - private long getMetadataFileChannelSize() { - return metadataFileChannelSize; - } - - private FileAllocator createFileAllocator(final SeekableByteChannel dataFileChannel, final SeekableByteChannel metadataFileChannel) throws IOException { - if (ALWAYS_ALLOCATE_NEW) { - return new FileAllocator(dataFileChannel); - } else { - Long2IntMap freeBytes = new Long2IntRBTreeMap(); - Long2IntMap usedBytes = new Long2IntRBTreeMap(); - long firstOffset = 0; - metadataFileChannel.position(0); - while (metadataFileChannel.position() + IndexDetails.TOTAL_BYTES <= getMetadataFileChannelSize()) { - IndexDetails indexDetails = readIndexDetailsAt(metadataFileChannel); - if (indexDetails != null) { - long offset = indexDetails.getOffset(); - if (!usedBytes.containsKey(offset) || indexDetails.getSize() > usedBytes.get(offset)) { - usedBytes.put(offset, indexDetails.getSize()); - } - if (offset < firstOffset) { - firstOffset = offset; - } - } - } - - long previousEntryOffset = 0; - long previousEntrySize = 0; - ObjectIterator it = usedBytes.long2IntEntrySet().iterator(); - while (it.hasNext()) { - final Long2IntMap.Entry entry = it.next(); - final long entryOffset = entry.getLongKey(); - final long entrySize = entry.getIntValue(); - it.remove(); - - if (previousEntryOffset + previousEntrySize < entryOffset) { - freeBytes.put(previousEntryOffset + previousEntrySize, (int) (entryOffset - (previousEntryOffset + previousEntrySize))); - } - - previousEntryOffset = entryOffset; - previousEntrySize = entrySize; - } - - final long fileSize = previousEntryOffset + previousEntrySize; - - return new FileAllocator(dataFileChannel, fileSize, freeBytes); - } - } - - @Override - public T get(long index, DBReader reader) throws IOException { - checkClosed(); - IndexDetails details = getIndexMetadata(index); - Input i = new Input(Channels.newInputStream(dataFileChannel.position(details.getOffset())), details.getSize()); - T result = reader.read(i, details.getSize()); - return result; - } - - @Override - public IndexDetails set(long index, int size, DBWriter data) throws IOException { - checkClosed(); - IndexDetails indexDetails = getIndexMetadataUnsafe(index); - if (ALWAYS_ALLOCATE_NEW || indexDetails == null || indexDetails.getSize() < size) { - // Allocate new space - IndexDetails newDetails = allocateAndWrite(index, size, data); - if (indexDetails != null) { - // Mark free the old bytes - fileAllocator.markFree(indexDetails.getOffset(), indexDetails.getSize()); - } - return newDetails; - } else { - // Check if size changed - if (size < indexDetails.getSize()) { - // Mark free the unused bytes - fileAllocator.markFree(indexDetails.getOffset() + size, size); - } - // Update index details - indexDetails = editIndex(index, indexDetails, indexDetails.getOffset(), size); - // Write data - writeExact(indexDetails, size, data); - // Before returning, return IndexDetails - return indexDetails; - } - } - - @Override - public long add(int size) { - checkClosed(); - final long offset = fileAllocator.allocate(size); - final IndexDetails indexDetails = new IndexDetails(offset, size); - final long index = createIndexMetadata(indexDetails); - return index; - } - - @Override - public long add(int size, DBWriter data) throws IOException { - checkClosed(); - final long offset = fileAllocator.allocate(size); - final IndexDetails indexDetails = new IndexDetails(offset, size); - final long index = createIndexMetadata(indexDetails); - writeExact(indexDetails, size, data); - return index; - } - - @Override - public FullIndexDetails addAndGetDetails(int size, DBWriter data) throws IOException { - checkClosed(); - final long offset = fileAllocator.allocate(size); - final IndexDetails indexDetails = new IndexDetails(offset, size); - final long index = createIndexMetadata(indexDetails); - writeExact(indexDetails, size, data); - return new FullIndexDetails(index, indexDetails); - } - - /** - * Write the data at index. - * The input size must be equal to the index size! - */ - private void writeExact(final IndexDetails indexDetails, int size, DBWriter data) throws IOException { - if (indexDetails.getSize() != size) { - throw new IOException("Unable to write " + size + " in a space of " + indexDetails.getSize()); - } - final long offset = indexDetails.getOffset(); - OutputStream os = Channels.newOutputStream(dataFileChannel.position(offset)); - final Output o = new Output(os, size); - data.write(o); - os.flush(); - o.flush(); - } - - private IndexDetails allocateAndWrite(final long index, int size, DBWriter w) throws IOException { - final long offset = fileAllocator.allocate(size); - IndexDetails details = editIndex(index, offset, size); - writeExact(details, size, w); - return details; - } - - @Override - public void delete(long index) throws IOException { - checkClosed(); - IndexDetails indexDetails = getIndexMetadataUnsafe(index); - if (indexDetails != null) { - fileAllocator.markFree(indexDetails.getOffset(), indexDetails.getSize()); - } - synchronized (indicesMapsAccessLock) { - dirtyLoadedIndices.remove(index); - loadedIndices.remove(index); - removedIndices.add(index); - } - } - - public void flushAndUnload(long index) throws IOException { - if (removedIndices.contains(index)) { - synchronized (indicesMapsAccessLock) { - removedIndices.remove(index); - dirtyLoadedIndices.remove(index); - loadedIndices.remove(index); - } - // Update indices metadata - SeekableByteChannel metadata = metadataFileChannel.position(index * IndexDetails.TOTAL_BYTES); - eraseIndexDetails(metadata); - } - boolean isDirty = false; - IndexDetails indexDetails = null; - synchronized (indicesMapsAccessLock) { - if (dirtyLoadedIndices.contains(index)) { - indexDetails = loadedIndices.get(index); - dirtyLoadedIndices.remove(index); - } - } - if (isDirty) { - // Update indices metadata - long position = index * IndexDetails.TOTAL_BYTES; - resizeMetadataFileChannel(position); - SeekableByteChannel metadata = metadataFileChannel.position(position); - writeIndexDetails(metadata, indexDetails); - } - synchronized (indicesMapsAccessLock) { - loadedIndices.remove(index); - } - } - - @Override - public boolean has(long index) { - checkClosed(); - try { - return getIndexMetadataUnsafe(index) != null; - } catch (IOException ex) { - ex.printStackTrace(); - return false; - } - } - - /** - * Edit index data if a change is detected - * @param index - * @param oldData Old index data to check - * @param offset offset - * @param size size - * @return - */ - private IndexDetails editIndex(long index, IndexDetails oldData, long offset, int size) { - if (oldData.getOffset() != offset || oldData.getSize() != size) { - return editIndex(index, offset, size); - } else { - return oldData; - } - } - - /** - * Edit index data - * @param index - * @param offset - * @param size - * @return - */ - private IndexDetails editIndex(long index, long offset, int size) { - IndexDetails indexDetails = new IndexDetails(offset, size); - editIndex(index, indexDetails); - return indexDetails; - } - - /** - * Edit index data - * @param index - * @param details - */ - private void editIndex(long index, IndexDetails details) { - synchronized (indicesMapsAccessLock) { - loadedIndices.put(index, details); - dirtyLoadedIndices.add(index); - } - } - - private long createIndexMetadata(IndexDetails indexDetails) { - synchronized (indicesMapsAccessLock) { - long newIndex = firstAllocableIndex++; - loadedIndices.put(newIndex, indexDetails); - dirtyLoadedIndices.add(newIndex); - removedIndices.remove(newIndex); - return newIndex; - } - } - - private IndexDetails getIndexMetadataUnsafe(long index) throws IOException { - // Return index details if loaded - IndexDetails details; - synchronized (indicesMapsAccessLock) { - details = loadedIndices.getOrDefault(index, null); - } - if (details != null) return details; - - // Try to load the details from file - final long metadataPosition = index * IndexDetails.TOTAL_BYTES; - if (metadataPosition + IndexDetails.TOTAL_BYTES > getMetadataFileChannelSize()) { - // Avoid underflow exception - return null; - } - SeekableByteChannel currentMetadataFileChannel = metadataFileChannel.position(metadataPosition); - IndexDetails indexDetails = readIndexDetailsAt(currentMetadataFileChannel); - - if (indexDetails != null) { - editIndex(index, indexDetails); - return indexDetails; - } - - // No results found. Returning null - return null; - } - - private IndexDetails readIndexDetailsAt(SeekableByteChannel currentMetadataFileChannel) throws IOException { - IndexDetails indexDetails = null; - synchronized (metadataByteBufferLock) { - metadataByteBuffer.rewind(); - currentMetadataFileChannel.read(metadataByteBuffer); - metadataByteBuffer.rewind(); - // If it's not deleted continue - final long offset = metadataByteBuffer.getLong(); - if (offset >= 0) { // If it's < 0 it means that the index has been deleted - final int size = metadataByteBuffer.getInt(); - indexDetails = new IndexDetails(offset, size); - } - } - return indexDetails; - } - - private IndexDetails getIndexMetadata(long index) throws IOException { - IndexDetails details = getIndexMetadataUnsafe(index); - if (details == null) - throw new IOException("Index " + index + " not found"); - else - return details; - } - - @Override - public void close() throws IOException { - if (closed) { - return; - } - synchronized (closeLock) { - if (closed) { - return; - } - closed = true; - } - - // Update indices metadata - flushAllFlushableIndices(); - - // Remove removed indices - removeRemovedIndices(); - fileAllocator.close(); - } - - private void writeIndexDetails(SeekableByteChannel position, IndexDetails indexDetails) throws IOException { - synchronized (metadataByteBufferLock) { - final int size = indexDetails.getSize(); - final long offset = indexDetails.getOffset(); - metadataByteBuffer.rewind(); - metadataByteBuffer.putLong(offset); - metadataByteBuffer.putInt(size); - metadataByteBuffer.rewind(); - position.write(metadataByteBuffer); - } - } - - private void eraseIndexDetails(SeekableByteChannel position) throws IOException { - synchronized (maskByteBufferLock) { - maskByteBuffer.rewind(); - maskByteBuffer.putLong(-1); // -1 = deleted - maskByteBuffer.rewind(); - position.write(maskByteBuffer); - } - } - - private void checkClosed() { - if (closed) { - throw new RuntimeException("Index Manager is closed."); - } - } - - @Override - public long clean() { - long cleaned = 0; - long tim1 = System.currentTimeMillis(); - try { - cleaned += flushAllFlushableIndices(); - } catch (IOException ex) { - ex.printStackTrace(); - } - long tim2 = System.currentTimeMillis(); - try { - cleaned += removeRemovedIndices(); - } catch (IOException ex) { - ex.printStackTrace(); - } - long tim3 = System.currentTimeMillis(); - cleaned += cleanExtraIndices(); - long tim4 = System.currentTimeMillis(); - if (Cleaner.ENABLE_CLEANER_LOGGING) System.out.println("[CLEANER] FileIndexManager CLEAN_TIME: " + (tim2-tim1) + "," + (tim3-tim2) + "," + (tim4-tim3)); - return cleaned; - } - - private long flushAllFlushableIndices() throws IOException { - long flushedIndices = 0; - SeekableByteChannel metadata = metadataFileChannel; - long lastIndex = -2; - synchronized (indicesMapsAccessLock) { - for (long index : dirtyLoadedIndices) { - IndexDetails indexDetails = loadedIndices.get(index); - long position = index * IndexDetails.TOTAL_BYTES; - resizeMetadataFileChannel(position); - if (index - lastIndex != 1) { - metadata = metadata.position(position); - } - writeIndexDetails(metadata, indexDetails); - lastIndex = index; - flushedIndices++; - } - dirtyLoadedIndices.clear(); - } - return flushedIndices; - } - - private void resizeMetadataFileChannel(long position) { - if (position + IndexDetails.TOTAL_BYTES > metadataFileChannelSize) { - metadataFileChannelSize = position + IndexDetails.TOTAL_BYTES; - } - } - - private long removeRemovedIndices() throws IOException { - SeekableByteChannel metadata = metadataFileChannel; - synchronized (indicesMapsAccessLock) { - long removed = this.removedIndices.size(); - for (long index : this.removedIndices) { - metadata = metadata.position(index * IndexDetails.TOTAL_BYTES); - eraseIndexDetails(metadata); - } - this.removedIndices.clear(); - return removed; - } - } - - private long cleanExtraIndices() { - long removedIndices = 0; - LongArrayList toUnload = new LongArrayList(); - synchronized (indicesMapsAccessLock) { - if (loadedIndices.size() > DatabaseManager.MAX_LOADED_INDICES) { - long count = loadedIndices.size(); - LongIterator it = loadedIndices.keySet().iterator(); - while (it.hasNext()) { - long loadedIndex = it.nextLong(); - if (count < DatabaseManager.MAX_LOADED_INDICES * 3l / 2l) { - break; - } - toUnload.add(loadedIndex); - removedIndices++; - count--; - } - } - } - for (long index : toUnload.elements()) { - try { - flushAndUnload(index); - } catch (IOException e) { - e.printStackTrace(); - } - } - return removedIndices; - } -} diff --git a/src/main/java/org/warp/jcwdb/FullIndexDetails.java b/src/main/java/org/warp/jcwdb/FullIndexDetails.java deleted file mode 100644 index 35cc35e..0000000 --- a/src/main/java/org/warp/jcwdb/FullIndexDetails.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.warp.jcwdb; - -public class FullIndexDetails extends IndexDetails { - private final long index; - - public FullIndexDetails(long index, IndexDetails details) { - super(details); - this.index = index; - } - - public long getIndex() { - return index; - } -} diff --git a/src/main/java/org/warp/jcwdb/IndexDetails.java b/src/main/java/org/warp/jcwdb/IndexDetails.java deleted file mode 100644 index d85aeb2..0000000 --- a/src/main/java/org/warp/jcwdb/IndexDetails.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.warp.jcwdb; - -public class IndexDetails { - /** - * The bitmask is used to determine if an index has been deleted - */ - public static final int OFFSET_BYTES = Long.BYTES; - public static final int DATA_SIZE_BYTES = Integer.BYTES; - public static final int TOTAL_BYTES = OFFSET_BYTES + DATA_SIZE_BYTES; - private final long offset; - private final int size; - - public IndexDetails(long offset, int size) { - this.offset = offset; - this.size = size; - } - - public IndexDetails(IndexDetails indexDetails) { - this.offset = indexDetails.offset; - this.size = indexDetails.size; - } - - public long getOffset() { - return offset; - } - - public int getSize() { - return size; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (offset ^ (offset >>> 32)); - result = prime * result + size; - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - IndexDetails other = (IndexDetails) obj; - if (offset != other.offset) - return false; - if (size != other.size) - return false; - return true; - } - - @Override - public String toString() { - return "IndexDetails [offset=" + offset + ", size=" + size + "]"; - } - - -} diff --git a/src/main/java/org/warp/jcwdb/IndexManager.java b/src/main/java/org/warp/jcwdb/IndexManager.java deleted file mode 100644 index d5983b0..0000000 --- a/src/main/java/org/warp/jcwdb/IndexManager.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.warp.jcwdb; - -import java.io.IOException; - -public interface IndexManager extends Cleanable { - T get(long index, DBReader reader) throws IOException; - long add(int size); - long add(int size, DBWriter writer) throws IOException; - FullIndexDetails addAndGetDetails(int size, DBWriter writer) throws IOException; - IndexDetails set(long index, int size, DBWriter writer) throws IOException; - void delete(long index) throws IOException; - boolean has(long index); - void close() throws IOException; -} diff --git a/src/main/java/org/warp/jcwdb/NoParserFoundException.java b/src/main/java/org/warp/jcwdb/NoParserFoundException.java deleted file mode 100644 index 087270d..0000000 --- a/src/main/java/org/warp/jcwdb/NoParserFoundException.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.warp.jcwdb; - -public class NoParserFoundException extends NullPointerException { - - public NoParserFoundException(String string) { - super(string); - } - - /** - * - */ - private static final long serialVersionUID = 701010818132241139L; - -} diff --git a/src/main/java/org/warp/jcwdb/Saveable.java b/src/main/java/org/warp/jcwdb/Saveable.java deleted file mode 100644 index b910fc5..0000000 --- a/src/main/java/org/warp/jcwdb/Saveable.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.warp.jcwdb; - -public interface Saveable { - void save(); - void saveAndFlush(); -} diff --git a/src/main/java/org/warp/jcwdb/ann/DBDBObjectList.java b/src/main/java/org/warp/jcwdb/ann/DBDBObjectList.java deleted file mode 100644 index a96af45..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DBDBObjectList.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.warp.jcwdb.ann; - -import java.io.IOException; - -public class DBDBObjectList extends DBArrayList { - - @DBField(id = 1, type = DBDataType.OBJECT) - private Class type; - - public DBDBObjectList() { - super(); - } - - public DBDBObjectList(JCWDatabase database, Class type) throws IOException { - super(database); - this.type = type; - } - - @Override - protected T loadItem(long uid) throws IOException { - return database.getDataLoader().loadDBObject(type, uid); - } - - @Override - protected void writeItemToDisk(long uid, T item) throws IOException { - database.getDataLoader().writeObjectProperty(uid, DBDataType.DATABASE_OBJECT, item); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/DBDataType.java b/src/main/java/org/warp/jcwdb/ann/DBDataType.java index 24eabb0..9166a39 100644 --- a/src/main/java/org/warp/jcwdb/ann/DBDataType.java +++ b/src/main/java/org/warp/jcwdb/ann/DBDataType.java @@ -9,6 +9,5 @@ public enum DBDataType { CHAR, INTEGER, LONG, - UID_LIST, REFERENCES_LIST } \ No newline at end of file diff --git a/src/main/java/org/warp/jcwdb/ann/DBObject.java b/src/main/java/org/warp/jcwdb/ann/DBObject.java deleted file mode 100644 index e68c9cf..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DBObject.java +++ /dev/null @@ -1,137 +0,0 @@ -package org.warp.jcwdb.ann; - -import org.apache.commons.lang3.reflect.MethodUtils; - -import java.io.IOError; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.Map; - -public abstract class DBObject { - protected JCWDatabase database; - private Field[] fields; - private DBDataType[] fieldTypes; - private long[] fieldUIDs; - - private Method[] propertyGetters; - private Method[] propertySetters; - private DBDataType[] propertyTypes; - private long[] propertyUIDs; - private boolean[] loadedProperties; - private Object[] loadedPropertyValues; - private Map setterMethods; - private Map getterMethods; - private final Object fieldsAccessLock = new Object(); - private final Object propertiesAccessLock = new Object(); - - public DBObject() { - - } - - public DBObject(JCWDatabase database) throws IOException { - this.database = database; - database.initializeDBObject(this); - } - - public abstract void initialize() throws IOException; - - - public T getProperty() { - StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); - StackWalker.StackFrame stackFrame = walker.walk(f -> f.skip(1).findFirst().orElse(null)); - try { - int propertyId = stackFrame.getDeclaringClass().getDeclaredMethod(stackFrame.getMethodName()).getAnnotation(DBPropertyGetter.class).id(); - return getProperty(propertyId); - } catch (IOException | NoSuchMethodException e) { - throw new RuntimeException(e); - } - } - - void setLoadedProperty(int propertyId, T value) { - loadedPropertyValues[propertyId] = value; - loadedProperties[propertyId] = true; - } - - @SuppressWarnings("unchecked") - private T getProperty(int propertyId) throws IOException { - synchronized (propertiesAccessLock) { - if (!loadedProperties[propertyId]) { - long propertyUID = propertyUIDs[propertyId]; - database.getDataLoader().loadProperty(this, propertyId, propertyGetters[propertyId], propertyTypes[propertyId], propertyUID); - } - return (T) loadedPropertyValues[propertyId]; - } - } - - public void setProperty(T value) { - StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); - StackWalker.StackFrame stackFrame = walker.walk(f -> f.skip(1).findFirst().orElse(null)); - DBPropertySetter propertyAnnotation = setterMethods.get(stackFrame.getMethodName()); - setProperty(propertyAnnotation.id(), propertyAnnotation.type(), value); - } - - public void setProperty(int propertyId, DBDataType propertyType, T value) { - synchronized (propertiesAccessLock) { - loadedPropertyValues[propertyId] = value; - loadedProperties[propertyId] = true; - } - } - - public void writeToDisk(long uid) { - //System.err.println("Saving object " + uid + ":" + this); - try { - synchronized (propertiesAccessLock) { - synchronized (fieldsAccessLock) { - database.getDataLoader().writeObjectInfo(uid, fieldUIDs, propertyUIDs); - } - } - synchronized (fieldsAccessLock) { - for (int i = 0; i < fieldUIDs.length; i++) { - try { - database.getDataLoader().writeObjectProperty(fieldUIDs[i], fieldTypes[i], fields[i].get(this)); - } catch (IllegalAccessException e) { - throw new IOError(e); - } - } - } - synchronized (propertiesAccessLock) { - for (int i = 0; i < propertyUIDs.length; i++) { - database.getDataLoader().writeObjectProperty(propertyUIDs[i], propertyTypes[i], loadedPropertyValues[i]); - } - } - } catch (IOException e) { - throw new IOError(e); - } - } - - public final void setFields(Field[] fields, DBDataType[] fieldTypes, long[] fieldUIDs) { - synchronized (fieldsAccessLock) { - this.fields = fields; - this.fieldTypes = fieldTypes; - this.fieldUIDs = fieldUIDs; - } - } - - public final void setProperties(Method[] propertyGetters, Method[] propertySetters, DBDataType[] propertyTypes, long[] propertyUIDs, Map setterMethods, Map getterMethods) { - synchronized (propertiesAccessLock) { - this.propertyGetters = propertyGetters; - this.propertySetters = propertySetters; - this.propertyTypes = propertyTypes; - this.propertyUIDs = propertyUIDs; - this.loadedProperties = new boolean[this.propertyUIDs.length]; - this.loadedPropertyValues = new Object[this.propertyUIDs.length]; - this.setterMethods = setterMethods; - this.getterMethods = getterMethods; - } - } - - Method[] getPropertyGetters() { - return MethodUtils.getMethodsWithAnnotation(this.getClass(), DBPropertyGetter.class); - } - - public Method[] getPropertySetters() { - return MethodUtils.getMethodsWithAnnotation(this.getClass(), DBPropertySetter.class); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/DBObjectIndicesManager.java b/src/main/java/org/warp/jcwdb/ann/DBObjectIndicesManager.java deleted file mode 100644 index 4005946..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DBObjectIndicesManager.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.warp.jcwdb.ann; - -import org.warp.jcwdb.FileIndexManager; - -import java.io.IOError; -import java.io.IOException; - -public class DBObjectIndicesManager { - private final FileIndexManager indices; - - DBObjectIndicesManager(FileIndexManager indices) { - this.indices = indices; - } - - public long allocate(int fieldsCount, int propertiesCount) { - long uid = indices.add(calculateObjectSize(fieldsCount, propertiesCount)); - //System.err.println("ALLOCATED UID " + uid); - return uid; - } - - public void setNull(long uid) throws IOException { - indices.set(uid, 0, (w) -> w.write(new byte[0])); - } - - public void set(long uid, long[] fields, long[] properties) throws IOException { - indices.set(uid, calculateObjectSize(fields, properties), (w) -> { - w.writeInt(fields.length); - w.writeInt(properties.length); - for (int i = 0; i < fields.length; i++) { - w.writeLong(fields[i]); - } - for (int i = 0; i < properties.length; i++) { - w.writeLong(properties[i]); - } - }); - } - - public DBObjectInfo get(long uid) throws IOException { - return indices.get(uid, (i, size) -> { - if (size < Integer.BYTES * 2) { - return null; - } - long[] indices = new long[i.readInt()]; - long[] properties = new long[i.readInt()]; - if (size != calculateObjectSize(indices, properties)) { - throw new IOError(new IOException("The size of the object is different!")); - } - for (int indicesI = 0; indicesI < indices.length; indicesI++) { - indices[indicesI] = i.readLong(); - } - for (int propertiesI = 0; propertiesI < properties.length; propertiesI++) { - properties[propertiesI] = i.readLong(); - } - return new DBObjectInfo(indices, properties); - }); - } - - public boolean has(long uid) { - return indices.has(uid); - } - - private int calculateObjectSize(long[] fields, long[] properties) { - return calculateObjectSize(fields.length, properties.length); - } - - private int calculateObjectSize(int fieldsCount, int propertiesCount) { - return Integer.BYTES * 2 + (fieldsCount + propertiesCount) * Long.BYTES; - } - - public class DBObjectInfo { - private final long[] fields; - private final long[] properties; - - public DBObjectInfo(long[] fields, long[] properties) { - this.fields = fields; - this.properties = properties; - } - - public long[] getFields() { - return fields; - } - - public long[] getProperties() { - return properties; - } - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/DBObjectList.java b/src/main/java/org/warp/jcwdb/ann/DBObjectList.java deleted file mode 100644 index 0063fee..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DBObjectList.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.warp.jcwdb.ann; - -import java.io.IOException; - -public class DBObjectList extends DBArrayList { - - public DBObjectList() { - - } - - public DBObjectList(JCWDatabase database) throws IOException { - super(database); - } - - @Override - public T loadItem(long uid) throws IOException { - return database.getDataLoader().loadObject(uid); - } - - @Override - public void writeItemToDisk(long uid, T item) throws IOException { - database.getDataLoader().writeObjectProperty(uid, DBDataType.OBJECT, item); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/DataInitializer.java b/src/main/java/org/warp/jcwdb/ann/DataInitializer.java deleted file mode 100644 index d980a93..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DataInitializer.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.warp.jcwdb.ann; - -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.LinkedHashMap; -import java.util.Map; - -public class DataInitializer { - private final DataLoader dataLoader; - - public DataInitializer(DataLoader dataLoader) { - this.dataLoader = dataLoader; - } - - public void initializeDBObject(DBObject obj) throws IOException { - initializeDBObjectFields(obj); - initializeDBObjectProperties(obj); - obj.initialize(); - } - - private void initializeDBObjectFields(DBObject obj) throws IOException { - // Declare the variables needed to get the biggest field Id - Field[] unorderedFields = dataLoader.getFields(obj); - // Find the biggest field Id - int biggestFieldId = dataLoader.getBiggestFieldId(unorderedFields); - - // Allocate new UIDs - long[] fieldUIDs = dataLoader.allocateNewUIDs(biggestFieldId + 1); - - // Declare the other variables - Field[] fields = new Field[biggestFieldId + 1]; - DBDataType[] orderedFieldTypes = new DBDataType[biggestFieldId + 1]; - - // Load all fields metadata and load them - for (Field field : unorderedFields) { - DBField fieldAnnotation = field.getAnnotation(DBField.class); - int fieldId = fieldAnnotation.id(); - DBDataType fieldType = fieldAnnotation.type(); - dataLoader.loadField(obj, field, fieldType, fieldUIDs[fieldId]); - fields[fieldId] = field; - orderedFieldTypes[fieldId] = fieldType; - } - // Set fields metadata - obj.setFields(fields, orderedFieldTypes, fieldUIDs); - } - - private void initializeDBObjectProperties(DBObject obj) { - // Declare the variables needed to get the biggest property Id - Method[] unorderedPropertyGetters = obj.getPropertyGetters(); - Method[] unorderedPropertySetters = obj.getPropertySetters(); - - // Find the biggest property Id - int biggestGetter = dataLoader.getBiggestPropertyGetterId(unorderedPropertyGetters); - int biggestSetter = dataLoader.getBiggestPropertySetterId(unorderedPropertySetters); - int biggestPropertyId = biggestGetter > biggestSetter ? biggestGetter : biggestSetter; - - // Allocate new UIDs - long[] propertyUIDs = dataLoader.allocateNewUIDs(biggestPropertyId + 1); - - for (Method property : unorderedPropertySetters) { - DBPropertySetter fieldAnnotation = property.getAnnotation(DBPropertySetter.class); - int propertyId = fieldAnnotation.id(); - if (propertyId > biggestPropertyId) { - biggestPropertyId = propertyId; - } - } - - // Declare the other variables - DBDataType[] propertyTypes = new DBDataType[biggestPropertyId + 1]; - Method[] propertyGetters = new Method[biggestPropertyId + 1]; - Method[] propertySetters = new Method[biggestPropertyId + 1]; - Map setterMethods = new LinkedHashMap<>(); - Map getterMethods = new LinkedHashMap<>(); - - // Load the properties metadata - for (Method property : unorderedPropertyGetters) { - DBPropertyGetter propertyAnnotation = property.getAnnotation(DBPropertyGetter.class); - int propertyId = propertyAnnotation.id(); - DBDataType propertyType = propertyAnnotation.type(); - propertyTypes[propertyId] = propertyType; - propertyGetters[propertyId] = property; - getterMethods.put(property.getName(), propertyAnnotation); - } - for (Method property : unorderedPropertySetters) { - DBPropertySetter propertyAnnotation = property.getAnnotation(DBPropertySetter.class); - int propertyId = propertyAnnotation.id(); - DBDataType propertyType = propertyAnnotation.type(); - propertyTypes[propertyId] = propertyType; - propertySetters[propertyId] = property; - setterMethods.put(property.getName(), propertyAnnotation); - } - // Set properties metadata - obj.setProperties(propertyGetters, propertySetters, propertyTypes, propertyUIDs, setterMethods, getterMethods); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/DataLoader.java b/src/main/java/org/warp/jcwdb/ann/DataLoader.java deleted file mode 100644 index 2acd136..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DataLoader.java +++ /dev/null @@ -1,645 +0,0 @@ -package org.warp.jcwdb.ann; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.io.Output; -import it.unimi.dsi.fastutil.booleans.BooleanArrayList; -import it.unimi.dsi.fastutil.bytes.ByteArrayList; -import it.unimi.dsi.fastutil.chars.CharArrayList; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.shorts.ShortArrayList; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.apache.commons.lang3.reflect.MethodUtils; -import org.warp.jcwdb.FileIndexManager; - -import java.io.ByteArrayOutputStream; -import java.io.IOError; -import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Path; -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class DataLoader { - - private final Kryo kryo = new Kryo(); - private final DBObjectIndicesManager objectIndicesManager; - private final FileIndexManager indices; - private final Object indicesAccessLock = new Object(); - private volatile boolean closed; - /** - * DO NOT USE - */ - private JCWDatabase databaseInstance; - - public DataLoader(JCWDatabase databaseInstance, Path dataFile, Path metadataFile, boolean registrationRequired) throws IOException { - synchronized (indicesAccessLock) { - this.databaseInstance = databaseInstance; - this.indices = new FileIndexManager(dataFile, metadataFile); - if (!indices.has(0)) { - allocateNullValue(); - } - this.objectIndicesManager = new DBObjectIndicesManager(this.indices); - kryo.setRegistrationRequired(registrationRequired); - registerDefaultClasses(); - } - } - - private void registerDefaultClasses() { - int id = -90; - registerClass(boolean[].class, id++); - registerClass(byte[].class, id++); - registerClass(short[].class, id++); - registerClass(char[].class, id++); - registerClass(int[].class, id++); - registerClass(long[].class, id++); - registerClass(Boolean[].class, id++); - registerClass(Byte[].class, id++); - registerClass(Short[].class, id++); - registerClass(Character[].class, id++); - registerClass(Integer[].class, id++); - registerClass(Long[].class, id++); - registerClass(String.class, id++); - registerClass(String[].class, id++); - registerClass(Boolean.class, id++); - registerClass(Byte.class, id++); - registerClass(Short.class, id++); - registerClass(Character.class, id++); - registerClass(Integer.class, id++); - registerClass(Class.class, id++); - registerClass(Object.class, id++); - registerClass(Object[].class, id++); - registerClass(Long.class, id++); - registerClass(String.class, id++); - registerClass(String[].class, id++); - registerClass(boolean[][].class, id++); - registerClass(byte[][].class, id++); - registerClass(short[][].class, id++); - registerClass(char[][].class, id++); - registerClass(int[][].class, id++); - registerClass(long[][].class, id++); - registerClass(String[][].class, id++); - registerClass(List.class, id++); - registerClass(ArrayList.class, id++); - registerClass(LinkedList.class, id++); - registerClass(Set.class, id++); - registerClass(HashSet.class, id++); - registerClass(LinkedHashSet.class, id++); - registerClass(Map.class, id++); - registerClass(HashMap.class, id++); - registerClass(LinkedHashMap.class, id++); - registerClass(TreeMap.class, id++); - registerClass(BooleanArrayList.class, id++); - registerClass(ByteArrayList.class, id++); - registerClass(ShortArrayList.class, id++); - registerClass(CharArrayList.class, id++); - registerClass(IntArrayList.class, id++); - registerClass(LongArrayList.class, id++); - registerClass(TreeSet.class, id++); - registerClass(SortedSet.class, id++); - registerClass(SortedMap.class, id++); - } - - public void close() throws IOException { - synchronized (indicesAccessLock) { - if (!closed) { - closed = true; - indices.close(); - } - } - } - - public void preloadDBObject(DBObject obj, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - synchronized (indicesAccessLock) { - preloadDBObjectFields(obj, objectInfo.getFields()); - preloadDBObjectProperties(obj, objectInfo.getProperties()); - } - } - - T loadRoot(Class rootType, SupplierWithIO ifAbsent) throws IOException { - synchronized (indicesAccessLock) { - if (isDBObjectNull(0)) { - return ifAbsent.getWithIO(); - } else { - return loadDBObject(rootType, 0); - } - } - } - - private T instantiateDBObject(Class type) throws IOException { - synchronized (indicesAccessLock) { - try { - T obj = type.getConstructor().newInstance(); - obj.database = databaseInstance; - return obj; - } catch (NoSuchMethodException e) { - throw new IOException("You must declare a public empty constructor in class " + type + ": public " + type.getSimpleName() + "()", e); - } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - throw new IOException(e); - } - } - } - - private void preloadDBObjectFields(DBObject obj, long[] fieldUIDs) throws IOException { - synchronized (indicesAccessLock) { - // Declare the variables needed to get the biggest field Id - Field[] unorderedFields = getFields(obj); - // Find the biggest field Id - int biggestFieldId = getBiggestFieldId(unorderedFields); - - // Declare the other variables - Field[] fields = new Field[biggestFieldId + 1]; - DBDataType[] orderedFieldTypes = new DBDataType[biggestFieldId + 1]; - - // Load all fields metadata and load them - for (Field field : unorderedFields) { - DBField fieldAnnotation = field.getAnnotation(DBField.class); - int fieldId = fieldAnnotation.id(); - DBDataType fieldType = fieldAnnotation.type(); - loadField(obj, field, fieldType, fieldUIDs[fieldId]); - fields[fieldId] = field; - orderedFieldTypes[fieldId] = fieldType; - } - // Set fields metadata - obj.setFields(fields, orderedFieldTypes, fieldUIDs); - } - } - - private void preloadDBObjectProperties(DBObject obj, long[] propertyUIDs) { - synchronized (indicesAccessLock) { - // Declare the variables needed to get the biggest property Id - Method[] unorderedPropertyGetters = obj.getPropertyGetters(); - Method[] unorderedPropertySetters = obj.getPropertySetters(); - - // Find the biggest property Id - int biggestGetter = getBiggestPropertyGetterId(unorderedPropertyGetters); - int biggestSetter = getBiggestPropertySetterId(unorderedPropertySetters); - int biggestPropertyId = biggestGetter > biggestSetter ? biggestGetter : biggestSetter; - - for (Method property : unorderedPropertySetters) { - DBPropertySetter fieldAnnotation = property.getAnnotation(DBPropertySetter.class); - int propertyId = fieldAnnotation.id(); - if (propertyId > biggestPropertyId) { - biggestPropertyId = propertyId; - } - } - - // Declare the other variables - DBDataType[] propertyTypes = new DBDataType[biggestPropertyId + 1]; - Method[] propertyGetters = new Method[biggestPropertyId + 1]; - Method[] propertySetters = new Method[biggestPropertyId + 1]; - Map setterMethods = new LinkedHashMap<>(); - Map getterMethods = new LinkedHashMap<>(); - - // Load the properties metadata - for (Method property : unorderedPropertyGetters) { - DBPropertyGetter propertyAnnotation = property.getAnnotation(DBPropertyGetter.class); - int propertyId = propertyAnnotation.id(); - DBDataType propertyType = propertyAnnotation.type(); - propertyTypes[propertyId] = propertyType; - propertyGetters[propertyId] = property; - getterMethods.put(property.getName(), propertyAnnotation); - } - for (Method property : unorderedPropertySetters) { - DBPropertySetter propertyAnnotation = property.getAnnotation(DBPropertySetter.class); - int propertyId = propertyAnnotation.id(); - DBDataType propertyType = propertyAnnotation.type(); - propertyTypes[propertyId] = propertyType; - propertySetters[propertyId] = property; - setterMethods.put(property.getName(), propertyAnnotation); - } - // Set properties metadata - obj.setProperties(propertyGetters, propertySetters, propertyTypes, propertyUIDs, setterMethods, getterMethods); - } - } - - - protected Field[] getFields(DBObject obj) { - synchronized (indicesAccessLock) { - return FieldUtils.getFieldsWithAnnotation(obj.getClass(), DBField.class); - } - } - - - int getBiggestPropertyGetterId(Method[] unorderedPropertyGetters) { - synchronized (indicesAccessLock) { - int biggestPropertyId = -1; - for (Method property : unorderedPropertyGetters) { - DBPropertyGetter fieldAnnotation = property.getAnnotation(DBPropertyGetter.class); - int propertyId = fieldAnnotation.id(); - if (propertyId > biggestPropertyId) { - biggestPropertyId = propertyId; - } - } - return biggestPropertyId; - } - } - - int getBiggestPropertySetterId(Method[] unorderedPropertySetters) { - synchronized (indicesAccessLock) { - int biggestPropertyId = -1; - for (Method property : unorderedPropertySetters) { - DBPropertySetter fieldAnnotation = property.getAnnotation(DBPropertySetter.class); - int propertyId = fieldAnnotation.id(); - if (propertyId > biggestPropertyId) { - biggestPropertyId = propertyId; - } - } - return biggestPropertyId; - } - } - - - protected int getBiggestFieldId(Field[] unorderedFields) { - synchronized (indicesAccessLock) { - int biggestFieldId = -1; - for (Field field : unorderedFields) { - DBField fieldAnnotation = field.getAnnotation(DBField.class); - int propertyId = fieldAnnotation.id(); - if (propertyId > biggestFieldId) { - biggestFieldId = propertyId; - } - } - return biggestFieldId; - } - } - - public void loadProperty(DBObject obj, int propertyId, Method property, DBDataType propertyType, long propertyUID) throws IOException { - synchronized (indicesAccessLock) { - loadData(propertyType, propertyUID, property::getReturnType, (data) -> { - synchronized (indicesAccessLock) { - obj.setLoadedProperty(propertyId, data); - } - }); - } - } - - public void loadField(DBObject obj, Field field, DBDataType fieldType, long fieldUID) throws IOException { - synchronized (indicesAccessLock) { - loadData(fieldType, fieldUID, field::getType, (data) -> { - synchronized (indicesAccessLock) { - try { - if (fieldType == DBDataType.OBJECT && data != null) { - if (!field.getType().isInstance(data)) { - throw new IOException("There is an attempt to load an object of type " + data.getClass() + " into a field of type " + field.getType()); - } - } - FieldUtils.writeField(field, obj, data, true); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - }); - } - } - - @SuppressWarnings("unchecked") - private void loadData(DBDataType propertyType, long dataUID, Supplier> returnType, ConsumerWithIO result) throws IOException { - synchronized (indicesAccessLock) { - switch (propertyType) { - case DATABASE_OBJECT: - DBObject fieldDBObjectValue = loadDBObject((Class) returnType.get(), dataUID); - //System.err.println("Loading data DBObj " + dataUID + ":" + fieldDBObjectValue); - result.accept(fieldDBObjectValue); - return; - case OBJECT: - Object fieldObjectValue = loadObject(dataUID); - //System.err.println("Loading data Obj " + dataUID + ":" + fieldObjectValue); - result.accept(fieldObjectValue); - return; - case UID_LIST: - LongArrayList fieldListObjectValue = loadListObject(dataUID); - //System.err.println("Loading data LOb " + dataUID + ":" + fieldListObjectValue); - result.accept(fieldListObjectValue); - return; - case BOOLEAN: - boolean fieldBooleanValue = loadBoolean(dataUID); - //System.err.println("Loading data Boo " + dataUID + ":" + fieldBooleanValue); - result.accept(fieldBooleanValue); - return; - case BYTE: - byte fieldByteValue = loadByte(dataUID); - //System.err.println("Loading data Byt " + dataUID + ":" + fieldByteValue); - result.accept(fieldByteValue); - return; - case SHORT: - short fieldShortValue = loadShort(dataUID); - //System.err.println("Loading data Shr " + dataUID + ":" + fieldShortValue); - result.accept(fieldShortValue); - return; - case CHAR: - char fieldCharValue = loadChar(dataUID); - //System.err.println("Loading data Chr " + dataUID + ":" + fieldCharValue); - result.accept(fieldCharValue); - return; - case INTEGER: - int fieldIntValue = loadInt(dataUID); - //System.err.println("Loading data Int " + dataUID + ":" + fieldIntValue); - result.accept(fieldIntValue); - return; - case LONG: - long fieldLongValue = loadLong(dataUID); - //System.err.println("Loading data Lng " + dataUID + ":" + fieldLongValue); - result.accept(fieldLongValue); - return; - default: - throw new NullPointerException("Unknown data type"); - } - } - } - - - public T loadDBObject(Class type, long propertyUID) throws IOException { - synchronized (indicesAccessLock) { - DBObjectIndicesManager.DBObjectInfo objectInfo = readUIDs(propertyUID); - if (objectInfo == null) return null; - T obj = instantiateDBObject(type); - preloadDBObject(obj, objectInfo); - return obj; - } - } - - private boolean isDBObjectNull(long uid) { - synchronized (indicesAccessLock) { - try { - return !objectIndicesManager.has(uid) || objectIndicesManager.get(uid) == null; - } catch (IOException ex) { - throw new IOError(ex); - } - } - } - - @SuppressWarnings("unchecked") - public T loadObject(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - synchronized (indicesAccessLock) { - if (size != 0) { - return (T) kryo.readClassAndObject(i); - } else { - return null; - } - } - }); - } - } - - private LongArrayList loadListObject(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - synchronized (indicesAccessLock) { - if (size != 0) { - LongArrayList list = new LongArrayList(); - int listSize = i.readVarInt(true); - for (int li = 0; li < listSize; li++) { - list.add(i.readVarLong(true)); - } - return list; - } else { - return null; - } - } - }); - } - } - - public boolean loadBoolean(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - synchronized (indicesAccessLock) { - if (size != 0) { - return i.readBoolean(); - } else { - return false; - } - } - }); - } - } - - public byte loadByte(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - synchronized (indicesAccessLock) { - if (size != 0) { - return i.readByte(); - } else { - return (byte) 0; - } - } - }); - } - } - - public short loadShort(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - synchronized (indicesAccessLock) { - if (size != 0) { - return i.readShort(); - } else { - return (short) 0; - } - } - }); - } - } - - public char loadChar(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - synchronized (indicesAccessLock) { - if (size != 0) { - return i.readChar(); - } else { - return (char) 0; - } - } - }); - } - } - - - public int loadInt(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - if (size != 0) { - return i.readInt(); - } else { - return 0; - } - }); - } - } - - public long loadLong(long uid) throws IOException { - synchronized (indicesAccessLock) { - return indices.get(uid, (i, size) -> { - synchronized (indicesAccessLock) { - if (size != 0) { - return i.readLong(); - } else { - return 0L; - } - } - }); - } - } - public boolean exists(long uid) { - synchronized (indicesAccessLock) { - return objectIndicesManager.has(uid); - } - } - - public void writeObjectInfo(long uid, long[] fieldUIDs, long[] propertyUIDs) throws IOException { - synchronized (indicesAccessLock) { - //System.err.println("Saving obj. " + uid); - this.objectIndicesManager.set(uid, fieldUIDs, propertyUIDs); - } - } - - private void writeObjectInfoNull(long uid) throws IOException { - synchronized (indicesAccessLock) { - this.objectIndicesManager.setNull(uid); - } - } - - /** - * - * @param uid - * @return - */ - public DBObjectIndicesManager.DBObjectInfo readUIDs(long uid) { - synchronized (indicesAccessLock) { - try { - return objectIndicesManager.get(uid); - } catch (IOException e) { - throw new IOError(e); - } - } - } - - - public void writeObjectProperty(long uid, DBDataType propertyType, T loadedPropertyValue) throws IOException { - synchronized (indicesAccessLock) { - switch (propertyType) { - case BOOLEAN: - indices.set(uid, 1, (o) -> { - synchronized (indicesAccessLock) { - o.writeBoolean(loadedPropertyValue == null ? false : (boolean) loadedPropertyValue); - } - }); - //System.err.println("Saving data Boo " + uid + ":" + loadedPropertyValue); - break; - case BYTE: - indices.set(uid, Byte.BYTES, (o) -> { - synchronized (indicesAccessLock) { - o.writeByte(loadedPropertyValue == null ? 0 : (byte) loadedPropertyValue); - } - }); - //System.err.println("Saving data Byt " + uid + ":" + loadedPropertyValue); - break; - case SHORT: - indices.set(uid, Short.BYTES, (o) -> { - synchronized (indicesAccessLock) { - o.writeShort(loadedPropertyValue == null ? 0 : (short) loadedPropertyValue); - } - }); - //System.err.println("Saving data Shr " + uid + ":" + loadedPropertyValue); - break; - case CHAR: - indices.set(uid, Character.BYTES, (o) -> { - synchronized (indicesAccessLock) { - o.writeChar(loadedPropertyValue == null ? 0 : (char) loadedPropertyValue); - } - }); - //System.err.println("Saving data Chr " + uid + ":" + loadedPropertyValue); - break; - case INTEGER: - indices.set(uid, Integer.BYTES, (o) -> { - synchronized (indicesAccessLock) { - o.writeInt(loadedPropertyValue == null ? 0 : (int) loadedPropertyValue); - } - }); - //System.err.println("Saving data Int " + uid + ":" + loadedPropertyValue); - break; - case LONG: - indices.set(uid, Long.BYTES, (o) -> { - synchronized (indicesAccessLock) { - o.writeLong(loadedPropertyValue == null ? 0 : (long) loadedPropertyValue); - } - }); - //System.err.println("Saving data Lng " + uid + ":" + loadedPropertyValue); - break; - case OBJECT: - Output baosOutput = new Output(new ByteArrayOutputStream()); - kryo.writeClassAndObject(baosOutput, loadedPropertyValue); - //System.err.println("Saving data Obj " + uid + ":" + loadedPropertyValue); - if (loadedPropertyValue instanceof Class) { - System.out.println(); - } - byte[] out = baosOutput.toBytes(); - indices.set(uid, out.length, o -> { - synchronized (indicesAccessLock) { - o.write(out, 0, out.length); - } - }); - break; - case UID_LIST: - if (loadedPropertyValue == null) { - indices.set(uid, 0, (o) -> { - }); - } else { - LongArrayList list = (LongArrayList) loadedPropertyValue; - final int listSize = list.size(); - Output baosListOutput = new Output(Long.BYTES * 100, Long.BYTES * (listSize > 100 ? listSize : 100)); - baosListOutput.writeVarInt(listSize, true); - for (int i = 0; i < listSize; i++) { - baosListOutput.writeVarLong(list.getLong(i), true); - } - //System.err.println("Saving data LOb " + uid + ":" + loadedPropertyValue); - byte[] outList = baosListOutput.toBytes(); - indices.set(uid, outList.length, o -> { - synchronized (indicesAccessLock) { - o.write(outList, 0, outList.length); - } - }); - } - break; - case DATABASE_OBJECT: - //System.err.println("Saving data DBObj " + uid + ":" + loadedPropertyValue); - if (loadedPropertyValue == null) { - writeObjectInfoNull(uid); - } else { - ((DBObject) loadedPropertyValue).writeToDisk(uid); - } - break; - } - } - } - - public void registerClass(Class clazz, int id) { - synchronized (indicesAccessLock) { - kryo.register(clazz, 100 + id); - } - } - - public long allocateNullValue() { - synchronized (indicesAccessLock) { - return indices.add(0); - } - } - - public long[] allocateNewUIDs(int quantity) { - synchronized (indicesAccessLock) { - long[] ids = new long[quantity]; - for (int i = 0; i < quantity; i++) { - ids[i] = allocateNullValue(); - } - return ids; - } - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/DatabaseManager.java b/src/main/java/org/warp/jcwdb/ann/DatabaseManager.java deleted file mode 100644 index 875b61f..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DatabaseManager.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.warp.jcwdb.ann; - -import org.warp.jcwdb.Cleanable; -import org.warp.jcwdb.Cleaner; - -import java.io.IOException; -import java.util.function.Supplier; - -public class DatabaseManager implements Cleanable { - - public static final long MAX_LOADED_INDICES = 100000; - private final Cleaner cleaner; - private final DataLoader dataLoader; - private DBObject loadedRootObject = null; - private volatile boolean closed; - - DatabaseManager(DataLoader dataLoader) { - this.dataLoader = dataLoader; - this.cleaner = new Cleaner(this); - this.cleaner.start(); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - try { - DatabaseManager.this.close(); - } catch (Exception e) { - e.printStackTrace(); - } - })); - } - - public T loadRoot(Class rootType, SupplierWithIO ifAbsent) throws IOException { - if (loadedRootObject != null) { - throw new RuntimeException("Root already set!"); - } - T root = dataLoader.loadRoot(rootType, ifAbsent); - loadedRootObject = root; - return root; - } - - public void close() throws IOException { - if (!closed) { - closed = true; - DatabaseManager.this.cleaner.stop(); - if (loadedRootObject != null) { - loadedRootObject.writeToDisk(0); - } - dataLoader.close(); - } - } - - @Override - public long clean() { - return 0;//indices.clean(); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/JCWDatabase.java b/src/main/java/org/warp/jcwdb/ann/JCWDatabase.java deleted file mode 100644 index fbde022..0000000 --- a/src/main/java/org/warp/jcwdb/ann/JCWDatabase.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.warp.jcwdb.ann; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.nio.file.Path; -import java.util.function.Supplier; - -public class JCWDatabase { - private final DatabaseManager database; - private final DataLoader dataLoader; - private final DataInitializer dataInitializer; - - public JCWDatabase(Path dataFile, Path metadataFile, boolean registrationRequired) throws IOException { - this.dataLoader = new DataLoader(this, dataFile, metadataFile, registrationRequired); - this.dataInitializer = new DataInitializer(dataLoader); - this.database = new DatabaseManager(dataLoader); - } - - public T loadRoot(Class rootClass) throws IOException { - return loadRoot(rootClass, () -> { - try { - return rootClass.getConstructor(JCWDatabase.class).newInstance(this); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - throw new IOException(e); - } - }); - } - - public T loadRoot(Class rootClass, SupplierWithIO ifAbsent) throws IOException { - return database.loadRoot(rootClass, ifAbsent); - } - - public void registerClass(Class clazz, int id) { - if (id < 0) { - throw new IllegalArgumentException(); - } - dataLoader.registerClass(clazz, id); - } - - public void close() throws IOException { - database.close(); - } - - public DataLoader getDataLoader() { - return dataLoader; - } - - public DataInitializer getDataInitializer() { - return dataInitializer; - } - - public void initializeDBObject(DBObject dbObject) throws IOException { - dataInitializer.initializeDBObject(dbObject); - } -} diff --git a/src/test/java/org/warp/jcwdb/tests/DBDBObjectListTests.java b/src/test/java/org/warp/jcwdb/tests/DBDBObjectListTests.java deleted file mode 100644 index f362f50..0000000 --- a/src/test/java/org/warp/jcwdb/tests/DBDBObjectListTests.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.warp.jcwdb.tests; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.warp.jcwdb.ann.*; -import org.warp.jcwdb.utils.TestUtils; - -import java.io.IOException; - -import static org.junit.Assert.*; - -public class DBDBObjectListTests { - private TestUtils.WrappedDb db; - private RootWithList root; - - @Before - public void setUp() throws Exception { - db = TestUtils.wrapDb().create((db) -> { - db.get().registerClass(TestUtils.class, 0); - db.get().registerClass(TestUtils.RootClass.class, 1); - db.get().registerClass(Class.class, 2); - System.out.println("Loading root"); - root = db.get().loadRoot(RootWithList.class); - }); - root.list = new DBDBObjectList<>(db.get(), TestUtils.RootClass.class); - for (int i = 0; i < 100; i++) { - TestUtils.RootClass rootClass = new TestUtils.RootClass(db.get()); - db.setRootClassValues(rootClass); - root.list.add(rootClass); - } - db.closeAndReopen(); - for (int i = 0; i < 100; i++) { - TestUtils.RootClass rootClass = new TestUtils.RootClass(db.get()); - db.setRootClassValues(rootClass); - root.list.add(rootClass); - } - } - - @Test - public void shouldMatchList() throws IOException { - checkEmptyList(); - assertEquals(200, root.list.size()); - for (int i = 0; i < 200; i++) { - db.testRootClassValues(root.list.get(i)); - } - } - - private void checkEmptyList() throws IOException { - DBObjectList list = new DBObjectList<>(db.get()); - assertEquals(null, list.getLast()); - assertEquals(0, list.size()); - assertTrue(list.isEmpty()); - list.add("1"); - assertEquals(1, list.size()); - assertEquals("1", list.getLast()); - assertFalse(list.isEmpty()); - } - - @After - public void tearDown() throws Exception { - db.delete(); - } - - public static class RootWithList extends DBObject { - - @DBField(id = 0, type = DBDataType.DATABASE_OBJECT) - public DBDBObjectList list; - - public RootWithList() { - super(); - } - - public RootWithList(JCWDatabase database) throws IOException { - super(database); - } - - @Override - public void initialize() throws IOException { - list = new DBDBObjectList<>(database, TestUtils.RootClass.class); - } - } -} diff --git a/src/test/java/org/warp/jcwdb/tests/DBMultipleDBObjects.java b/src/test/java/org/warp/jcwdb/tests/DBMultipleDBObjects.java deleted file mode 100644 index dc378fe..0000000 --- a/src/test/java/org/warp/jcwdb/tests/DBMultipleDBObjects.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.warp.jcwdb.tests; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.warp.jcwdb.ann.*; -import org.warp.jcwdb.utils.TestUtils; - -import java.io.IOException; - -public class DBMultipleDBObjects { - private TestUtils.WrappedDb db; - private RootTwoClasses root; - - @Before - public void setUp() throws Exception { - db = TestUtils.wrapDb().create((db) -> { - root = db.get().loadRoot(RootTwoClasses.class); - }); - root.class1 = new TestUtils.RootClass(db.get()); - db.setRootClassValues(root.class1); - root.class2 = new TestUtils.RootClass(db.get()); - db.setRootClassValues(root.class2); - root.setClass3(new TestUtils.RootClass(db.get())); - db.setRootClassValues(root.getClass3()); - root.setClass4(new TestUtils.RootClass(db.get())); - db.setRootClassValues(root.getClass4()); - db.closeAndReopen(); - } - - @Test - public void shouldMatchMultipleObjects() { - db.testRootClassValues(root.class1); - db.testRootClassValues(root.class2); - db.testRootClassValues(root.getClass3()); - db.testRootClassValues(root.getClass4()); - } - - @After - public void tearDown() throws Exception { - db.delete(); - } - - public static class RootTwoClasses extends DBObject { - - @DBField(id = 0, type = DBDataType.DATABASE_OBJECT) - public TestUtils.RootClass class1; - - @DBField(id = 1, type = DBDataType.DATABASE_OBJECT) - public TestUtils.RootClass class2; - - public RootTwoClasses() { - super(); - } - - public RootTwoClasses(JCWDatabase database) throws IOException { - super(database); - } - - @DBPropertyGetter(id = 0, type = DBDataType.DATABASE_OBJECT) - public TestUtils.RootClass getClass3() { - return getProperty(); - } - - @DBPropertySetter(id = 0, type = DBDataType.DATABASE_OBJECT) - public void setClass3(TestUtils.RootClass value) { - setProperty(value); - } - - @DBPropertyGetter(id = 1, type = DBDataType.DATABASE_OBJECT) - public TestUtils.RootClass getClass4() { - return getProperty(); - } - - @DBPropertySetter(id = 1, type = DBDataType.DATABASE_OBJECT) - public void setClass4(TestUtils.RootClass value) { - setProperty(value); - } - - @Override - public void initialize() throws IOException { - - } - } -} diff --git a/src/test/java/org/warp/jcwdb/tests/DBNestedDBObjects.java b/src/test/java/org/warp/jcwdb/tests/DBNestedDBObjects.java deleted file mode 100644 index 5ad71a9..0000000 --- a/src/test/java/org/warp/jcwdb/tests/DBNestedDBObjects.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.warp.jcwdb.tests; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.warp.jcwdb.utils.NestedClass; -import org.warp.jcwdb.utils.TestUtils; - -import static org.junit.Assert.*; - -public class DBNestedDBObjects { - private TestUtils.WrappedDb db; - private NestedClass root; - - @Before - public void setUp() throws Exception { - db = TestUtils.wrapDb().create((db) -> { - root = db.get().loadRoot(NestedClass.class); - }); - root.child = new NestedClass(db.get()); - root.child.child = new NestedClass(db.get()); - root.child.child.child = new NestedClass(db.get()); - root.child.child.child.child = new NestedClass(db.get()); - root.child.child.child.child.isFinal = true; - - NestedClass nestedClass0 = new NestedClass(db.get()); - nestedClass0.isFinal = true; - NestedClass nestedClass1 = new NestedClass(db.get()); - nestedClass1.setValue(nestedClass0); - NestedClass nestedClass2 = new NestedClass(db.get()); - nestedClass2.setValue(nestedClass1); - NestedClass nestedClass3 = new NestedClass(db.get()); - nestedClass3.setValue(nestedClass2); - NestedClass nestedClass4 = new NestedClass(db.get()); - nestedClass4.setValue(nestedClass3); - root.setValue(nestedClass4); - - db.closeAndReopen(); - } - - @Test - public void shouldMatchNestedObjects() { - assertNotNull(root); - assertNotNull(root.child); - assertNotNull(root.child.child); - assertNotNull(root.child.child.child); - assertNotNull(root.child.child.child.child); - assertTrue(root.child.child.child.child.isFinal); - assertNotNull(root.getValue()); - assertFalse(root.isFinal); - assertNotNull(root.getValue().getValue()); - assertFalse(root.getValue().isFinal); - assertNotNull(root.getValue().getValue().getValue()); - assertFalse(root.getValue().getValue().isFinal); - assertNotNull(root.getValue().getValue().getValue().getValue()); - assertFalse(root.getValue().getValue().getValue().isFinal); - assertNotNull(root.getValue().getValue().getValue().getValue().getValue()); - assertFalse(root.getValue().getValue().getValue().getValue().isFinal); - assertTrue(root.getValue().getValue().getValue().getValue().getValue().isFinal); - } - - @After - public void tearDown() throws Exception { - db.delete(); - } -} diff --git a/src/test/java/org/warp/jcwdb/tests/DBRootCreation.java b/src/test/java/org/warp/jcwdb/tests/DBRootCreation.java deleted file mode 100644 index 4b2523b..0000000 --- a/src/test/java/org/warp/jcwdb/tests/DBRootCreation.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.warp.jcwdb.tests; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.warp.jcwdb.ann.DBObject; -import org.warp.jcwdb.ann.DBObjectIndicesManager; -import org.warp.jcwdb.ann.JCWDatabase; -import org.warp.jcwdb.utils.TestUtils; - -import java.io.IOException; - -import static org.junit.Assert.assertTrue; - -public class DBRootCreation { - private TestUtils.WrappedDb db; - - @Before - public void setUp() throws Exception { - db = TestUtils.wrapDb().create(); - } - - @Test - public void shouldCreateRoot() throws IOException { - RootClass root = db.get().loadRoot(RootClass.class); - assertTrue(root.test()); - } - - @After - public void tearDown() throws Exception { - db.delete(); - } - - public static class RootClass extends DBObject { - - public RootClass(JCWDatabase database) throws IOException { - super(database); - } - - public boolean test() { - return true; - } - - @Override - public void initialize() throws IOException { - - } - } -} diff --git a/src/test/java/org/warp/jcwdb/tests/DBRootFields.java b/src/test/java/org/warp/jcwdb/tests/DBRootFields.java deleted file mode 100644 index 0073e08..0000000 --- a/src/test/java/org/warp/jcwdb/tests/DBRootFields.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.warp.jcwdb.tests; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.warp.jcwdb.utils.TestUtils; - -public class DBRootFields { - private TestUtils.WrappedDb db; - private TestUtils.RootClass root; - - @Before - public void setUp() throws Exception { - db = TestUtils.wrapDb().create((db) -> { - root = db.get().loadRoot(TestUtils.RootClass.class); - }); - db.setRootClassFields(root); - db.closeAndReopen(); - } - - @Test - public void shouldMatchAllFields() { - db.testRootClassFields(root); - } - - @After - public void tearDown() throws Exception { - db.delete(); - } -} diff --git a/src/test/java/org/warp/jcwdb/tests/DBRootProperties.java b/src/test/java/org/warp/jcwdb/tests/DBRootProperties.java deleted file mode 100644 index a144ecd..0000000 --- a/src/test/java/org/warp/jcwdb/tests/DBRootProperties.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.warp.jcwdb.tests; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.warp.jcwdb.utils.TestUtils; - -public class DBRootProperties { - private TestUtils.WrappedDb db; - private TestUtils.RootClass root; - - @Before - public void setUp() throws Exception { - db = TestUtils.wrapDb().create((db) -> { - root = db.get().loadRoot(TestUtils.RootClass.class); - }); - db.setRootClassProperties(root); - db.closeAndReopen(); - } - - @Test - public void shouldMatchAllProperties() { - db.testRootClassProperties(root); - } - - @After - public void tearDown() throws Exception { - db.delete(); - } -} diff --git a/src/test/java/org/warp/jcwdb/utils/NSimplestClass.java b/src/test/java/org/warp/jcwdb/utils/NSimplestClass.java index 55f76d6..f73ba00 100644 --- a/src/test/java/org/warp/jcwdb/utils/NSimplestClass.java +++ b/src/test/java/org/warp/jcwdb/utils/NSimplestClass.java @@ -4,8 +4,6 @@ import org.warp.cowdb.Database; import org.warp.cowdb.EnhancedObject; import org.warp.jcwdb.ann.DBDataType; import org.warp.jcwdb.ann.DBField; -import org.warp.jcwdb.ann.DBObject; -import org.warp.jcwdb.ann.JCWDatabase; import java.io.IOException; diff --git a/src/test/java/org/warp/jcwdb/utils/NTestUtils.java b/src/test/java/org/warp/jcwdb/utils/NTestUtils.java index ffbae03..c6f13c5 100644 --- a/src/test/java/org/warp/jcwdb/utils/NTestUtils.java +++ b/src/test/java/org/warp/jcwdb/utils/NTestUtils.java @@ -218,7 +218,7 @@ public class NTestUtils { assertEquals("Test", val); } - private void shouldGetDBObject(SimplestClass val) { + private void shouldGetDBObject(NSimplestClass val) { assertNotNull(val); assertTrue(val.field1); } diff --git a/src/test/java/org/warp/jcwdb/utils/NestedClass.java b/src/test/java/org/warp/jcwdb/utils/NestedClass.java deleted file mode 100644 index 042cbd4..0000000 --- a/src/test/java/org/warp/jcwdb/utils/NestedClass.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.warp.jcwdb.utils; - -import org.warp.jcwdb.ann.*; - -import java.io.IOException; - -public class NestedClass extends DBObject { - - @DBField(id = 0, type = DBDataType.BOOLEAN) - public boolean isFinal; - - @DBField(id = 1, type = DBDataType.DATABASE_OBJECT) - public NestedClass child; - - public NestedClass() { - - } - - public NestedClass(JCWDatabase database) throws IOException { - super(database); - } - - @DBPropertySetter(id = 0, type = DBDataType.DATABASE_OBJECT) - public void setValue(NestedClass value) { - setProperty(value); - } - - @DBPropertyGetter(id = 0, type = DBDataType.DATABASE_OBJECT) - public NestedClass getValue() { - return getProperty(); - } - - @Override - public void initialize() throws IOException { - - } -} diff --git a/src/test/java/org/warp/jcwdb/utils/SimplestClass.java b/src/test/java/org/warp/jcwdb/utils/SimplestClass.java deleted file mode 100644 index 2791395..0000000 --- a/src/test/java/org/warp/jcwdb/utils/SimplestClass.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.warp.jcwdb.utils; - -import org.warp.jcwdb.ann.*; - -import java.io.IOException; - -public class SimplestClass extends DBObject { - - @DBField(id = 0, type = DBDataType.BOOLEAN) - public boolean field1; - - public SimplestClass() { - - } - - public SimplestClass(JCWDatabase database) throws IOException { - super(database); - } - - @Override - public void initialize() throws IOException { - field1 = true; - } -} diff --git a/src/test/java/org/warp/jcwdb/utils/TestUtils.java b/src/test/java/org/warp/jcwdb/utils/TestUtils.java deleted file mode 100644 index ed622e0..0000000 --- a/src/test/java/org/warp/jcwdb/utils/TestUtils.java +++ /dev/null @@ -1,381 +0,0 @@ -package org.warp.jcwdb.utils; - -import it.unimi.dsi.fastutil.longs.LongArrayList; -import org.warp.jcwdb.ann.*; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Comparator; -import java.util.function.Consumer; - -import static org.junit.Assert.*; - -public class TestUtils { - public static WrappedDb wrapDb() { - return new WrappedDb(); - } - - public static class WrappedDb { - - private JCWDatabase db; - private Path tempDir; - private RunnableWithIO r; - - private WrappedDb() { - - } - - public WrappedDb create() throws IOException { - tempDir = Files.createTempDirectory("tests-"); - db = openDatabase(); - if (r != null) { - r.run(); - } - return this; - } - - public WrappedDb create(ConsumerWithIO r) throws IOException { - this.r = () -> r.accept(WrappedDb.this); - this.create(); - return this; - } - - private JCWDatabase openDatabase() throws IOException { - return new JCWDatabase(tempDir.resolve(Paths.get("data.db")), tempDir.resolve(Paths.get("indices.idx")), true); - } - - public void delete() throws IOException { - db.close(); - deleteDir(tempDir); - } - - public JCWDatabase get() { - return db; - } - - private void deleteDir(Path p) throws IOException { - Files.walk(p) - .sorted(Comparator.reverseOrder()) - .map(Path::toFile) - .forEach(File::delete); - } - - public void closeAndReopen() throws IOException { - db.close(); - db = openDatabase(); - r.run(); - } - - public void setRootClassValues(RootClass root) throws IOException { - setRootClassFields(root); - setRootClassProperties(root); - } - - public void setRootClassFields(RootClass root) throws IOException { - root.field1 = true; - root.field2 = 2; - root.field3 = 3; - root.field4 = 4; - root.field5 = 5; - root.field6 = 6; - root.field7 = "Test"; - root.field8 = new LongArrayList(); - root.field8.add(0); - root.field8.add(1); - root.field8.add(2); - root.field8.add(Long.MAX_VALUE/2); - root.field8.add(Long.MIN_VALUE/2); - root.field8.add(Long.MAX_VALUE); - root.field8.add(Long.MIN_VALUE); - root.field9 = new SimplestClass(db); - root.field9.field1 = true; - - } - - public void setRootClassProperties(RootClass root) throws IOException { - root.set1(true); - root.set2((byte)2); - root.set3((short)3); - root.set4((char)4); - root.set5(5); - root.set6(6); - root.set7("Test"); - LongArrayList lArrayList = new LongArrayList(); - lArrayList.add(0); - lArrayList.add(1); - lArrayList.add(2); - lArrayList.add(Long.MAX_VALUE/2); - lArrayList.add(Long.MIN_VALUE/2); - lArrayList.add(Long.MAX_VALUE); - lArrayList.add(Long.MIN_VALUE); - root.set8(lArrayList); - SimplestClass simplestClass9 = new SimplestClass(db); - simplestClass9.field1 = true; - root.set9(simplestClass9); - } - - public void testRootClassValues(RootClass root) { - testRootClassFields(root); - testRootClassProperties(root); - } - - public void testRootClassFields(RootClass root) { - shouldGetFieldBoolean(root); - shouldGetFieldByte(root); - shouldGetFieldShort(root); - shouldGetFieldCharacter(root); - shouldGetFieldInteger(root); - shouldGetFieldLong(root); - shouldGetFieldObject(root); - shouldGetFieldUID(root); - shouldGetFieldDBObject(root); - } - - public void testRootClassProperties(RootClass root) { - shouldGetPropertyBoolean(root); - shouldGetPropertyByte(root); - shouldGetPropertyShort(root); - shouldGetPropertyCharacter(root); - shouldGetPropertyInteger(root); - shouldGetPropertyLong(root); - shouldGetPropertyObject(root); - shouldGetPropertyUID(root); - shouldGetPropertyDBObject(root); - } - - - private void shouldGetFieldBoolean(RootClass root) { - assertTrue(root.field1); - } - - private void shouldGetPropertyBoolean(RootClass root) { - assertTrue(root.get1()); - } - - private void shouldGetFieldByte(RootClass root) { - assertEquals(2, root.field2); - } - - private void shouldGetPropertyByte(RootClass root) { - assertEquals(2, root.get2()); - } - - private void shouldGetFieldShort(RootClass root) { - assertEquals(3, root.field3); - } - - private void shouldGetPropertyShort(RootClass root) { - assertEquals(3, root.get3()); - } - - private void shouldGetFieldCharacter(RootClass root) { - assertEquals(4, root.field4); - } - - private void shouldGetPropertyCharacter(RootClass root) { - assertEquals(4, root.get4()); - } - - private void shouldGetFieldInteger(RootClass root) { - assertEquals(5, root.field5); - } - - private void shouldGetPropertyInteger(RootClass root) { - assertEquals(5, root.get5()); - } - - private void shouldGetFieldLong(RootClass root) { - assertEquals(6, root.field6); - } - - private void shouldGetPropertyLong(RootClass root) { - assertEquals(6, root.get6()); - } - - private void shouldGetFieldObject(RootClass root) { - shouldGetObject(root.field7); - } - - private void shouldGetPropertyObject(RootClass root) { - shouldGetObject(root.get7()); - } - - private void shouldGetFieldDBObject(RootClass root) { - assertTrue(root.field9.field1); - } - - private void shouldGetPropertyDBObject(RootClass root) { - assertTrue(root.get9().field1); - } - - private void shouldGetObject(String val) { - assertNotNull(val); - assertEquals("Test", val); - } - - private void shouldGetDBObject(SimplestClass val) { - assertNotNull(val); - assertTrue(val.field1); - } - - private void shouldGetFieldUID(RootClass root) { - shouldGetUID(root.field8); - } - - private void shouldGetPropertyUID(RootClass root) { - shouldGetUID(root.get8()); - } - - private void shouldGetUID(LongArrayList val) { - assertNotNull(val); - assertEquals(7, val.size()); - assertEquals(0, val.getLong(0)); - assertEquals(val.getLong(5), Long.MAX_VALUE); - assertEquals(val.getLong(6), Long.MIN_VALUE); - } - - public void onLoad(RunnableWithIO r) { - this.r = r; - } - } - - public static class RootClass extends DBObject { - - @DBField(id = 0, type = DBDataType.BOOLEAN) - public boolean field1; - - @DBField(id = 1, type = DBDataType.BYTE) - public byte field2; - - @DBField(id = 2, type = DBDataType.SHORT) - public short field3; - - @DBField(id = 3, type = DBDataType.CHAR) - public char field4; - - @DBField(id = 4, type = DBDataType.INTEGER) - public int field5; - - @DBField(id = 5, type = DBDataType.LONG) - public long field6; - - @DBField(id = 6, type = DBDataType.OBJECT) - public String field7; - - @DBField(id = 7, type = DBDataType.UID_LIST) - public LongArrayList field8; - - @DBField(id = 8, type = DBDataType.DATABASE_OBJECT) - public SimplestClass field9; - - public RootClass() { - - } - - public RootClass(JCWDatabase database) throws IOException { - super(database); - } - - @DBPropertyGetter(id = 0, type = DBDataType.BOOLEAN) - public boolean get1() { - return getProperty(); - } - - @DBPropertyGetter(id = 1, type = DBDataType.BYTE) - public byte get2() { - return getProperty(); - } - - @DBPropertyGetter(id = 2, type = DBDataType.SHORT) - public short get3() { - return getProperty(); - } - - @DBPropertyGetter(id = 3, type = DBDataType.CHAR) - public char get4() { - return getProperty(); - } - - @DBPropertyGetter(id = 4, type = DBDataType.INTEGER) - public int get5() { - return getProperty(); - } - - @DBPropertyGetter(id = 5, type = DBDataType.LONG) - public long get6() { - return getProperty(); - } - - @DBPropertyGetter(id = 6, type = DBDataType.OBJECT) - public String get7() { - return getProperty(); - } - - @DBPropertyGetter(id = 7, type = DBDataType.UID_LIST) - public LongArrayList get8() { - return getProperty(); - } - - @DBPropertyGetter(id = 8, type = DBDataType.DATABASE_OBJECT) - public SimplestClass get9() { - return getProperty(); - } - - @DBPropertySetter(id = 0, type = DBDataType.BOOLEAN) - public void set1(boolean val) { - setProperty(val); - } - - @DBPropertySetter(id = 1, type = DBDataType.BYTE) - public void set2(byte val) { - setProperty(val); - } - - @DBPropertySetter(id = 2, type = DBDataType.SHORT) - public void set3(short val) { - setProperty(val); - } - - @DBPropertySetter(id = 3, type = DBDataType.CHAR) - public void set4(char val) { - setProperty(val); - } - - @DBPropertySetter(id = 4, type = DBDataType.INTEGER) - public void set5(int val) { - setProperty(val); - } - - @DBPropertySetter(id = 5, type = DBDataType.LONG) - public void set6(long val) { - setProperty(val); - } - - @DBPropertySetter(id = 6, type = DBDataType.OBJECT) - public void set7(String val) { - setProperty(val); - } - - @DBPropertySetter(id = 7, type = DBDataType.UID_LIST) - public void set8(LongArrayList val) { - setProperty(val); - } - - @DBPropertySetter(id = 8, type = DBDataType.DATABASE_OBJECT) - public void set9(SimplestClass val) { - setProperty(val); - } - - public boolean test() { - return true; - } - - @Override - public void initialize() throws IOException { - - } - } -}