diff --git a/pom.xml b/pom.xml index e46f8ab..6451ac9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.warp jcwdb - 1.1-SNAPSHOT + 1.2-SNAPSHOT jcwdb @@ -41,7 +41,7 @@ com.esotericsoftware kryo - 5.0.0-RC2-SNAPSHOT + 5.0.0-RC1 net.openhft @@ -52,7 +52,13 @@ org.apache.commons commons-lang3 - 3.8.1 + 3.5 + + + org.jetbrains + annotations + RELEASE + compile diff --git a/src/main/java/org/warp/jcwdb/ann/DBArrayList.java b/src/main/java/org/warp/jcwdb/ann/DBArrayList.java new file mode 100644 index 0000000..366024f --- /dev/null +++ b/src/main/java/org/warp/jcwdb/ann/DBArrayList.java @@ -0,0 +1,110 @@ +package org.warp.jcwdb.ann; + +import it.unimi.dsi.fastutil.longs.LongArrayList; + +import java.io.IOError; +import java.io.IOException; +import java.util.StringJoiner; + +public abstract class DBArrayList extends DBObject { + + private final Object indicesAccessLock = new Object(); + + @DBField(id = 0, type = DBDataType.UID_LIST) + private LongArrayList indices; + + public DBArrayList(JCWDatabase database) { + super(database); + indices = new LongArrayList(); + } + + public DBArrayList(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + super(database, objectInfo); + } + + public T get(int index) { + synchronized (indicesAccessLock) { + try { + long uid = indices.getLong(index); + return loadItem(uid); + } catch (IOException e) { + throw new IOError(e); + } + } + } + + public void add(T value) { + long uid = databaseManager.allocateNullValue(); + synchronized (indicesAccessLock) { + indices.add(uid); + try { + writeItemToDisk(uid, value); + } catch (IOException e) { + throw new IOError(e); + } + } + } + + public void update(int index, T value) { + synchronized (indicesAccessLock) { + set(index, value); + } + } + + public void set(int index, T value) { + long uid = databaseManager.allocateNullValue(); + synchronized (indicesAccessLock) { + indices.set(index, uid); + try { + writeItemToDisk(uid, value); + } catch (IOException e) { + throw new IOError(e); + } + } + } + + public void add(int index, T value) { + long uid = databaseManager.allocateNullValue(); + synchronized (indicesAccessLock) { + indices.add(index, uid); + try { + writeItemToDisk(uid, value); + } catch (IOException e) { + throw new IOError(e); + } + } + } + + public T getLast() { + synchronized (indicesAccessLock) { + if (indices.size() > 0) { + return get(indices.size() - 1); + } else { + return null; + } + } + } + + public boolean isEmpty() { + synchronized (indicesAccessLock) { + return indices.size() <= 0; + } + } + + public int size() { + synchronized (indicesAccessLock) { + return indices.size(); + } + } + + protected abstract T loadItem(long uid) throws IOException; + + protected abstract void writeItemToDisk(long uid, T item) throws IOException; + + @Override + public String toString() { + return new StringJoiner(", ", DBArrayList.class.getSimpleName() + "[", "]") + .add(indices.size() + " items") + .toString(); + } +} diff --git a/src/main/java/org/warp/jcwdb/ann/DBDBObjectList.java b/src/main/java/org/warp/jcwdb/ann/DBDBObjectList.java index d22a5ca..71d7dac 100644 --- a/src/main/java/org/warp/jcwdb/ann/DBDBObjectList.java +++ b/src/main/java/org/warp/jcwdb/ann/DBDBObjectList.java @@ -1,20 +1,14 @@ package org.warp.jcwdb.ann; import java.io.IOException; -import java.util.LinkedList; -public class DBDBObjectList extends DBList { +public class DBDBObjectList extends DBArrayList { - @DBField(id = 2, type = DBDataType.OBJECT) - public Class type; + @DBField(id = 1, type = DBDataType.OBJECT) + private Class type; - public DBDBObjectList(JCWDatabase db, Class type) { - super(db, 10); - this.type = type; - } - - public DBDBObjectList(JCWDatabase db, Class type, int maxLoadedItems) { - super(db, maxLoadedItems); + public DBDBObjectList(JCWDatabase database, Class type) { + super(database); this.type = type; } @@ -23,13 +17,12 @@ public class DBDBObjectList extends DBList { } @Override - protected T loadObjectFromDatabase(long uid) throws IOException { - return database.loadDBObject(type, uid); + protected T loadItem(long uid) throws IOException { + return databaseManager.loadDBObject(type, uid); } @Override - protected long saveObjectToDatabase(long uid, T value) throws IOException { - database.writeObjectProperty(uid, DBDataType.DATABASE_OBJECT, value); - return uid; + protected void writeItemToDisk(long uid, T item) throws IOException { + databaseManager.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 0ced52c..9e8907b 100644 --- a/src/main/java/org/warp/jcwdb/ann/DBDataType.java +++ b/src/main/java/org/warp/jcwdb/ann/DBDataType.java @@ -3,6 +3,11 @@ package org.warp.jcwdb.ann; public enum DBDataType { DATABASE_OBJECT, OBJECT, + BOOLEAN, + BYTE, + SHORT, + CHAR, INTEGER, + LONG, UID_LIST } \ No newline at end of file diff --git a/src/main/java/org/warp/jcwdb/ann/DBList.java b/src/main/java/org/warp/jcwdb/ann/DBList.java deleted file mode 100644 index 685798c..0000000 --- a/src/main/java/org/warp/jcwdb/ann/DBList.java +++ /dev/null @@ -1,171 +0,0 @@ -package org.warp.jcwdb.ann; - -import it.unimi.dsi.fastutil.longs.LongArrayList; - -import java.io.IOError; -import java.io.IOException; -import java.util.LinkedList; -import java.util.StringJoiner; - -public abstract class DBList extends DBObject { - @DBField(id = 0, type = DBDataType.INTEGER) - private int maxLoadedItems; - - @DBField(id = 1, type = DBDataType.UID_LIST) - private LongArrayList itemIndices; - - public DBList(JCWDatabase db, int maxLoadedItems) { - super(db); - this.maxLoadedItems = maxLoadedItems; - this.itemIndices = new LongArrayList(); - } - - public DBList(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - super(database, objectInfo); - } - - public int getMaxLoadedItems() { - return maxLoadedItems; - } - - public void add(T obj) { - try { - itemIndices.add(saveObjectToDatabase(database.allocateNullValue(), obj)); - } catch (IOException e) { - throw new IOError(e); - } - } - - public int size() { - return this.itemIndices.size(); - } - - private T loadObjectAt(int i) throws IOException { - return loadObjectFromDatabase(itemIndices.getLong(i)); - } - - protected abstract T loadObjectFromDatabase(long uid) throws IOException; - - protected abstract long saveObjectToDatabase(long uid, T value) throws IOException; - - public DBListIterator iterator() { - return new DBListIterator<>() { - private int position = itemIndices.size(); - private LinkedList cachedItems; - - private int objectToSavePosition; - private T objectToSave; - - @Override - public boolean hasNext() { - if (position > 0) { - return true; - } else { - try { - saveObservedObject(); - } catch (IOException e) { - throw new IOError(e); - } - return false; - } - } - - @Override - public T next() { - position--; - if (position < 0) { - throw new NullPointerException("Position < 0"); - } - if (cachedItems == null || cachedItems.size() == 0) { - try { - cachedItems = fillCache(position); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - try { - return switchObservedObject(position, cachedItems.removeFirst()); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - @Override - public void remove() { - try { - saveObservedObject(); - } catch (IOException e) { - throw new RuntimeException(e); - } - itemIndices.removeLong(position); - } - - @Override - public void insert(T obj) { - try { - itemIndices.add(position, saveObjectToDatabase(database.allocateNullValue(), obj)); - } catch (IOException e) { - throw new IOError(e); - } - } - - @Override - public void set(T obj) { - try { - itemIndices.set(position, saveObjectToDatabase(database.allocateNullValue(), obj)); - } catch (IOException e) { - throw new IOError(e); - } - } - - private LinkedList fillCache(int position) throws IOException { - LinkedList cachedItems = new LinkedList<>(); - int firstObjectIndex = position; - int lastObjectIndex = firstObjectIndex - maxLoadedItems; - if (lastObjectIndex < 0) { - lastObjectIndex = 0; - } - for (int i = firstObjectIndex; i >= lastObjectIndex; i--) { - cachedItems.addLast(loadObjectAt(i)); - } - return cachedItems; - } - - private void saveObservedObject() throws IOException { - if (objectToSave != null) { - itemIndices.set(objectToSavePosition, saveObjectToDatabase(database.allocateNullValue(), objectToSave)); - objectToSave = null; - objectToSavePosition = 0; - } - } - - private T switchObservedObject(int position, T obj) throws IOException { - saveObservedObject(); - objectToSave = obj; - objectToSavePosition = position; - return obj; - } - }; - } - - public interface DBListIterator { - boolean hasNext(); - - T next(); - - void remove(); - - void insert(T obj); - - void set(T obj); - } - - @Override - public String toString() { - return new StringJoiner(", ", DBList.class.getSimpleName() + "[", "]") - .add("size=" + size()) - .add("maxLoadedItems=" + maxLoadedItems) - .add("itemIndices=" + (itemIndices.size() < 100 ? itemIndices : "["+itemIndices.size()+" items]")) - .toString(); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/DBObject.java b/src/main/java/org/warp/jcwdb/ann/DBObject.java index da5a3ae..e70b17a 100644 --- a/src/main/java/org/warp/jcwdb/ann/DBObject.java +++ b/src/main/java/org/warp/jcwdb/ann/DBObject.java @@ -10,7 +10,8 @@ import java.util.LinkedHashMap; import java.util.Map; public abstract class DBObject { - protected final DatabaseManager database; + protected final JCWDatabase database; + protected final DatabaseManager databaseManager; private Field[] fields; private DBDataType[] fieldTypes; private long[] fieldUIDs; @@ -27,7 +28,8 @@ public abstract class DBObject { private final Object propertiesAccessLock = new Object(); public DBObject(JCWDatabase database) { - this.database = database.getDatabaseManager(); + this.database = database; + this.databaseManager = database.getDatabaseManager(); try { initializeDBObject(); } catch (IOException e) { @@ -35,6 +37,12 @@ public abstract class DBObject { } } + public DBObject(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + this.database = database; + this.databaseManager = database.getDatabaseManager(); + this.databaseManager.preloadDBObject(this, objectInfo); + } + private void initializeDBObject() throws IOException { initializeDBObjectFields(); initializeDBObjectProperties(); @@ -42,12 +50,12 @@ public abstract class DBObject { private void initializeDBObjectFields() throws IOException { // Declare the variables needed to get the biggest field Id - Field[] unorderedFields = database.getFields(this); + Field[] unorderedFields = databaseManager.getFields(this); // Find the biggest field Id - int biggestFieldId = database.getBiggestFieldId(unorderedFields); + int biggestFieldId = databaseManager.getBiggestFieldId(unorderedFields); // Allocate new UIDs - fieldUIDs = database.allocateNewUIDs(biggestFieldId + 1); + fieldUIDs = databaseManager.allocateNewUIDs(biggestFieldId + 1); // Declare the other variables Field[] fields = new Field[biggestFieldId + 1]; @@ -58,7 +66,7 @@ public abstract class DBObject { DBField fieldAnnotation = field.getAnnotation(DBField.class); int fieldId = fieldAnnotation.id(); DBDataType fieldType = fieldAnnotation.type(); - database.loadField(this, field, fieldType, fieldUIDs[fieldId]); + databaseManager.loadField(this, field, fieldType, fieldUIDs[fieldId]); fields[fieldId] = field; orderedFieldTypes[fieldId] = fieldType; } @@ -68,16 +76,16 @@ public abstract class DBObject { private void initializeDBObjectProperties() { // Declare the variables needed to get the biggest property Id - Method[] unorderedPropertyGetters = database.getPropertyGetters(this); - Method[] unorderedPropertySetters = database.getPropertySetters(this); + Method[] unorderedPropertyGetters = databaseManager.getPropertyGetters(this); + Method[] unorderedPropertySetters = databaseManager.getPropertySetters(this); // Find the biggest property Id - int biggestGetter = database.getBiggestPropertyGetterId(unorderedPropertyGetters); - int biggestSetter = database.getBiggestPropertySetterId(unorderedPropertySetters); + int biggestGetter = databaseManager.getBiggestPropertyGetterId(unorderedPropertyGetters); + int biggestSetter = databaseManager.getBiggestPropertySetterId(unorderedPropertySetters); int biggestPropertyId = biggestGetter > biggestSetter ? biggestGetter : biggestSetter; // Allocate new UIDs - propertyUIDs = database.allocateNewUIDs(biggestPropertyId + 1); + propertyUIDs = databaseManager.allocateNewUIDs(biggestPropertyId + 1); for (Method property : unorderedPropertySetters) { DBPropertySetter fieldAnnotation = property.getAnnotation(DBPropertySetter.class); @@ -115,11 +123,6 @@ public abstract class DBObject { setProperties(propertyGetters, propertySetters, propertyTypes, propertyUIDs, setterMethods, getterMethods); } - public DBObject(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - this.database = database.getDatabaseManager(); - this.database.preloadDBObject(this, objectInfo); - } - public T getProperty() { StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); StackWalker.StackFrame stackFrame = walker.walk(f -> f.skip(1).findFirst().orElse(null)); @@ -141,7 +144,7 @@ public abstract class DBObject { synchronized (propertiesAccessLock) { if (!loadedProperties[propertyId]) { long propertyUID = propertyUIDs[propertyId]; - database.loadProperty(this, propertyId, propertyGetters[propertyId], propertyTypes[propertyId], propertyUID); + databaseManager.loadProperty(this, propertyId, propertyGetters[propertyId], propertyTypes[propertyId], propertyUID); } return (T) loadedPropertyValues[propertyId]; } @@ -166,13 +169,13 @@ public abstract class DBObject { try { synchronized (propertiesAccessLock) { synchronized (fieldsAccessLock) { - database.writeObjectInfo(uid, fieldUIDs, propertyUIDs); + databaseManager.writeObjectInfo(uid, fieldUIDs, propertyUIDs); } } synchronized (fieldsAccessLock) { for (int i = 0; i < fieldUIDs.length; i++) { try { - database.writeObjectProperty(fieldUIDs[i], fieldTypes[i], fields[i].get(this)); + databaseManager.writeObjectProperty(fieldUIDs[i], fieldTypes[i], fields[i].get(this)); } catch (IllegalAccessException e) { throw new IOError(e); } @@ -180,7 +183,7 @@ public abstract class DBObject { } synchronized (propertiesAccessLock) { for (int i = 0; i < propertyUIDs.length; i++) { - database.writeObjectProperty(propertyUIDs[i], propertyTypes[i], loadedPropertyValues[i]); + databaseManager.writeObjectProperty(propertyUIDs[i], propertyTypes[i], loadedPropertyValues[i]); } } } catch (IOException e) { diff --git a/src/main/java/org/warp/jcwdb/ann/DBObjectList.java b/src/main/java/org/warp/jcwdb/ann/DBObjectList.java index 1fa796e..44a41a0 100644 --- a/src/main/java/org/warp/jcwdb/ann/DBObjectList.java +++ b/src/main/java/org/warp/jcwdb/ann/DBObjectList.java @@ -2,10 +2,9 @@ package org.warp.jcwdb.ann; import java.io.IOException; -public class DBObjectList extends DBList { - - public DBObjectList(JCWDatabase db, int maxLoadedItems) { - super(db, maxLoadedItems); +public class DBObjectList extends DBArrayList { + public DBObjectList(JCWDatabase database) { + super(database); } public DBObjectList(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { @@ -13,13 +12,12 @@ public class DBObjectList extends DBList { } @Override - protected T loadObjectFromDatabase(long uid) throws IOException { - return database.loadObject(uid); + public T loadItem(long uid) throws IOException { + return databaseManager.loadObject(uid); } @Override - protected long saveObjectToDatabase(long uid, T value) throws IOException { - database.writeObjectProperty(uid, DBDataType.OBJECT, value); - return uid; + public void writeItemToDisk(long uid, T item) throws IOException { + databaseManager.writeObjectProperty(uid, DBDataType.OBJECT, item); } } diff --git a/src/main/java/org/warp/jcwdb/ann/DatabaseManager.java b/src/main/java/org/warp/jcwdb/ann/DatabaseManager.java index 7a986bd..84a0cb4 100644 --- a/src/main/java/org/warp/jcwdb/ann/DatabaseManager.java +++ b/src/main/java/org/warp/jcwdb/ann/DatabaseManager.java @@ -1,7 +1,6 @@ package org.warp.jcwdb.ann; import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.Registration; import com.esotericsoftware.kryo.io.Output; import it.unimi.dsi.fastutil.booleans.BooleanArrayList; import it.unimi.dsi.fastutil.bytes.ByteArrayList; @@ -14,7 +13,6 @@ import org.apache.commons.lang3.reflect.MethodUtils; import org.warp.jcwdb.Cleanable; import org.warp.jcwdb.Cleaner; import org.warp.jcwdb.FileIndexManager; -import org.warp.jcwdb.ann.exampleimpl.ClassWithList; import java.io.ByteArrayOutputStream; import java.io.IOError; @@ -24,6 +22,8 @@ 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 DatabaseManager implements Cleanable { @@ -36,9 +36,9 @@ public class DatabaseManager implements Cleanable { private final Kryo kryo = new Kryo(); private volatile boolean closed; - DatabaseManager(JCWDatabase jcwDatabase, Path dataFile, Path metadataFile) throws IOException { + DatabaseManager(JCWDatabase jcwDatabase, Path dataFile, Path metadataFile, boolean registrationRequired) throws IOException { this.jcwDatabase = jcwDatabase; - kryo.setRegistrationRequired(true); + kryo.setRegistrationRequired(registrationRequired); registerDefaultClasses(); this.indices = new FileIndexManager(dataFile, metadataFile); if (!indices.has(0)) { @@ -106,6 +106,9 @@ public class DatabaseManager implements Cleanable { registerClass(CharArrayList.class, id++); registerClass(IntArrayList.class, id++); registerClass(LongArrayList.class, id++); + registerClass(TreeSet.class, id++); + registerClass(SortedSet.class, id++); + registerClass(SortedMap.class, id++); } @SuppressWarnings("unchecked") @@ -262,63 +265,70 @@ public class DatabaseManager implements Cleanable { return biggestFieldId; } - @SuppressWarnings("unchecked") public void loadProperty(DBObject obj, int propertyId, Method property, DBDataType propertyType, long propertyUID) throws IOException { - switch (propertyType) { - case DATABASE_OBJECT: - DBObject fieldDBObjectValue = loadDBObject((Class) property.getReturnType(), propertyUID); - //System.err.println("Loading prop. DBObj " + propertyUID + ":" + fieldDBObjectValue); - obj.setLoadedProperty(propertyId, fieldDBObjectValue); - break; - case OBJECT: - Object fieldObjectValue = loadObject(propertyUID); - //System.err.println("Loading prop. Obj " + propertyUID + ":" + fieldObjectValue); - obj.setLoadedProperty(propertyId, fieldObjectValue); - break; - case UID_LIST: - LongArrayList fieldListObjectValue = loadListObject(propertyUID); - //System.err.println("Loading prop. LOb " + propertyUID + ":" + fieldListObjectValue); - obj.setLoadedProperty(propertyId, fieldListObjectValue); - break; - case INTEGER: - int fieldIntValue = loadInt(propertyUID); - //System.err.println("Loading prop. Int " + propertyUID + ":" + fieldIntValue); - obj.setLoadedProperty(propertyId, fieldIntValue); - break; - default: - throw new NullPointerException("Unknown Field Type"); - } + loadData(propertyType, propertyUID, property::getReturnType, (data) -> obj.setLoadedProperty(propertyId, data)); + } + + public void loadField(DBObject obj, Field field, DBDataType fieldType, long fieldUID) throws IOException { + loadData(fieldType, fieldUID, field::getType, (data) -> { + try { + FieldUtils.writeField(field, obj, data, true); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }); } @SuppressWarnings("unchecked") - public void loadField(DBObject obj, Field field, DBDataType fieldType, long fieldUID) throws IOException { - try { - switch (fieldType) { - case DATABASE_OBJECT: - DBObject fieldDBObjectValue = loadDBObject((Class) field.getType(), fieldUID); - //System.err.println("Loading field DBObj " + fieldUID + ":" + fieldDBObjectValue); - FieldUtils.writeField(field, obj, fieldDBObjectValue, true); - break; - case OBJECT: - Object fieldObjectValue = loadObject(fieldUID); - //System.err.println("Loading field Obj " + fieldUID + ":" + fieldObjectValue); - FieldUtils.writeField(field, obj, fieldObjectValue, true); - break; - case UID_LIST: - LongArrayList fieldListObjectValue = loadListObject(fieldUID); - //System.err.println("Loading field LOb " + fieldUID + ":" + fieldObjectValue); - FieldUtils.writeField(field, obj, fieldListObjectValue, true); - break; - case INTEGER: - int fieldIntValue = loadInt(fieldUID); - //System.err.println("Loading field Int " + fieldUID + ":" + fieldIntValue); - FieldUtils.writeField(field, obj, fieldIntValue, true); - break; - default: - throw new NullPointerException("Unknown Field Type"); - } - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + private void loadData(DBDataType propertyType, long dataUID, Supplier> returnType, Consumer result) throws IOException { + 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"); } } @@ -345,7 +355,6 @@ public class DatabaseManager implements Cleanable { return indices.get(uid, (i, size) -> size == 0 ? null : (T) kryo.readClassAndObject(i)); } - @SuppressWarnings("unchecked") private LongArrayList loadListObject(long uid) throws IOException { return indices.get(uid, (i, size) -> { if (size == 0) return null; @@ -358,10 +367,31 @@ public class DatabaseManager implements Cleanable { }); } + public boolean loadBoolean(long uid) throws IOException { + return indices.get(uid, (i, size) -> size != 0 && i.readBoolean()); + } + + public byte loadByte(long uid) throws IOException { + return indices.get(uid, (i, size) -> size == 0 ? 0 : i.readByte()); + } + + public short loadShort(long uid) throws IOException { + return indices.get(uid, (i, size) -> size == 0 ? 0 : i.readShort()); + } + + public char loadChar(long uid) throws IOException { + return indices.get(uid, (i, size) -> size == 0 ? 0 : i.readChar()); + } + + public int loadInt(long uid) throws IOException { return indices.get(uid, (i, size) -> size == 0 ? 0 : i.readInt()); } + public long loadLong(long uid) throws IOException { + return indices.get(uid, (i, size) -> size == 0 ? 0 : i.readLong()); + } + /** * * @param uid @@ -390,31 +420,58 @@ public class DatabaseManager implements Cleanable { public void writeObjectProperty(long uid, DBDataType propertyType, T loadedPropertyValue) throws IOException { switch (propertyType) { + case BOOLEAN: + indices.set(uid, 1, (o) -> o.writeBoolean(loadedPropertyValue == null ? false : (boolean) loadedPropertyValue)); + //System.err.println("Saving data Boo " + uid + ":" + loadedPropertyValue); + break; + case BYTE: + indices.set(uid, Byte.BYTES, (o) -> o.writeByte(loadedPropertyValue == null ? 0 : (byte) loadedPropertyValue)); + //System.err.println("Saving data Byt " + uid + ":" + loadedPropertyValue); + break; + case SHORT: + indices.set(uid, Short.BYTES, (o) -> o.writeShort(loadedPropertyValue == null ? 0 : (short) loadedPropertyValue)); + //System.err.println("Saving data Shr " + uid + ":" + loadedPropertyValue); + break; + case CHAR: + indices.set(uid, Character.BYTES, (o) -> o.writeChar(loadedPropertyValue == null ? 0 : (char) loadedPropertyValue)); + //System.err.println("Saving data Chr " + uid + ":" + loadedPropertyValue); + break; case INTEGER: - indices.set(uid, Integer.BYTES, (o) -> o.writeInt((int) loadedPropertyValue)); - //System.err.println("Saving prop. Int " + uid + ":" + loadedPropertyValue); + indices.set(uid, Integer.BYTES, (o) -> o.writeInt(loadedPropertyValue == null ? 0 : (int) loadedPropertyValue)); + //System.err.println("Saving data Int " + uid + ":" + loadedPropertyValue); + break; + case LONG: + indices.set(uid, Long.BYTES, (o) -> 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 prop. Obj " + uid + ":" + 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 -> o.write(out, 0, out.length)); break; case UID_LIST: - LongArrayList list = (LongArrayList) loadedPropertyValue; - final int listSize = list.size(); - Output baosListOutput = new Output(Long.BYTES * 100, Long.BYTES * listSize); - baosListOutput.writeVarInt(listSize, true); - for (int i = 0; i < listSize; i++) { - baosListOutput.writeVarLong(list.getLong(i), true); + 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 -> o.write(outList, 0, outList.length)); } - //System.err.println("Saving prop. LOb " + uid + ":" + loadedPropertyValue); - byte[] outList = baosListOutput.toBytes(); - indices.set(uid, outList.length, o -> o.write(outList, 0, outList.length)); break; case DATABASE_OBJECT: - //System.err.println("Saving prop. DBObj " + uid + ":" + loadedPropertyValue); + //System.err.println("Saving data DBObj " + uid + ":" + loadedPropertyValue); if (loadedPropertyValue == null) { writeObjectInfoNull(uid); } else { diff --git a/src/main/java/org/warp/jcwdb/ann/JCWDatabase.java b/src/main/java/org/warp/jcwdb/ann/JCWDatabase.java index 0d25ca2..4e0854d 100644 --- a/src/main/java/org/warp/jcwdb/ann/JCWDatabase.java +++ b/src/main/java/org/warp/jcwdb/ann/JCWDatabase.java @@ -6,8 +6,8 @@ import java.nio.file.Path; public class JCWDatabase { private final DatabaseManager database; - public JCWDatabase(Path dataFile, Path metadataFile) throws IOException { - this.database = new DatabaseManager(this, dataFile, metadataFile); + public JCWDatabase(Path dataFile, Path metadataFile, boolean registrationRequired) throws IOException { + this.database = new DatabaseManager(this, dataFile, metadataFile, registrationRequired); } public T loadRoot(Class rootClass) { @@ -23,6 +23,9 @@ public class JCWDatabase { } public void registerClass(Class clazz, int id) { + if (id < 0) { + throw new IllegalArgumentException(); + } database.registerClass(clazz, id); } diff --git a/src/main/java/org/warp/jcwdb/ann/exampleimpl/Class1.java b/src/main/java/org/warp/jcwdb/ann/exampleimpl/Class1.java deleted file mode 100644 index 3687822..0000000 --- a/src/main/java/org/warp/jcwdb/ann/exampleimpl/Class1.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.warp.jcwdb.ann.exampleimpl; - -import org.warp.jcwdb.ann.*; - -import java.io.IOException; -import java.util.StringJoiner; - -public class Class1 extends DBObject { - - public Class1(JCWDatabase database) { - super(database); - } - - public Class1(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - super(database, objectInfo); - } - - @DBField(id = 0, type = DBDataType.OBJECT) - public String value1; - - @DBField(id = 1, type = DBDataType.INTEGER) - public int value2; - - @DBField(id = 2, type = DBDataType.INTEGER) - public int value3; - - @DBPropertyGetter(id = 0, type = DBDataType.OBJECT) - public String getValue3() { - return getProperty(); - } - - @DBPropertySetter(id = 0, type = DBDataType.OBJECT) - public void setValue3(String value) { - setProperty(value); - } - - @DBPropertyGetter(id = 1, type = DBDataType.DATABASE_OBJECT) - public Class1 getValue4() { - return getProperty(); - } - - @DBPropertySetter(id = 1, type = DBDataType.DATABASE_OBJECT) - public void setValue4(Class1 value) { - setProperty(value); - } - - @DBPropertyGetter(id = 2, type = DBDataType.OBJECT) - public String getValueStr() { - return getProperty(); - } - - @DBPropertySetter(id = 2, type = DBDataType.OBJECT) - public void setValueStr(String value) { - setProperty(value); - } - - @Override - public String toString() { - return new StringJoiner(", ", Class1.class.getSimpleName() + "[", "]") - .add("value1='" + value1 + "'") - .add("value2=" + value2) - .add("value3=" + value3) - .add("getValue3=" + getValue3()) - .add("getValue4=" + getValue4()) - .add("getValueStr=" + getValueStr()) - .toString(); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/exampleimpl/Class2.java b/src/main/java/org/warp/jcwdb/ann/exampleimpl/Class2.java deleted file mode 100644 index 4b92731..0000000 --- a/src/main/java/org/warp/jcwdb/ann/exampleimpl/Class2.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.warp.jcwdb.ann.exampleimpl; - -import org.warp.jcwdb.ann.*; - -import java.io.IOException; -import java.util.StringJoiner; - -public class Class2 extends Class1 { - - //@DBField(id = 3, type = DBDataType.DATABASE_OBJECT) - //public DBDBObjectList value4; - - @DBField(id = 3, type = DBDataType.DATABASE_OBJECT) - public Class1 value4; - - @DBField(id = 4, type = DBDataType.INTEGER) - public int value5; - - public Class2(JCWDatabase database) { - super(database); - } - - public Class2(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - super(database, objectInfo); - } - - @Override - public String toString() { - return new StringJoiner(", ", Class1.class.getSimpleName() + "[", "]") - .add("value1='" + value1 + "'") - .add("value2=" + value2) - .add("value3=" + value3) - .add("value4=" + value4) - .add("value5=" + value5) - .add("getValue3=" + getValue3()) - .add("getValue4=" + getValue4()) - .add("getValueStr=" + getValueStr()) - .toString(); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/exampleimpl/ClassWithList.java b/src/main/java/org/warp/jcwdb/ann/exampleimpl/ClassWithList.java deleted file mode 100644 index 6e76677..0000000 --- a/src/main/java/org/warp/jcwdb/ann/exampleimpl/ClassWithList.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.warp.jcwdb.ann.exampleimpl; - -import org.warp.jcwdb.ann.*; - -import java.io.IOError; -import java.io.IOException; -import java.util.StringJoiner; - -public class ClassWithList extends DBObject { - - public ClassWithList(JCWDatabase database) { - super(database); - } - - public ClassWithList(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - super(database, objectInfo); - } - - @DBField(id = 0, type = DBDataType.DATABASE_OBJECT) - public DBDBObjectList valueList; - - - @DBPropertySetter(id = 0, type = DBDataType.DATABASE_OBJECT) - public void setList(DBDBObjectList value) { - setProperty(value); - } - - @DBPropertyGetter(id = 0, type = DBDataType.DATABASE_OBJECT) - public DBDBObjectList getList() { - return getProperty(); - } - - @Override - public String toString() { - DBDBObjectList list; - boolean listErrored = false; - try { - list = getList(); - } catch (IOError | Exception ex) { - list = null; - listErrored = true; - } - return new StringJoiner(", ", ClassWithList.class.getSimpleName() + "[", "]") - .add("valueList=" + valueList) - .add("getList=" + (listErrored ? "{error}" : (list == null ? list : list.size() < 100 ? list : "[" + list.size() + " items])"))) - .toString(); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/exampleimpl/IntClass.java b/src/main/java/org/warp/jcwdb/ann/exampleimpl/IntClass.java deleted file mode 100644 index cf19761..0000000 --- a/src/main/java/org/warp/jcwdb/ann/exampleimpl/IntClass.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.warp.jcwdb.ann.exampleimpl; - -import org.warp.jcwdb.ann.*; - -import java.io.IOException; -import java.util.StringJoiner; - -public class IntClass extends DBObject { - - public IntClass(JCWDatabase database) { - super(database); - } - - public IntClass(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - super(database, objectInfo); - } - - @DBField(id = 0, type = DBDataType.INTEGER) - public int value; - - @Override - public String toString() { - return new StringJoiner(", ", IntClass.class.getSimpleName() + "[", "]") - .add("value=" + value) - .toString(); - } -} diff --git a/src/main/java/org/warp/jcwdb/ann/exampleimpl/Main.java b/src/main/java/org/warp/jcwdb/ann/exampleimpl/Main.java deleted file mode 100644 index 2e07a5b..0000000 --- a/src/main/java/org/warp/jcwdb/ann/exampleimpl/Main.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.warp.jcwdb.ann.exampleimpl; - -import org.warp.jcwdb.ann.DBDBObjectList; -import org.warp.jcwdb.ann.JCWDatabase; - -import java.io.IOException; -import java.nio.file.Paths; - -public class Main { - - public static void main(String[] args) throws IOException { - long t0 = System.currentTimeMillis(); - JCWDatabase db = new JCWDatabase(Paths.get("N:\\TimedTemp\\database_temp.db"), Paths.get("N:\\TimedTemp\\database_temp.idx")); - db.registerClass(Class1.class, 0); - db.registerClass(Class2.class, 1); - Class2 class1 = db.loadRoot(Class2.class); - long t1 = System.currentTimeMillis(); - System.err.println("Loading took " + (t1-t0)/1000d + " seconds"); - t0 = System.currentTimeMillis(); - System.err.println("[MAIN] class1="+class1); - class1.value1 = "ciaoooooooooooooooooooooo"; - class1.value2 = 3; - class1.value5 = 5; - System.err.println("[MAIN] value3="+class1.getValue3()); - class1.setValue3("Ciao 3"); - System.err.println("[MAIN] value3="+class1.getValue3()); - - System.err.println("[MAIN] propString="+class1.getValueStr()); - class1.setValueStr("Ciao String"); - System.err.println("[MAIN] propString="+class1.getValueStr()); - - System.err.println("[MAIN] getValue4="+class1.getValue4()); - t1 = System.currentTimeMillis(); - System.err.println("Post-loading took " + (t1-t0)/1000d + " seconds"); - t0 = System.currentTimeMillis(); - for (int i = 0; i < 200; i++) { - Class1 nested; - if ((nested = class1.getValue4()) == null) { - //System.err.println("[MAIN] Created nested class"); - class1.setValue4(nested = new Class1(db)); - } - nested.getValue3(); - //System.err.println("[MAIN] value4="+class1.getValue4()); - //System.err.println("[MAIN] nested value3="+nested.getValue3()); - nested.setValue3("Ciao nested 3"); - //System.err.println("[MAIN] nested value3=" + class1.getValue4().getValue3()); - } - t1 = System.currentTimeMillis(); - System.err.println("Took " + (t1-t0)/1000d + " seconds"); - - - /* - if (class1.value4 == null) { - class1.value4 = new DBDBObjectList<>(db, 100, Class1.class); - } - for (int i = 0; i < 15; i++) { - Class1 c1 = new Class1(db); - c1.value1 = "" + i; - c1.value2 = i; - c1.setValueStr("" + i); - class1.value4.add(c1); - }*/ - class1.value4 = new Class1(db); - } -} \ No newline at end of file diff --git a/src/main/java/org/warp/jcwdb/ann/exampleimpl/MainSingleClass.java b/src/main/java/org/warp/jcwdb/ann/exampleimpl/MainSingleClass.java deleted file mode 100644 index 0cd1961..0000000 --- a/src/main/java/org/warp/jcwdb/ann/exampleimpl/MainSingleClass.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.warp.jcwdb.ann.exampleimpl; - -import org.warp.jcwdb.ann.DBDBObjectList; -import org.warp.jcwdb.ann.DBList; -import org.warp.jcwdb.ann.JCWDatabase; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; - -public class MainSingleClass { - - public static void main(String[] args) throws IOException { - long t0 = System.currentTimeMillis(); - Files.deleteIfExists(Paths.get("N:\\TimedTemp\\database_t.db")); - Files.deleteIfExists(Paths.get("N:\\TimedTemp\\database_t.idx")); - for (int i = 0; i < 18; i++) { - doIt(); - } - } - - public static void doIt() throws IOException { - System.err.println("doIt"); - JCWDatabase db = new JCWDatabase(Paths.get("N:\\TimedTemp\\database_t.db"), Paths.get("N:\\TimedTemp\\database_t.idx")); - db.registerClass(ClassWithList.class, 0); - db.registerClass(IntClass.class, 1); - ClassWithList classWithList = db.loadRoot(ClassWithList.class); - System.err.println("[MAIN init] classWithList="+classWithList); - - if (classWithList.valueList == null) { - System.out.println("Get list was null"); - classWithList.valueList = new DBDBObjectList<>(db, IntClass.class, 10000); - } - DBDBObjectList list = classWithList.valueList; - - for (int i = 0; i < 1000000; i++) { - IntClass intClass = new IntClass(db); - intClass.value = i+0xFF00; - //System.err.println("[WRITE]" + intClass.value); - list.add(intClass); - } - - DBList.DBListIterator it = list.iterator(); - while (it.hasNext()) { - IntClass intClass = it.next(); - //System.err.println("[READ]" + intClass.value); - } - - System.err.println("[MAIN end.] singleClass="+classWithList); - db.close(); - } -} \ No newline at end of file diff --git a/src/main/java/org/warp/jcwdb/ann/exampleimpl/SingleClass.java b/src/main/java/org/warp/jcwdb/ann/exampleimpl/SingleClass.java deleted file mode 100644 index f35e5da..0000000 --- a/src/main/java/org/warp/jcwdb/ann/exampleimpl/SingleClass.java +++ /dev/null @@ -1,68 +0,0 @@ -package org.warp.jcwdb.ann.exampleimpl; - -import org.warp.jcwdb.ann.*; - -import java.io.IOException; -import java.util.StringJoiner; - -public class SingleClass extends DBObject { - - @DBField(id = 0, type = DBDataType.INTEGER) - public int valueInt; - - @DBField(id = 1, type = DBDataType.OBJECT) - public String valueObj; - - @DBField(id = 2, type = DBDataType.DATABASE_OBJECT) - public IntClass valueDB; - - @DBPropertySetter(id = 0, type = DBDataType.INTEGER) - public void setInt(int value) { - setProperty(value); - } - - @DBPropertySetter(id = 1, type = DBDataType.OBJECT) - public void setObj(String value) { - setProperty(value); - } - - @DBPropertySetter(id = 2, type = DBDataType.DATABASE_OBJECT) - public void setDB(IntClass value) { - setProperty(value); - } - - @DBPropertyGetter(id = 0, type = DBDataType.INTEGER) - public int getInt() { - return getProperty(); - } - - @DBPropertyGetter(id = 1, type = DBDataType.OBJECT) - public String getObj() { - return getProperty(); - } - - @DBPropertyGetter(id = 2, type = DBDataType.DATABASE_OBJECT) - public IntClass getDB() { - return getProperty(); - } - - public SingleClass(JCWDatabase database) { - super(database); - } - - public SingleClass(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { - super(database, objectInfo); - } - - @Override - public String toString() { - return new StringJoiner(", ", SingleClass.class.getSimpleName() + "[", "]") - .add("valueInt=" + valueInt) - .add("valueObj='" + valueObj + "'") - .add("valueDB=" + valueDB) - .add("getInt=" + getInt()) - .add("getObj='" + getObj() + "'") - .add("getDB=" + getDB()) - .toString(); - } -} diff --git a/src/test/java/org/warp/jcwdb/AppTest.java b/src/test/java/org/warp/jcwdb/AppTest.java deleted file mode 100644 index 7e58457..0000000 --- a/src/test/java/org/warp/jcwdb/AppTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.warp.jcwdb; - -import org.junit.Test; -import org.warp.jcwdb.ann.JCWDatabase; -import org.warp.jcwdb.ann.exampleimpl.IntClass; -import org.warp.jcwdb.ann.exampleimpl.SingleClass; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; - -import static org.junit.Assert.assertTrue; - -/** - * Unit test for simple App. - */ -public class AppTest { - /** - * Rigorous Test :-) - */ - @Test - public void shouldAnswerWithTrue() { - assertTrue(true); - } - - @Test - public void simpleClassTest() throws IOException { - long t0 = System.currentTimeMillis(); - Files.deleteIfExists(Paths.get("N:\\TimedTemp\\database_s.db")); - Files.deleteIfExists(Paths.get("N:\\TimedTemp\\database_s.idx")); - for (int i = 0; i < 3; i++) { - doSingleClassTest(); - } - } - - public static void doSingleClassTest() throws IOException { - System.err.println("doSingleClassTest"); - JCWDatabase db = new JCWDatabase(Paths.get("N:\\TimedTemp\\database_s.db"), Paths.get("N:\\TimedTemp\\database_s.idx")); - db.registerClass(SingleClass.class, 0); - db.registerClass(IntClass.class, 1); - SingleClass singleClass = db.loadRoot(SingleClass.class); - System.err.println("[MAIN init] singleClass="+singleClass); - - singleClass.getInt(); - singleClass.setInt((int) (Math.random() * 100)); - - singleClass.getObj(); - singleClass.setObj(String.valueOf(Math.random() * 100)); - - if (singleClass.getDB() == null) { - System.out.println("Get db was null"); - singleClass.setDB(new IntClass(db)); - } - IntClass intClass = singleClass.getDB(); - intClass.value = (int) (Math.random() * 100); - - singleClass.valueInt = (int) (Math.random() * 100); - - singleClass.valueObj = String.valueOf(Math.random() * 100); - - if (singleClass.valueDB == null) { - System.out.println("Value db was null"); - singleClass.valueDB = new IntClass(db); - } - singleClass.valueDB.value = (int) (Math.random() * 100); - - - System.err.println("[MAIN end.] singleClass="+singleClass); - db.close(); - } -} diff --git a/src/test/java/org/warp/jcwdb/FileAllocatorTest.java b/src/test/java/org/warp/jcwdb/FileAllocatorTest.java deleted file mode 100644 index 91e4792..0000000 --- a/src/test/java/org/warp/jcwdb/FileAllocatorTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.warp.jcwdb; - -import org.junit.Test; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.SeekableByteChannel; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class FileAllocatorTest { - - @Test - public void shouldAllocateAtZero() throws IOException { - Path tempFile = Files.createTempFile("", ""); - SeekableByteChannel byteCh = Files.newByteChannel(tempFile); - FileAllocator allocator = new FileAllocator(byteCh); - long offset1 = allocator.allocate(512); - assertEquals(0, offset1); - } - - @Test - public void shouldAllocateAt512() throws IOException { - Path tempFile = Files.createTempFile("", ""); - SeekableByteChannel byteCh = Files.newByteChannel(tempFile, StandardOpenOption.WRITE); - byteCh.write(ByteBuffer.wrap(new byte[512])); - FileAllocator allocator = new FileAllocator(byteCh); - long offset1 = allocator.allocate(512); - assertEquals(512, offset1); - } - - @Test - public void shouldAllocateUnusedSpace() throws IOException { - Path tempFile = Files.createTempFile("", ""); - SeekableByteChannel byteCh = Files.newByteChannel(tempFile, StandardOpenOption.WRITE); - FileAllocator allocator = new FileAllocator(byteCh); - long offset1 = allocator.allocate(512); - allocator.markFree(offset1, 512); - long offset2 = allocator.allocate(128); - long offset3 = allocator.allocate(512-128); - long offset4 = allocator.allocate(128); - assertEquals(0, offset2); - assertEquals(128, offset3); - assertEquals(512, offset4); - } - -} diff --git a/src/test/java/org/warp/jcwdb/tests/DBDBObjectListTests.java b/src/test/java/org/warp/jcwdb/tests/DBDBObjectListTests.java new file mode 100644 index 0000000..60eaaa3 --- /dev/null +++ b/src/test/java/org/warp/jcwdb/tests/DBDBObjectListTests.java @@ -0,0 +1,77 @@ +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); + 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() { + checkEmptyList(); + assertEquals(200, root.list.size()); + for (int i = 0; i < 200; i++) { + db.testRootClassValues(root.list.get(i)); + } + } + + private void checkEmptyList() { + 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 { + + public RootWithList(JCWDatabase database) { + super(database); + } + + public RootWithList(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + super(database, objectInfo); + } + + @DBField(id = 0, type = DBDataType.DATABASE_OBJECT) + public DBDBObjectList list; + } +} diff --git a/src/test/java/org/warp/jcwdb/tests/DBMultipleDBObjects.java b/src/test/java/org/warp/jcwdb/tests/DBMultipleDBObjects.java new file mode 100644 index 0000000..c0e0aa1 --- /dev/null +++ b/src/test/java/org/warp/jcwdb/tests/DBMultipleDBObjects.java @@ -0,0 +1,80 @@ +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 { + + public RootTwoClasses(JCWDatabase database) { + super(database); + } + + public RootTwoClasses(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + super(database, objectInfo); + } + + @DBField(id = 0, type = DBDataType.DATABASE_OBJECT) + public TestUtils.RootClass class1; + + @DBField(id = 1, type = DBDataType.DATABASE_OBJECT) + public TestUtils.RootClass class2; + + @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); + } + } +} diff --git a/src/test/java/org/warp/jcwdb/tests/DBNestedDBObjects.java b/src/test/java/org/warp/jcwdb/tests/DBNestedDBObjects.java new file mode 100644 index 0000000..73160df --- /dev/null +++ b/src/test/java/org/warp/jcwdb/tests/DBNestedDBObjects.java @@ -0,0 +1,69 @@ +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.NestedClass; +import org.warp.jcwdb.utils.TestUtils; + +import java.io.IOException; + +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 new file mode 100644 index 0000000..ff962d0 --- /dev/null +++ b/src/test/java/org/warp/jcwdb/tests/DBRootCreation.java @@ -0,0 +1,48 @@ +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.*; + +public class DBRootCreation { + private TestUtils.WrappedDb db; + + @Before + public void setUp() throws Exception { + db = TestUtils.wrapDb().create(); + } + + @Test + public void shouldCreateRoot() { + 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) { + super(database); + } + + public RootClass(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + super(database, objectInfo); + } + + public boolean test() { + return true; + } + } +} diff --git a/src/test/java/org/warp/jcwdb/tests/DBRootFields.java b/src/test/java/org/warp/jcwdb/tests/DBRootFields.java new file mode 100644 index 0000000..0073e08 --- /dev/null +++ b/src/test/java/org/warp/jcwdb/tests/DBRootFields.java @@ -0,0 +1,30 @@ +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 new file mode 100644 index 0000000..a144ecd --- /dev/null +++ b/src/test/java/org/warp/jcwdb/tests/DBRootProperties.java @@ -0,0 +1,30 @@ +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/NestedClass.java b/src/test/java/org/warp/jcwdb/utils/NestedClass.java new file mode 100644 index 0000000..7a53bb3 --- /dev/null +++ b/src/test/java/org/warp/jcwdb/utils/NestedClass.java @@ -0,0 +1,32 @@ +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; + + @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(); + } + + public NestedClass(JCWDatabase database) { + super(database); + } + + public NestedClass(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + super(database, objectInfo); + } +} diff --git a/src/test/java/org/warp/jcwdb/utils/SimplestClass.java b/src/test/java/org/warp/jcwdb/utils/SimplestClass.java new file mode 100644 index 0000000..e73e55d --- /dev/null +++ b/src/test/java/org/warp/jcwdb/utils/SimplestClass.java @@ -0,0 +1,20 @@ +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(JCWDatabase database) { + super(database); + field1 = true; + } + + public SimplestClass(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + super(database, objectInfo); + } +} diff --git a/src/test/java/org/warp/jcwdb/utils/TestUtils.java b/src/test/java/org/warp/jcwdb/utils/TestUtils.java new file mode 100644 index 0000000..5f8c632 --- /dev/null +++ b/src/test/java/org/warp/jcwdb/utils/TestUtils.java @@ -0,0 +1,377 @@ +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.*; +import static org.junit.Assert.assertEquals; + +public class TestUtils { + public static WrappedDb wrapDb() { + return new WrappedDb(); + } + + public static class WrappedDb { + + private JCWDatabase db; + private Path tempDir; + private Runnable r; + + private WrappedDb() { + + } + + public WrappedDb create() throws IOException { + tempDir = Files.createTempDirectory("tests-"); + db = openDatabase(); + if (r != null) { + r.run(); + } + return this; + } + + public WrappedDb create(Consumer 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) { + setRootClassFields(root); + setRootClassProperties(root); + } + + public void setRootClassFields(RootClass root) { + 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) { + 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(Runnable 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; + + @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 RootClass(JCWDatabase database) { + super(database); + } + + public RootClass(JCWDatabase database, DBObjectIndicesManager.DBObjectInfo objectInfo) throws IOException { + super(database, objectInfo); + } + + public boolean test() { + return true; + } + } +}