Multithread
This commit is contained in:
parent
14702d759c
commit
641233af3e
9
pom.xml
9
pom.xml
@ -37,10 +37,17 @@
|
|||||||
<artifactId>fastutil</artifactId>
|
<artifactId>fastutil</artifactId>
|
||||||
<version>8.2.2</version>
|
<version>8.2.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!--
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.ruedigermoeller</groupId>
|
||||||
|
<artifactId>fst</artifactId>
|
||||||
|
<version>2.56</version>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.esotericsoftware</groupId>
|
<groupId>com.esotericsoftware</groupId>
|
||||||
<artifactId>kryo</artifactId>
|
<artifactId>kryo</artifactId>
|
||||||
<version>5.0.0-RC1</version>
|
<version>5.0.0-RC4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>it.cavallium</groupId>
|
<groupId>it.cavallium</groupId>
|
||||||
|
@ -1,157 +0,0 @@
|
|||||||
package it.cavallium.strangedb.java.database;
|
|
||||||
|
|
||||||
import it.cavallium.strangedb.java.annotations.*;
|
|
||||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
|
||||||
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class DatabaseDataInitializer implements IDataInitializer {
|
|
||||||
|
|
||||||
private final DatabaseObjectsIO objectsIO;
|
|
||||||
|
|
||||||
public DatabaseDataInitializer(DatabaseObjectsIO objectsIO) {
|
|
||||||
this.objectsIO = objectsIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeDbObject(EnhancedObject obj) throws IOException {
|
|
||||||
initializeDbObjectFields(obj);
|
|
||||||
initializeDbObjectPrimitiveFields(obj);
|
|
||||||
initializeDbObjectProperties(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeDbObjectFields(EnhancedObject obj) throws IOException {
|
|
||||||
// Declare the variables needed to getBlock the biggest field Id
|
|
||||||
Field[] unorderedFields = objectsIO.getFields(obj);
|
|
||||||
// Find the biggest field Id
|
|
||||||
int biggestFieldId = objectsIO.getBiggestFieldId(unorderedFields);
|
|
||||||
|
|
||||||
// Allocate new UIDs
|
|
||||||
long[] fieldUIDs = objectsIO.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();
|
|
||||||
objectsIO.loadField(obj, field, fieldType, fieldUIDs[fieldId]);
|
|
||||||
fields[fieldId] = field;
|
|
||||||
orderedFieldTypes[fieldId] = fieldType;
|
|
||||||
}
|
|
||||||
// Set fields metadata
|
|
||||||
obj.setFields(fields, orderedFieldTypes, fieldUIDs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeDbObjectPrimitiveFields(EnhancedObject obj) throws IOException {
|
|
||||||
// Declare the variables needed to getBlock the biggest field Id
|
|
||||||
Field[] unorderedFields = objectsIO.getPrimitiveFields(obj);
|
|
||||||
// Find the biggest field Id
|
|
||||||
int biggestFieldId = objectsIO.getBiggestPrimitiveFieldId(unorderedFields);
|
|
||||||
|
|
||||||
// Allocate new UID
|
|
||||||
long fieldDataUID = objectsIO.newNullObject();
|
|
||||||
|
|
||||||
// Declare the other variables
|
|
||||||
Field[] fields = new Field[biggestFieldId + 1];
|
|
||||||
DbPrimitiveType[] orderedFieldTypes = new DbPrimitiveType[biggestFieldId + 1];
|
|
||||||
|
|
||||||
// Load all fields metadata and load them
|
|
||||||
try {
|
|
||||||
for (Field field : unorderedFields) {
|
|
||||||
DbPrimitiveField fieldAnnotation = field.getAnnotation(DbPrimitiveField.class);
|
|
||||||
int fieldId = fieldAnnotation.id();
|
|
||||||
DbPrimitiveType fieldType = fieldAnnotation.type();
|
|
||||||
switch (fieldType) {
|
|
||||||
case BOOLEAN:
|
|
||||||
FieldUtils.writeField(field, obj, false, true);
|
|
||||||
break;
|
|
||||||
case BYTE:
|
|
||||||
FieldUtils.writeField(field, obj, (byte) 0, true);
|
|
||||||
break;
|
|
||||||
case CHAR:
|
|
||||||
FieldUtils.writeField(field, obj, (char) 0, true);
|
|
||||||
break;
|
|
||||||
case SHORT:
|
|
||||||
FieldUtils.writeField(field, obj, (short) 0, true);
|
|
||||||
break;
|
|
||||||
case INTEGER:
|
|
||||||
FieldUtils.writeField(field, obj, 0, true);
|
|
||||||
break;
|
|
||||||
case LONG:
|
|
||||||
FieldUtils.writeField(field, obj, (long) 0, true);
|
|
||||||
break;
|
|
||||||
case FLOAT:
|
|
||||||
FieldUtils.writeField(field, obj, (float) 0, true);
|
|
||||||
break;
|
|
||||||
case DOUBLE:
|
|
||||||
FieldUtils.writeField(field, obj, (double) 0, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fields[fieldId] = field;
|
|
||||||
orderedFieldTypes[fieldId] = fieldType;
|
|
||||||
}
|
|
||||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
// Set fields metadata
|
|
||||||
obj.setPrimitiveFields(fields, orderedFieldTypes, fieldDataUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeDbObjectProperties(EnhancedObject obj) throws IOException {
|
|
||||||
// Declare the variables needed to getBlock the biggest property Id
|
|
||||||
Method[] unorderedPropertyGetters = obj.getPropertyGetters();
|
|
||||||
Method[] unorderedPropertySetters = obj.getPropertySetters();
|
|
||||||
|
|
||||||
// Find the biggest property Id
|
|
||||||
int biggestGetter = objectsIO.getBiggestPropertyGetterId(unorderedPropertyGetters);
|
|
||||||
int biggestSetter = objectsIO.getBiggestPropertySetterId(unorderedPropertySetters);
|
|
||||||
int biggestPropertyId = biggestGetter > biggestSetter ? biggestGetter : biggestSetter;
|
|
||||||
|
|
||||||
// Allocate new UIDs
|
|
||||||
long[] propertyUIDs = objectsIO.allocateNewUIDs(biggestPropertyId + 1);
|
|
||||||
|
|
||||||
for (Method property : unorderedPropertySetters) {
|
|
||||||
DbProperty fieldAnnotation = property.getAnnotation(DbProperty.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<String, DbProperty> setterMethods = new LinkedHashMap<>();
|
|
||||||
Map<String, DbProperty> getterMethods = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
// Load the properties metadata
|
|
||||||
for (Method property : unorderedPropertyGetters) {
|
|
||||||
DbProperty propertyAnnotation = property.getAnnotation(DbProperty.class);
|
|
||||||
int propertyId = propertyAnnotation.id();
|
|
||||||
DbDataType propertyType = propertyAnnotation.type();
|
|
||||||
propertyTypes[propertyId] = propertyType;
|
|
||||||
propertyGetters[propertyId] = property;
|
|
||||||
getterMethods.put(property.getName(), propertyAnnotation);
|
|
||||||
}
|
|
||||||
for (Method property : unorderedPropertySetters) {
|
|
||||||
DbProperty propertyAnnotation = property.getAnnotation(DbProperty.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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,12 +5,7 @@ import it.cavallium.strangedb.database.references.ReferenceInfo;
|
|||||||
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
||||||
import it.cavallium.strangedb.functionalinterfaces.FunctionWithIO;
|
import it.cavallium.strangedb.functionalinterfaces.FunctionWithIO;
|
||||||
import it.cavallium.strangedb.java.objects.EnhancedObjectIndices;
|
import it.cavallium.strangedb.java.objects.EnhancedObjectIndices;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
import it.unimi.dsi.fastutil.longs.LongArraySet;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -66,6 +61,26 @@ public class DatabaseJava extends DatabaseCore implements IDatabaseTools {
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T extends EnhancedObject> T loadRoot(FunctionWithIO<IDatabaseTools, T> ifAbsent, Class<?> forcedClassType) throws IOException {
|
||||||
|
if (hasLoadedRootObject) {
|
||||||
|
throw new RuntimeException("Root already set!");
|
||||||
|
}
|
||||||
|
T root;
|
||||||
|
if (referencesMetadata.getFirstFreeReference() > 0) {
|
||||||
|
root = objectsIO.loadEnhancedObject(0, forcedClassType);
|
||||||
|
} else {
|
||||||
|
if (objectsIO.newNullObject() != 0) {
|
||||||
|
throw new IOException("Can't allocate root!");
|
||||||
|
} else {
|
||||||
|
root = ifAbsent.apply(DatabaseJava.this);
|
||||||
|
objectsIO.setEnhancedObject(0, root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadedRootObject = root;
|
||||||
|
hasLoadedRootObject = true;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void closeAndClean() throws IOException {
|
public void closeAndClean() throws IOException {
|
||||||
if (!this.closed) {
|
if (!this.closed) {
|
||||||
@ -97,7 +112,7 @@ public class DatabaseJava extends DatabaseCore implements IDatabaseTools {
|
|||||||
|
|
||||||
for (int referenceID = 0; referenceID < firstFreeReference; referenceID++) {
|
for (int referenceID = 0; referenceID < firstFreeReference; referenceID++) {
|
||||||
try {
|
try {
|
||||||
ReferenceInfo ref = databaseToClean.referencesMetadata.getReference(referenceID);
|
ReferenceInfo ref = databaseToClean.referencesMetadata.getCleanReference(referenceID);
|
||||||
if (!NONEXISTENT_REFERENCE_INFO.equals(ref)) {
|
if (!NONEXISTENT_REFERENCE_INFO.equals(ref)) {
|
||||||
referencesCount++;
|
referencesCount++;
|
||||||
if (idsToKeep.contains(referenceID)) {
|
if (idsToKeep.contains(referenceID)) {
|
||||||
@ -123,7 +138,7 @@ public class DatabaseJava extends DatabaseCore implements IDatabaseTools {
|
|||||||
|
|
||||||
private void cleanRef(DatabaseJava db, LongArrayList idsToKeep, long ref) throws IOException {
|
private void cleanRef(DatabaseJava db, LongArrayList idsToKeep, long ref) throws IOException {
|
||||||
idsToKeep.add(ref);
|
idsToKeep.add(ref);
|
||||||
ReferenceInfo refInfo = db.referencesMetadata.getReference(ref);
|
ReferenceInfo refInfo = db.referencesMetadata.getCleanReference(ref);
|
||||||
if (!NONEXISTENT_REFERENCE_INFO.equals(refInfo)) {
|
if (!NONEXISTENT_REFERENCE_INFO.equals(refInfo)) {
|
||||||
switch (refInfo.getCleanerId()) {
|
switch (refInfo.getCleanerId()) {
|
||||||
case ENHANCED_OBJECT_METADATA_CLEANER: {
|
case ENHANCED_OBJECT_METADATA_CLEANER: {
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
package it.cavallium.strangedb.java.database;
|
package it.cavallium.strangedb.java.database;
|
||||||
|
|
||||||
import com.esotericsoftware.kryo.Kryo;
|
|
||||||
import com.esotericsoftware.kryo.io.Input;
|
|
||||||
import com.esotericsoftware.kryo.io.Output;
|
|
||||||
import it.cavallium.strangedb.database.references.DatabaseReferencesIO;
|
import it.cavallium.strangedb.database.references.DatabaseReferencesIO;
|
||||||
import it.cavallium.strangedb.java.annotations.*;
|
import it.cavallium.strangedb.java.annotations.*;
|
||||||
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
||||||
@ -20,15 +17,12 @@ import it.unimi.dsi.fastutil.longs.LongList;
|
|||||||
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||||
import org.apache.commons.lang3.reflect.FieldUtils;
|
import org.apache.commons.lang3.reflect.FieldUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
|
|
||||||
import static it.cavallium.strangedb.database.references.DatabaseReferencesMetadata.BLANK_DATA_CLEANER;
|
import static it.cavallium.strangedb.database.references.DatabaseReferencesMetadata.BLANK_DATA_CLEANER;
|
||||||
|
|
||||||
@ -40,16 +34,14 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
private final IDatabaseTools databaseTools;
|
private final IDatabaseTools databaseTools;
|
||||||
private final DatabaseReferencesIO referencesIO;
|
private final DatabaseReferencesIO referencesIO;
|
||||||
|
|
||||||
private final Lock lock = new ReentrantLock();
|
|
||||||
private final DatabaseDataInitializer dataInitializer;
|
private final DatabaseDataInitializer dataInitializer;
|
||||||
|
private final KryoSerializer serializer;
|
||||||
private Kryo kryo = new Kryo();
|
|
||||||
|
|
||||||
public DatabaseObjectsIO(IDatabaseTools databaseTools, DatabaseReferencesIO referencesIO) {
|
public DatabaseObjectsIO(IDatabaseTools databaseTools, DatabaseReferencesIO referencesIO) {
|
||||||
this.databaseTools = databaseTools;
|
this.databaseTools = databaseTools;
|
||||||
this.referencesIO = referencesIO;
|
this.referencesIO = referencesIO;
|
||||||
this.dataInitializer = new DatabaseDataInitializer(this);
|
this.serializer = new KryoSerializer();
|
||||||
kryo.setRegistrationRequired(false);
|
this.dataInitializer = new DatabaseDataInitializer();
|
||||||
int id = -90;
|
int id = -90;
|
||||||
registerClass(boolean[].class, id++);
|
registerClass(boolean[].class, id++);
|
||||||
registerClass(byte[].class, id++);
|
registerClass(byte[].class, id++);
|
||||||
@ -111,16 +103,19 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends EnhancedObject> T loadEnhancedObject(long reference) throws IOException {
|
public <T extends EnhancedObject> T loadEnhancedObject(long reference) throws IOException {
|
||||||
lock.lock();
|
return loadEnhancedObject_(reference, null);
|
||||||
try {
|
|
||||||
return loadEnhancedObject_(reference);
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends EnhancedObject> T loadEnhancedObject(long reference, Class<?> forcedType) throws IOException {
|
||||||
|
if (forcedType == null) {
|
||||||
|
throw new NullPointerException("The class is null!");
|
||||||
|
}
|
||||||
|
return loadEnhancedObject_(reference, forcedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <T extends EnhancedObject> T loadEnhancedObject_(long reference) throws IOException {
|
private <T extends EnhancedObject> T loadEnhancedObject_(long reference, Class<?> forcedType) throws IOException {
|
||||||
ByteBuffer buffer = referencesIO.readFromReference(reference);
|
ByteBuffer buffer = referencesIO.readFromReference(reference);
|
||||||
if (buffer.limit() == 0) {
|
if (buffer.limit() == 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -128,12 +123,17 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
int serializedVersion = Byte.toUnsignedInt(buffer.get()) - 5;
|
int serializedVersion = Byte.toUnsignedInt(buffer.get()) - 5;
|
||||||
if (serializedVersion < 0) {
|
if (serializedVersion < 0) {
|
||||||
System.err.println("PLEASE UPGRADE THE DATABASE");
|
System.err.println("PLEASE UPGRADE THE DATABASE");
|
||||||
throw new IllegalAccessError("PLEASE UPGRADE THE DATABASE");
|
throw new IOException("PLEASE UPGRADE THE DATABASE");
|
||||||
}
|
}
|
||||||
int serializedClassLength = Byte.toUnsignedInt(buffer.get());
|
int serializedClassLength = Byte.toUnsignedInt(buffer.get());
|
||||||
byte[] serializedClassData = new byte[serializedClassLength];
|
byte[] serializedClassData = new byte[serializedClassLength];
|
||||||
buffer.get(serializedClassData);
|
buffer.get(serializedClassData);
|
||||||
Class<T> objectType = kryo.readClass(new Input(serializedClassData)).getType();
|
Class<?> objectType;
|
||||||
|
try {
|
||||||
|
objectType = forcedType != null ? forcedType : serializer.readClassBytes(serializedClassData);
|
||||||
|
} catch (Exception | Error ex) {
|
||||||
|
throw new IOException(ex);
|
||||||
|
}
|
||||||
int fieldsCount = buffer.getInt();
|
int fieldsCount = buffer.getInt();
|
||||||
int methodsCount = buffer.getInt();
|
int methodsCount = buffer.getInt();
|
||||||
long[] fieldRefs = new long[fieldsCount];
|
long[] fieldRefs = new long[fieldsCount];
|
||||||
@ -152,8 +152,6 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public EnhancedObjectIndices loadEnhancedObjectUids(long reference) throws IOException {
|
public EnhancedObjectIndices loadEnhancedObjectUids(long reference) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
ByteBuffer buffer = referencesIO.readFromReference(reference);
|
ByteBuffer buffer = referencesIO.readFromReference(reference);
|
||||||
if (buffer.limit() == 0) {
|
if (buffer.limit() == 0) {
|
||||||
return null;
|
return null;
|
||||||
@ -163,7 +161,12 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
int serializedClassLength = Byte.toUnsignedInt(buffer.get());
|
int serializedClassLength = Byte.toUnsignedInt(buffer.get());
|
||||||
byte[] serializedClassData = new byte[serializedClassLength];
|
byte[] serializedClassData = new byte[serializedClassLength];
|
||||||
buffer.get(serializedClassData);
|
buffer.get(serializedClassData);
|
||||||
Class<? extends EnhancedObject> objectType = (Class<? extends EnhancedObject>) kryo.readClass(new Input(serializedClassData)).getType();
|
Class<? extends EnhancedObject> objectType;
|
||||||
|
try {
|
||||||
|
objectType = serializer.readClassBytes(serializedClassData);
|
||||||
|
} catch (Exception | Error ex) {
|
||||||
|
throw new IOException(ex);
|
||||||
|
}
|
||||||
int fieldsCount = buffer.getInt();
|
int fieldsCount = buffer.getInt();
|
||||||
int methodsCount = buffer.getInt();
|
int methodsCount = buffer.getInt();
|
||||||
long[] fieldRefs = new long[fieldsCount];
|
long[] fieldRefs = new long[fieldsCount];
|
||||||
@ -176,25 +179,17 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
long nativeFieldsDataReference = buffer.getLong();
|
long nativeFieldsDataReference = buffer.getLong();
|
||||||
return new EnhancedObjectIndices(objectType, reference, fieldRefs, methodRefs, nativeFieldsDataReference);
|
return new EnhancedObjectIndices(objectType, reference, fieldRefs, methodRefs, nativeFieldsDataReference);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object loadData(DbDataType propertyType, long dataReference) throws IOException {
|
public Object loadData(DbDataType propertyType, long dataReference) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return loadData_(propertyType, dataReference);
|
return loadData_(propertyType, dataReference);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object loadData_(DbDataType propertyType, long dataReference) throws IOException {
|
private Object loadData_(DbDataType propertyType, long dataReference) throws IOException {
|
||||||
|
|
||||||
switch (propertyType) {
|
switch (propertyType) {
|
||||||
case ENHANCED_OBJECT:
|
case ENHANCED_OBJECT:
|
||||||
return loadEnhancedObject_(dataReference);
|
return loadEnhancedObject_(dataReference, null);
|
||||||
case OBJECT:
|
case OBJECT:
|
||||||
return loadObject_(dataReference);
|
return loadObject_(dataReference);
|
||||||
case REFERENCES_LIST:
|
case REFERENCES_LIST:
|
||||||
@ -265,12 +260,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends EnhancedObject> void setEnhancedObject(long reference, T value) throws IOException {
|
public <T extends EnhancedObject> void setEnhancedObject(long reference, T value) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
setEnhancedObject_(reference, value);
|
setEnhancedObject_(reference, value);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends EnhancedObject> void setEnhancedObject_(long reference, T value) throws IOException {
|
private <T extends EnhancedObject> void setEnhancedObject_(long reference, T value) throws IOException {
|
||||||
@ -291,9 +281,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
final long[] propertyReferences = objectFullInfo.getPropertyReferences();
|
final long[] propertyReferences = objectFullInfo.getPropertyReferences();
|
||||||
final DbDataType[] propertyTypes = objectFullInfo.getPropertyTypes();
|
final DbDataType[] propertyTypes = objectFullInfo.getPropertyTypes();
|
||||||
final Object[] propertyValues = objectFullInfo.getLoadedPropertyValues();
|
final Object[] propertyValues = objectFullInfo.getLoadedPropertyValues();
|
||||||
Output serializedClassDataStream = new Output(1024, 8192);
|
byte[] serializedClassData = serializer.writeClassBytes(value.getClass());
|
||||||
kryo.writeClass(serializedClassDataStream, value.getClass());
|
|
||||||
byte[] serializedClassData = serializedClassDataStream.toBytes();
|
|
||||||
final int totalSize = Byte.BYTES + serializedClassData.length + Byte.BYTES + Integer.BYTES * 2 + fieldReferences.length * Long.BYTES
|
final int totalSize = Byte.BYTES + serializedClassData.length + Byte.BYTES + Integer.BYTES * 2 + fieldReferences.length * Long.BYTES
|
||||||
+ propertyReferences.length * Long.BYTES + Long.BYTES;
|
+ propertyReferences.length * Long.BYTES + Long.BYTES;
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(totalSize);
|
ByteBuffer buffer = ByteBuffer.allocate(totalSize);
|
||||||
@ -340,12 +328,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T loadObject(long reference) throws IOException {
|
public <T> T loadObject(long reference) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return loadObject_(reference);
|
return loadObject_(reference);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -356,17 +339,16 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
buffer.rewind();
|
buffer.rewind();
|
||||||
byte[] data = buffer.array();
|
byte[] data = buffer.array();
|
||||||
return (T) kryo.readClassAndObject(new Input(data));
|
try {
|
||||||
|
return serializer.readClassAndObjectBytes(data);
|
||||||
|
} catch (Exception | Error ex) {
|
||||||
|
throw new IOException(ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LongArrayList loadReferencesList(long reference) throws IOException {
|
public LongArrayList loadReferencesList(long reference) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return loadReferencesList_(reference);
|
return loadReferencesList_(reference);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LongArrayList loadReferencesList_(long reference) throws IOException {
|
private LongArrayList loadReferencesList_(long reference) throws IOException {
|
||||||
@ -384,12 +366,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LongList loadPrimitiveData(long reference) throws IOException {
|
public LongList loadPrimitiveData(long reference) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return loadPrimitiveData_(reference);
|
return loadPrimitiveData_(reference);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LongList loadPrimitiveData_(long reference) throws IOException {
|
private LongList loadPrimitiveData_(long reference) throws IOException {
|
||||||
@ -407,21 +384,12 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> void setObject(long reference, T value) throws IOException {
|
public <T> void setObject(long reference, T value) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
setObject_(reference, value);
|
setObject_(reference, value);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void setObject_(long reference, T value) throws IOException {
|
private <T> void setObject_(long reference, T value) throws IOException {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
byte[] data = serializer.writeClassAndObjectBytes(value);
|
||||||
Output output = new Output(outputStream);
|
|
||||||
kryo.writeClassAndObject(output, value);
|
|
||||||
output.flush();
|
|
||||||
byte[] data = outputStream.toByteArray();
|
|
||||||
ByteBuffer dataByteBuffer = ByteBuffer.wrap(data);
|
ByteBuffer dataByteBuffer = ByteBuffer.wrap(data);
|
||||||
referencesIO.writeToReference(reference, BLANK_DATA_CLEANER, data.length, dataByteBuffer);
|
referencesIO.writeToReference(reference, BLANK_DATA_CLEANER, data.length, dataByteBuffer);
|
||||||
} else {
|
} else {
|
||||||
@ -431,12 +399,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setReferencesList(long reference, LongArrayList value) throws IOException {
|
public void setReferencesList(long reference, LongArrayList value) throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
setReferencesList_(reference, value);
|
setReferencesList_(reference, value);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setReferencesList_(long reference, LongArrayList value) throws IOException {
|
private void setReferencesList_(long reference, LongArrayList value) throws IOException {
|
||||||
@ -456,12 +419,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long newNullObject() throws IOException {
|
public long newNullObject() throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return newNullObject_();
|
return newNullObject_();
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long newNullObject_() throws IOException {
|
private long newNullObject_() throws IOException {
|
||||||
@ -480,7 +438,9 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
if (id < -100) {
|
if (id < -100) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
kryo.register(type, 100 + id);
|
final int realId = id + 100;
|
||||||
|
|
||||||
|
serializer.registerClass(type, realId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends EnhancedObject> void preloadEnhancedObjectProperties(T obj, long[] propertyReferences) {
|
private <T extends EnhancedObject> void preloadEnhancedObjectProperties(T obj, long[] propertyReferences) {
|
||||||
@ -531,12 +491,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getBiggestPropertyGetterId(Method[] unorderedPropertyGetters) {
|
public int getBiggestPropertyGetterId(Method[] unorderedPropertyGetters) {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return getBiggestPropertyGetterId_(unorderedPropertyGetters);
|
return getBiggestPropertyGetterId_(unorderedPropertyGetters);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getBiggestPropertyGetterId_(Method[] unorderedPropertyGetters) {
|
private int getBiggestPropertyGetterId_(Method[] unorderedPropertyGetters) {
|
||||||
@ -552,12 +507,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getBiggestPropertySetterId(Method[] unorderedPropertySetters) {
|
public int getBiggestPropertySetterId(Method[] unorderedPropertySetters) {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return getBiggestPropertySetterId_(unorderedPropertySetters);
|
return getBiggestPropertySetterId_(unorderedPropertySetters);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getBiggestPropertySetterId_(Method[] unorderedPropertySetters) {
|
private int getBiggestPropertySetterId_(Method[] unorderedPropertySetters) {
|
||||||
@ -601,6 +551,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
Field field = fields[id];
|
Field field = fields[id];
|
||||||
DbPrimitiveType type = orderedFieldTypes[id];
|
DbPrimitiveType type = orderedFieldTypes[id];
|
||||||
|
|
||||||
|
if (field != null) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BOOLEAN:
|
case BOOLEAN:
|
||||||
FieldUtils.writeField(field, obj, (boolean) (buffer.getLong() % 2 == 1), true);
|
FieldUtils.writeField(field, obj, (boolean) (buffer.getLong() % 2 == 1), true);
|
||||||
@ -628,6 +579,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
@ -662,12 +614,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
|
|
||||||
public <T extends EnhancedObject> void loadField(T obj, Field field, DbDataType fieldType, long fieldReference)
|
public <T extends EnhancedObject> void loadField(T obj, Field field, DbDataType fieldType, long fieldReference)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
loadField_(obj, field, fieldType, fieldReference);
|
loadField_(obj, field, fieldType, fieldReference);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends EnhancedObject> void loadField_(T obj, Field field, DbDataType fieldType, long fieldReference)
|
private <T extends EnhancedObject> void loadField_(T obj, Field field, DbDataType fieldType, long fieldReference)
|
||||||
@ -687,12 +634,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T extends EnhancedObject> Field[] getFields(T obj) {
|
public <T extends EnhancedObject> Field[] getFields(T obj) {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return getFields_(obj);
|
return getFields_(obj);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends EnhancedObject> Field[] getFields_(T obj) {
|
private <T extends EnhancedObject> Field[] getFields_(T obj) {
|
||||||
@ -700,12 +642,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T extends EnhancedObject> Field[] getPrimitiveFields(T obj) {
|
public <T extends EnhancedObject> Field[] getPrimitiveFields(T obj) {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return getPrimitiveFields_(obj);
|
return getPrimitiveFields_(obj);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends EnhancedObject> Field[] getPrimitiveFields_(T obj) {
|
private <T extends EnhancedObject> Field[] getPrimitiveFields_(T obj) {
|
||||||
@ -713,12 +650,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getBiggestFieldId(Field[] unorderedFields) {
|
public int getBiggestFieldId(Field[] unorderedFields) {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return getBiggestFieldId_(unorderedFields);
|
return getBiggestFieldId_(unorderedFields);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getBiggestFieldId_(Field[] unorderedFields) {
|
private int getBiggestFieldId_(Field[] unorderedFields) {
|
||||||
@ -734,12 +666,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getBiggestPrimitiveFieldId(Field[] unorderedFields) {
|
public int getBiggestPrimitiveFieldId(Field[] unorderedFields) {
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
return getBiggestPrimitiveFieldId_(unorderedFields);
|
return getBiggestPrimitiveFieldId_(unorderedFields);
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getBiggestPrimitiveFieldId_(Field[] unorderedFields) {
|
private int getBiggestPrimitiveFieldId_(Field[] unorderedFields) {
|
||||||
@ -754,9 +681,10 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
return biggestFieldId;
|
return biggestFieldId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends EnhancedObject> T toInstance(Class<T> type) throws IOException {
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T extends EnhancedObject> T toInstance(Class<?> type) throws IOException {
|
||||||
try {
|
try {
|
||||||
T obj = type.getConstructor().newInstance();
|
T obj = (T) type.getConstructor().newInstance();
|
||||||
obj.setDatabaseTools(databaseTools);
|
obj.setDatabaseTools(databaseTools);
|
||||||
return obj;
|
return obj;
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
@ -767,7 +695,7 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends EnhancedObject> T preloadEnhancedObject(Class<T> objectType, int serializedVersion, long nativeFieldsRef, long[] fieldRefs, long[] methodRefs) throws IOException {
|
private <T extends EnhancedObject> T preloadEnhancedObject(Class<?> objectType, int serializedVersion, long nativeFieldsRef, long[] fieldRefs, long[] methodRefs) throws IOException {
|
||||||
// Instantiate the class to an object
|
// Instantiate the class to an object
|
||||||
T obj = toInstance(objectType);
|
T obj = toInstance(objectType);
|
||||||
|
|
||||||
@ -777,22 +705,26 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
if (dbClass != null) {
|
if (dbClass != null) {
|
||||||
classVersion = dbClass.version();
|
classVersion = dbClass.version();
|
||||||
}
|
}
|
||||||
if (classVersion > serializedVersion) {
|
if (classVersion == serializedVersion) {
|
||||||
DatabaseEnhancedObjectUpgrader enhancedObjectUpgrader = new DatabaseEnhancedObjectUpgrader(this, fieldRefs, methodRefs, nativeFieldsRef);
|
|
||||||
dataInitializer.initializeDbObject(obj);
|
|
||||||
obj.onUpgrade(serializedVersion, enhancedObjectUpgrader);
|
|
||||||
} else if (classVersion < serializedVersion) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"The serialized class is more recent than the current version of that class!");
|
|
||||||
} else {
|
|
||||||
preloadEnhancedObjectPrimitiveFields(obj, nativeFieldsRef);
|
preloadEnhancedObjectPrimitiveFields(obj, nativeFieldsRef);
|
||||||
preloadEnhancedObjectFields(obj, fieldRefs);
|
preloadEnhancedObjectFields(obj, fieldRefs);
|
||||||
preloadEnhancedObjectProperties(obj, methodRefs);
|
preloadEnhancedObjectProperties(obj, methodRefs);
|
||||||
|
} else if (classVersion > serializedVersion) {
|
||||||
|
DatabaseEnhancedObjectUpgrader enhancedObjectUpgrader = new DatabaseEnhancedObjectUpgrader(this, fieldRefs, methodRefs, nativeFieldsRef);
|
||||||
|
dataInitializer.initializeDbObject_(obj);
|
||||||
|
obj.onUpgrade(serializedVersion, enhancedObjectUpgrader);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"The serialized class is more recent than the current version of that class!");
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long[] allocateNewUIDs(int quantity) throws IOException {
|
public long[] allocateNewUIDs(int quantity) throws IOException {
|
||||||
|
return allocateNewUIDs_(quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long[] allocateNewUIDs_(int quantity) throws IOException {
|
||||||
long[] ids = new long[quantity];
|
long[] ids = new long[quantity];
|
||||||
for (int i = 0; i < quantity; i++) {
|
for (int i = 0; i < quantity; i++) {
|
||||||
ids[i] = newNullObject_();
|
ids[i] = newNullObject_();
|
||||||
@ -805,4 +737,151 @@ public class DatabaseObjectsIO implements IObjectsIO {
|
|||||||
return dataInitializer;
|
return dataInitializer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class DatabaseDataInitializer implements IDataInitializer {
|
||||||
|
|
||||||
|
public DatabaseDataInitializer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initializeDbObject(EnhancedObject obj) throws IOException {
|
||||||
|
initializeDbObject_(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeDbObject_(EnhancedObject obj) throws IOException {
|
||||||
|
initializeDbObjectFields(obj);
|
||||||
|
initializeDbObjectPrimitiveFields(obj);
|
||||||
|
initializeDbObjectProperties(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeDbObjectFields(EnhancedObject obj) throws IOException {
|
||||||
|
// Declare the variables needed to getBlock the biggest field Id
|
||||||
|
Field[] unorderedFields = getFields_(obj);
|
||||||
|
// Find the biggest field Id
|
||||||
|
int biggestFieldId = getBiggestFieldId_(unorderedFields);
|
||||||
|
|
||||||
|
// Allocate new UIDs
|
||||||
|
long[] fieldUIDs = 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();
|
||||||
|
loadField_(obj, field, fieldType, fieldUIDs[fieldId]);
|
||||||
|
fields[fieldId] = field;
|
||||||
|
orderedFieldTypes[fieldId] = fieldType;
|
||||||
|
}
|
||||||
|
// Set fields metadata
|
||||||
|
obj.setFields(fields, orderedFieldTypes, fieldUIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeDbObjectPrimitiveFields(EnhancedObject obj) throws IOException {
|
||||||
|
// Declare the variables needed to getBlock the biggest field Id
|
||||||
|
Field[] unorderedFields = getPrimitiveFields_(obj);
|
||||||
|
// Find the biggest field Id
|
||||||
|
int biggestFieldId = getBiggestPrimitiveFieldId_(unorderedFields);
|
||||||
|
|
||||||
|
// Allocate new UID
|
||||||
|
long fieldDataUID = newNullObject_();
|
||||||
|
|
||||||
|
// Declare the other variables
|
||||||
|
Field[] fields = new Field[biggestFieldId + 1];
|
||||||
|
DbPrimitiveType[] orderedFieldTypes = new DbPrimitiveType[biggestFieldId + 1];
|
||||||
|
|
||||||
|
// Load all fields metadata and load them
|
||||||
|
try {
|
||||||
|
for (Field field : unorderedFields) {
|
||||||
|
DbPrimitiveField fieldAnnotation = field.getAnnotation(DbPrimitiveField.class);
|
||||||
|
int fieldId = fieldAnnotation.id();
|
||||||
|
DbPrimitiveType fieldType = fieldAnnotation.type();
|
||||||
|
switch (fieldType) {
|
||||||
|
case BOOLEAN:
|
||||||
|
FieldUtils.writeField(field, obj, false, true);
|
||||||
|
break;
|
||||||
|
case BYTE:
|
||||||
|
FieldUtils.writeField(field, obj, (byte) 0, true);
|
||||||
|
break;
|
||||||
|
case CHAR:
|
||||||
|
FieldUtils.writeField(field, obj, (char) 0, true);
|
||||||
|
break;
|
||||||
|
case SHORT:
|
||||||
|
FieldUtils.writeField(field, obj, (short) 0, true);
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
FieldUtils.writeField(field, obj, 0, true);
|
||||||
|
break;
|
||||||
|
case LONG:
|
||||||
|
FieldUtils.writeField(field, obj, (long) 0, true);
|
||||||
|
break;
|
||||||
|
case FLOAT:
|
||||||
|
FieldUtils.writeField(field, obj, (float) 0, true);
|
||||||
|
break;
|
||||||
|
case DOUBLE:
|
||||||
|
FieldUtils.writeField(field, obj, (double) 0, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fields[fieldId] = field;
|
||||||
|
orderedFieldTypes[fieldId] = fieldType;
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
// Set fields metadata
|
||||||
|
obj.setPrimitiveFields(fields, orderedFieldTypes, fieldDataUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeDbObjectProperties(EnhancedObject obj) throws IOException {
|
||||||
|
// Declare the variables needed to getBlock 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;
|
||||||
|
|
||||||
|
// Allocate new UIDs
|
||||||
|
long[] propertyUIDs = allocateNewUIDs_(biggestPropertyId + 1);
|
||||||
|
|
||||||
|
for (Method property : unorderedPropertySetters) {
|
||||||
|
DbProperty fieldAnnotation = property.getAnnotation(DbProperty.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<String, DbProperty> setterMethods = new LinkedHashMap<>();
|
||||||
|
Map<String, DbProperty> getterMethods = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
// Load the properties metadata
|
||||||
|
for (Method property : unorderedPropertyGetters) {
|
||||||
|
DbProperty propertyAnnotation = property.getAnnotation(DbProperty.class);
|
||||||
|
int propertyId = propertyAnnotation.id();
|
||||||
|
DbDataType propertyType = propertyAnnotation.type();
|
||||||
|
propertyTypes[propertyId] = propertyType;
|
||||||
|
propertyGetters[propertyId] = property;
|
||||||
|
getterMethods.put(property.getName(), propertyAnnotation);
|
||||||
|
}
|
||||||
|
for (Method property : unorderedPropertySetters) {
|
||||||
|
DbProperty propertyAnnotation = property.getAnnotation(DbProperty.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
package it.cavallium.strangedb.java.database;
|
||||||
|
|
||||||
|
import org.nustaq.serialization.FSTConfiguration;
|
||||||
|
import org.nustaq.serialization.FSTObjectInput;
|
||||||
|
import org.nustaq.serialization.FSTObjectOutput;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class FSTSerializer implements ISerializer {
|
||||||
|
|
||||||
|
private FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration();
|
||||||
|
|
||||||
|
public FSTSerializer() {
|
||||||
|
conf.setStructMode(true);
|
||||||
|
conf.setClassLoader(ClassLoader.getSystemClassLoader());
|
||||||
|
conf.setCrossPlatform(false);
|
||||||
|
conf.setPreferSpeed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T read(InputStream stream, Class<T> type) throws IOException {
|
||||||
|
try {
|
||||||
|
FSTObjectInput in = conf.getObjectInput(stream);
|
||||||
|
T result = (T) in.readObject(type);
|
||||||
|
// DON'T: in.close(); here prevents reuse and will result in an exception
|
||||||
|
stream.close();
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T readBytes(byte[] input, Class<T> type) throws IOException {
|
||||||
|
return read(new ByteArrayInputStream(input), type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Class<T> readClass(InputStream stream) throws IOException {
|
||||||
|
try {
|
||||||
|
FSTObjectInput in = conf.getObjectInput(stream);
|
||||||
|
Class<T> result = (Class<T>) in.readObject(Class.class);
|
||||||
|
// DON'T: in.close(); here prevents reuse and will result in an exception
|
||||||
|
stream.close();
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> Class<T> readClassBytes(byte[] input) throws IOException {
|
||||||
|
return readClass(new ByteArrayInputStream(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void write(OutputStream stream, T toWrite, Class<?> type) throws IOException {
|
||||||
|
FSTObjectOutput out = conf.getObjectOutput(stream);
|
||||||
|
out.writeObject(toWrite, type);
|
||||||
|
// DON'T out.close() when using factory method;
|
||||||
|
out.flush();
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> byte[] writeBytes(T toWrite, Class<?> type) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
write(baos, toWrite, type);
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeClass(OutputStream stream, Class<?> toWrite) throws IOException {
|
||||||
|
FSTObjectOutput out = conf.getObjectOutput(stream);
|
||||||
|
out.writeObject(toWrite, Class.class);
|
||||||
|
// DON'T out.close() when using factory method;
|
||||||
|
out.flush();
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] writeClassBytes(Class<?> toWrite) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
writeClass(baos, toWrite);
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerClass(Class<?> type, int id) {
|
||||||
|
conf.registerClass(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> byte[] writeClassAndObjectBytes(T value) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
FSTObjectOutput out = conf.getObjectOutput(baos);
|
||||||
|
out.writeObject(value);
|
||||||
|
// DON'T out.close() when using factory method;
|
||||||
|
out.flush();
|
||||||
|
baos.close();
|
||||||
|
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T readClassAndObjectBytes(byte[] input) throws IOException {
|
||||||
|
try {
|
||||||
|
ByteArrayInputStream bais = new ByteArrayInputStream(input);
|
||||||
|
FSTObjectInput in = conf.getObjectInput(bais);
|
||||||
|
T result;
|
||||||
|
result = (T) in.readObject();
|
||||||
|
// DON'T: in.close(); here prevents reuse and will result in an exception
|
||||||
|
bais.close();
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
**/
|
@ -13,6 +13,9 @@ public interface IObjectsIO {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
<T extends EnhancedObject> T loadEnhancedObject(long reference) throws IOException;
|
<T extends EnhancedObject> T loadEnhancedObject(long reference) throws IOException;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
<T extends EnhancedObject> T loadEnhancedObject(long reference, Class<?> forcedType) throws IOException;
|
||||||
|
|
||||||
EnhancedObjectIndices loadEnhancedObjectUids(long reference) throws IOException;
|
EnhancedObjectIndices loadEnhancedObjectUids(long reference) throws IOException;
|
||||||
|
|
||||||
<T> T loadObject(long reference) throws IOException;
|
<T> T loadObject(long reference) throws IOException;
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package it.cavallium.strangedb.java.database;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface ISerializer {
|
||||||
|
<T> Class<T> readClassBytes(byte[] input) throws IOException;
|
||||||
|
|
||||||
|
byte[] writeClassBytes(Class<?> toWrite) throws IOException;
|
||||||
|
|
||||||
|
<T> byte[] writeClassAndObjectBytes(T value) throws IOException;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
<T> T readClassAndObjectBytes(byte[] input) throws IOException;
|
||||||
|
|
||||||
|
void registerClass(Class<?> type, int id);
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package it.cavallium.strangedb.java.database;
|
||||||
|
|
||||||
|
import com.esotericsoftware.kryo.Kryo;
|
||||||
|
import com.esotericsoftware.kryo.io.ByteBufferOutput;
|
||||||
|
import com.esotericsoftware.kryo.io.Input;
|
||||||
|
import com.esotericsoftware.kryo.io.KryoDataOutput;
|
||||||
|
import com.esotericsoftware.kryo.io.Output;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
public class KryoSerializer implements ISerializer {
|
||||||
|
|
||||||
|
private static final int KRYO_INSTANCES = 20;
|
||||||
|
|
||||||
|
private ReentrantLock[] locks = new ReentrantLock[KRYO_INSTANCES];
|
||||||
|
private final Kryo[] kryo = new Kryo[KRYO_INSTANCES];
|
||||||
|
private AtomicInteger current = new AtomicInteger(0);
|
||||||
|
|
||||||
|
public KryoSerializer() {
|
||||||
|
for (int i = 0; i < KRYO_INSTANCES; i++) {
|
||||||
|
locks[i] = new ReentrantLock(false);
|
||||||
|
kryo[i] = new Kryo();
|
||||||
|
kryo[i].setRegistrationRequired(false);
|
||||||
|
kryo[i].setWarnUnregisteredClasses(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T> Class<T> readClassBytes(byte[] input) {
|
||||||
|
int i = current.getAndUpdate((currentInt) -> currentInt + 1 == KRYO_INSTANCES ? 0 : currentInt + 1);
|
||||||
|
locks[i].lock();
|
||||||
|
try {
|
||||||
|
return (Class<T>) kryo[i].readClass(new Input(input)).getType();
|
||||||
|
} finally {
|
||||||
|
locks[i].unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] writeClassBytes(Class<?> value) {
|
||||||
|
int i = current.getAndUpdate((currentInt) -> currentInt + 1 == KRYO_INSTANCES ? 0 : currentInt + 1);
|
||||||
|
locks[i].lock();
|
||||||
|
try {
|
||||||
|
Output out = new Output(1024, Integer.MAX_VALUE);
|
||||||
|
kryo[i].writeClass(out, value);
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
return out.toBytes();
|
||||||
|
} finally {
|
||||||
|
locks[i].unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> byte[] writeClassAndObjectBytes(T value) {
|
||||||
|
int i = current.getAndUpdate((currentInt) -> currentInt + 1 == KRYO_INSTANCES ? 0 : currentInt + 1);
|
||||||
|
locks[i].lock();
|
||||||
|
try {
|
||||||
|
Output out = new Output(1024, Integer.MAX_VALUE);
|
||||||
|
kryo[i].writeClassAndObject(out, value);
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
return out.toBytes();
|
||||||
|
} finally {
|
||||||
|
locks[i].unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <T> T readClassAndObjectBytes(byte[] input) {
|
||||||
|
int i = current.getAndUpdate((currentInt) -> currentInt + 1 == KRYO_INSTANCES ? 0 : currentInt + 1);
|
||||||
|
locks[i].lock();
|
||||||
|
try {
|
||||||
|
return (T) kryo[i].readClassAndObject(new Input(input));
|
||||||
|
} finally {
|
||||||
|
locks[i].unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerClass(Class<?> type, int id) {
|
||||||
|
for (int i = 0; i < KRYO_INSTANCES; i++) {
|
||||||
|
locks[i].lock();
|
||||||
|
try {
|
||||||
|
kryo[i].register(type, id);
|
||||||
|
} finally {
|
||||||
|
locks[i].unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,11 +1,18 @@
|
|||||||
package it.cavallium.strangedb.java.objects.lists;
|
package it.cavallium.strangedb.java.objects.lists;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.functionalinterfaces.ConsumerWithIO;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CompletionException;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
public class ElementsArrayList<T> implements ElementsList<T> {
|
public class ElementsArrayList<T> implements ElementsList<T> {
|
||||||
|
|
||||||
|
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(false);
|
||||||
|
|
||||||
private final ArrayList<T> list;
|
private final ArrayList<T> list;
|
||||||
|
|
||||||
public ElementsArrayList() {
|
public ElementsArrayList() {
|
||||||
@ -25,9 +32,34 @@ public class ElementsArrayList<T> implements ElementsList<T> {
|
|||||||
return list.get(index);
|
return list.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachParallelUnsorted(ConsumerWithIO<T> action) throws IOException {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
list.parallelStream().forEach((item) -> {
|
||||||
|
try {
|
||||||
|
action.accept(item);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new CompletionException(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (CompletionException ex) {
|
||||||
|
throw new IOException(ex.getCause());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(T value) {
|
public void add(T value) {
|
||||||
|
readWriteLock.writeLock().lock();
|
||||||
|
try {
|
||||||
list.add(value);
|
list.add(value);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.writeLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -37,34 +69,69 @@ public class ElementsArrayList<T> implements ElementsList<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(int index, T value) {
|
public void set(int index, T value) {
|
||||||
|
readWriteLock.writeLock().lock();
|
||||||
|
try {
|
||||||
list.set(index, value);
|
list.set(index, value);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.writeLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(int index, T value) {
|
public void add(int index, T value) {
|
||||||
|
readWriteLock.writeLock().lock();
|
||||||
|
try {
|
||||||
list.add(index, value);
|
list.add(index, value);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.writeLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T getLast() {
|
public T getLast() {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
return list.get(list.size() - 1);
|
return list.get(list.size() - 1);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
return list.isEmpty();
|
return list.isEmpty();
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
return list.size();
|
return list.size();
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(Object o) {
|
public boolean contains(Object o) {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
return list.contains(o);
|
return list.contains(o);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<T> asList() {
|
public ArrayList<T> asList() {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
return list;
|
return list;
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package it.cavallium.strangedb.java.objects.lists;
|
package it.cavallium.strangedb.java.objects.lists;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.functionalinterfaces.ConsumerWithIO;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
interface ElementsList<T> {
|
interface ElementsList<T> {
|
||||||
T get(int index) throws IOException;
|
T get(int index) throws IOException;
|
||||||
|
void forEachParallelUnsorted(ConsumerWithIO<T> action) throws IOException;
|
||||||
void add(T value) throws IOException;
|
void add(T value) throws IOException;
|
||||||
void update(int index, T value) throws IOException;
|
void update(int index, T value) throws IOException;
|
||||||
void set(int index, T value) throws IOException;
|
void set(int index, T value) throws IOException;
|
||||||
|
@ -15,9 +15,6 @@ public class EnhancedObjectStrangeDbList<T extends EnhancedObject> extends Stran
|
|||||||
@DbField(id = 0, type = DbDataType.REFERENCES_LIST)
|
@DbField(id = 0, type = DbDataType.REFERENCES_LIST)
|
||||||
private LongArrayList indices;
|
private LongArrayList indices;
|
||||||
|
|
||||||
@DbField(id = 1, type = DbDataType.OBJECT)
|
|
||||||
private Class<T> type;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected LongArrayList getIndices() {
|
protected LongArrayList getIndices() {
|
||||||
return indices;
|
return indices;
|
||||||
@ -27,9 +24,13 @@ public class EnhancedObjectStrangeDbList<T extends EnhancedObject> extends Stran
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public EnhancedObjectStrangeDbList(IDatabaseTools databaseTools, Class<T> type) throws IOException {
|
public EnhancedObjectStrangeDbList(IDatabaseTools databaseTools, Class<T> type) throws IOException {
|
||||||
|
this(databaseTools);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnhancedObjectStrangeDbList(IDatabaseTools databaseTools) throws IOException {
|
||||||
super(databaseTools);
|
super(databaseTools);
|
||||||
this.type = type;
|
|
||||||
indices = new LongArrayList();
|
indices = new LongArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,10 +52,7 @@ public class EnhancedObjectStrangeDbList<T extends EnhancedObject> extends Stran
|
|||||||
public ElementsArrayList<T> query(ListQuery query) throws IOException {
|
public ElementsArrayList<T> query(ListQuery query) throws IOException {
|
||||||
ElementsArrayList<EnhancedObjectIndices> uids = queryUids(query);
|
ElementsArrayList<EnhancedObjectIndices> uids = queryUids(query);
|
||||||
ElementsArrayList<T> elements = new ElementsArrayList<>(uids.size());
|
ElementsArrayList<T> elements = new ElementsArrayList<>(uids.size());
|
||||||
for (int i = 0; i < uids.size(); i++) {
|
uids.forEachParallelUnsorted((uid) -> elements.add(databaseTools.getObjectsIO().loadEnhancedObject(uid.objectUid)));
|
||||||
T element = databaseTools.getObjectsIO().loadEnhancedObject(uids.get(i).objectUid);
|
|
||||||
elements.add(element);
|
|
||||||
}
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +94,12 @@ public class EnhancedObjectStrangeDbList<T extends EnhancedObject> extends Stran
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is slow
|
||||||
|
* @param elementsList
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static ElementsArrayList<Long> toElementsArrayList(ElementsList<?> elementsList) {
|
static ElementsArrayList<Long> toElementsArrayList(ElementsList<?> elementsList) {
|
||||||
if (elementsList instanceof EnhancedObjectStrangeDbList<?>) {
|
if (elementsList instanceof EnhancedObjectStrangeDbList<?>) {
|
||||||
@ -112,10 +116,7 @@ public class EnhancedObjectStrangeDbList<T extends EnhancedObject> extends Stran
|
|||||||
ElementsArrayList<EnhancedObjectIndices> results = new ElementsArrayList<>();
|
ElementsArrayList<EnhancedObjectIndices> results = new ElementsArrayList<>();
|
||||||
if (inputList instanceof EnhancedObjectStrangeDbList<?>) {
|
if (inputList instanceof EnhancedObjectStrangeDbList<?>) {
|
||||||
EnhancedObjectStrangeDbList<?> dbList = ((EnhancedObjectStrangeDbList<?>) inputList);
|
EnhancedObjectStrangeDbList<?> dbList = ((EnhancedObjectStrangeDbList<?>) inputList);
|
||||||
final int listSize = inputList.size();
|
dbList.forEachIndexParallelUnsorted((Long elementUid) -> {
|
||||||
final LongArrayList indices = dbList.getIndices();
|
|
||||||
for (int i = 0; i < listSize; i++) {
|
|
||||||
Long elementUid = indices.get(i);
|
|
||||||
EnhancedObjectIndices elementUids = dbio.loadEnhancedObjectUids(elementUid); // check if the parent object is the declared type
|
EnhancedObjectIndices elementUids = dbio.loadEnhancedObjectUids(elementUid); // check if the parent object is the declared type
|
||||||
Class<?> declaredRootType = query.valuePointer.getRootType();
|
Class<?> declaredRootType = query.valuePointer.getRootType();
|
||||||
Class<?> obtainedRootType = elementUids.type;
|
Class<?> obtainedRootType = elementUids.type;
|
||||||
@ -128,22 +129,20 @@ public class EnhancedObjectStrangeDbList<T extends EnhancedObject> extends Stran
|
|||||||
//todo: use logging api
|
//todo: use logging api
|
||||||
System.err.println(obtainedRootType.getSimpleName() + " is not instance of " + declaredRootType.getSimpleName());
|
System.err.println(obtainedRootType.getSimpleName() + " is not instance of " + declaredRootType.getSimpleName());
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
} else if (inputList instanceof ElementsArrayList<?>) {
|
} else if (inputList instanceof ElementsArrayList<?>) {
|
||||||
final int listSize = inputList.size();
|
|
||||||
ElementsArrayList<EnhancedObjectIndices> elementsUids = ((ElementsArrayList<EnhancedObjectIndices>) inputList);
|
ElementsArrayList<EnhancedObjectIndices> elementsUids = ((ElementsArrayList<EnhancedObjectIndices>) inputList);
|
||||||
for (int i = 0; i < listSize; i++) {
|
elementsUids.forEachParallelUnsorted((elementUid) -> {
|
||||||
EnhancedObjectIndices elementUid = elementsUids.get(i);
|
|
||||||
Object result = resolveItemFromDb(query.valuePointer, dbio, elementUid);
|
Object result = resolveItemFromDb(query.valuePointer, dbio, elementUid);
|
||||||
if (query.valueOperation.evaluate(result)) {
|
if (query.valueOperation.evaluate(result)) {
|
||||||
results.add(elementUid);
|
results.add(elementUid);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object resolveItemFromDb(ValuePointer pointer, IObjectsIO objectsIO, EnhancedObjectIndices element) throws IOException {
|
private static Object resolveItemFromDb(ValuePointer pointer, IObjectsIO objectsIO, EnhancedObjectIndices element) throws IOException {
|
||||||
EnhancedObjectIndices currentElement = element;
|
EnhancedObjectIndices currentElement = element;
|
||||||
boolean isLastElement;
|
boolean isLastElement;
|
||||||
for (int i = 0; i < pointer.size(); i++) {
|
for (int i = 0; i < pointer.size(); i++) {
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
package it.cavallium.strangedb.java.objects.lists;
|
package it.cavallium.strangedb.java.objects.lists;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.VariableWrapper;
|
||||||
|
import it.cavallium.strangedb.functionalinterfaces.ConsumerWithIO;
|
||||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
||||||
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
||||||
|
|
||||||
|
import java.io.IOError;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public abstract class StrangeDbList<T> extends EnhancedObject implements ElementsList<T> {
|
public abstract class StrangeDbList<T> extends EnhancedObject implements ElementsList<T> {
|
||||||
|
|
||||||
private final Object indicesAccessLock = new Object();
|
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(false);
|
||||||
|
|
||||||
protected abstract LongArrayList getIndices();
|
protected abstract LongArrayList getIndices();
|
||||||
|
|
||||||
@ -23,18 +29,104 @@ public abstract class StrangeDbList<T> extends EnhancedObject implements Element
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get(int index) throws IOException {
|
public T get(int index) throws IOException {
|
||||||
synchronized (indicesAccessLock) {
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
long uid = getIndices().getLong(index);
|
long uid = getIndices().getLong(index);
|
||||||
return loadItem(uid);
|
return loadItem(uid);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(T value) throws IOException {
|
public void add(T value) throws IOException {
|
||||||
long uid = databaseTools.getObjectsIO().newNullObject();
|
long uid = databaseTools.getObjectsIO().newNullObject();
|
||||||
synchronized (indicesAccessLock) {
|
readWriteLock.writeLock().lock();
|
||||||
|
try {
|
||||||
getIndices().add(uid);
|
getIndices().add(uid);
|
||||||
writeItemToDisk(uid, value);
|
writeItemToDisk(uid, value);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachParallelUnsorted(ConsumerWithIO<T> action) throws IOException {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
forEachParallelUnsorted_(action);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void forEachParallelUnsorted_(ConsumerWithIO<T> action) throws IOException {
|
||||||
|
try {
|
||||||
|
int size = size();
|
||||||
|
ExecutorService executorService = Executors.newFixedThreadPool(16, (r) -> new Thread(r, "StrangeDbList.forEachParallelUnsorted worker"));
|
||||||
|
VariableWrapper<IOException> exceptionVariableWrapper = new VariableWrapper<>(null);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final int index = i;
|
||||||
|
executorService.execute(() -> {
|
||||||
|
try {
|
||||||
|
T t = get(index);
|
||||||
|
action.accept(t);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (exceptionVariableWrapper.var == null) exceptionVariableWrapper.var = e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
executorService.shutdown();
|
||||||
|
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
|
||||||
|
if (exceptionVariableWrapper.var != null) {
|
||||||
|
throw exceptionVariableWrapper.var;
|
||||||
|
}
|
||||||
|
executorService.shutdownNow();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
} catch (CompletionException e) {
|
||||||
|
throw new IOException(e.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forEachIndexParallelUnsorted(ConsumerWithIO<Long> action) throws IOException {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
forEachIndexParallelUnsorted_(action);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void forEachIndexParallelUnsorted_(ConsumerWithIO<Long> action) throws IOException {
|
||||||
|
try {
|
||||||
|
this.getIndices().parallelStream().forEach((id) -> {
|
||||||
|
try {
|
||||||
|
action.accept(id);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CompletionException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (CompletionException ex) {
|
||||||
|
throw new IOException(ex.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forEach(ConsumerWithIO<T> action) throws IOException {
|
||||||
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
forEach_(action);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void forEach_(ConsumerWithIO<T> action) throws IOException {
|
||||||
|
int size = size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
final int index = i;
|
||||||
|
T value = get(index);
|
||||||
|
action.accept(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,40 +138,55 @@ public abstract class StrangeDbList<T> extends EnhancedObject implements Element
|
|||||||
@Override
|
@Override
|
||||||
public void set(int index, T value) throws IOException {
|
public void set(int index, T value) throws IOException {
|
||||||
long uid = databaseTools.getObjectsIO().newNullObject();
|
long uid = databaseTools.getObjectsIO().newNullObject();
|
||||||
synchronized (indicesAccessLock) {
|
readWriteLock.writeLock().lock();
|
||||||
|
try {
|
||||||
getIndices().set(index, uid);
|
getIndices().set(index, uid);
|
||||||
writeItemToDisk(uid, value);
|
writeItemToDisk(uid, value);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void add(int index, T value) throws IOException {
|
public void add(int index, T value) throws IOException {
|
||||||
long uid = databaseTools.getObjectsIO().newNullObject();
|
long uid = databaseTools.getObjectsIO().newNullObject();
|
||||||
synchronized (indicesAccessLock) {
|
readWriteLock.writeLock().lock();
|
||||||
|
try {
|
||||||
getIndices().add(index, uid);
|
getIndices().add(index, uid);
|
||||||
writeItemToDisk(uid, value);
|
writeItemToDisk(uid, value);
|
||||||
|
} finally {
|
||||||
|
readWriteLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getLast() throws IOException {
|
public T getLast() throws IOException {
|
||||||
synchronized (indicesAccessLock) {
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
if (getIndices().size() > 0) {
|
if (getIndices().size() > 0) {
|
||||||
return get(getIndices().size() - 1);
|
return get(getIndices().size() - 1);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
synchronized (indicesAccessLock) {
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
return getIndices().size() <= 0;
|
return getIndices().size() <= 0;
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
synchronized (indicesAccessLock) {
|
readWriteLock.readLock().lock();
|
||||||
|
try {
|
||||||
return getIndices().size();
|
return getIndices().size();
|
||||||
|
} finally {
|
||||||
|
readWriteLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ public class EnhancedClassUpdate {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldUpdateClass() throws IOException {
|
public void shouldUpdateClass() throws IOException {
|
||||||
db = new DatabaseJava(path1, path2, path3);
|
db = new DatabaseJava(path1, path2, path3);
|
||||||
V2Class root = db.loadRoot(V2Class::new);
|
V2Class root = db.loadRoot(V2Class::new, V2Class.class);
|
||||||
assertEquals(root.field4, "Abc");
|
assertEquals(root.field4, "Abc");
|
||||||
assertEquals(root.field2, 12);
|
assertEquals(root.field2, 12);
|
||||||
assertEquals(root.field1, 13L);
|
assertEquals(root.field1, 13L);
|
||||||
|
@ -4,17 +4,24 @@ import it.cavallium.strangedb.functionalinterfaces.RunnableWithIO;
|
|||||||
import it.cavallium.strangedb.java.annotations.*;
|
import it.cavallium.strangedb.java.annotations.*;
|
||||||
import it.cavallium.strangedb.java.database.DatabaseJava;
|
import it.cavallium.strangedb.java.database.DatabaseJava;
|
||||||
import it.cavallium.strangedb.java.objects.lists.EnhancedObjectStrangeDbList;
|
import it.cavallium.strangedb.java.objects.lists.EnhancedObjectStrangeDbList;
|
||||||
|
import it.cavallium.strangedb.java.objects.lists.ListQuery;
|
||||||
import it.cavallium.strangedb.java.objects.lists.ObjectStrangeDbList;
|
import it.cavallium.strangedb.java.objects.lists.ObjectStrangeDbList;
|
||||||
|
import it.cavallium.strangedb.java.objects.lists.ValuePointer;
|
||||||
|
import it.cavallium.strangedb.java.objects.lists.operations.ContainsIgnoreCase;
|
||||||
|
import it.cavallium.strangedb.tests.query.*;
|
||||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
||||||
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
||||||
import it.cavallium.strangedb.VariableWrapper;
|
import it.cavallium.strangedb.VariableWrapper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public class Performance {
|
public class Performance {
|
||||||
private static boolean FAST_TESTS;
|
private static boolean FAST_TESTS;
|
||||||
@ -24,6 +31,7 @@ public class Performance {
|
|||||||
private static Path dbBlocksFile;
|
private static Path dbBlocksFile;
|
||||||
private static Path dbReferencesFile;
|
private static Path dbReferencesFile;
|
||||||
private static DatabaseJava db;
|
private static DatabaseJava db;
|
||||||
|
private static boolean tempDirectory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -40,18 +48,21 @@ public class Performance {
|
|||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
tempDirectory = false;
|
||||||
} else {
|
} else {
|
||||||
rootDirectory = Files.createTempDirectory("performance-tests");
|
rootDirectory = Files.createTempDirectory("performance-tests");
|
||||||
|
tempDirectory = true;
|
||||||
}
|
}
|
||||||
generateDb();
|
generateDb();
|
||||||
System.out.println("Performance test started.");
|
System.out.println("Performance test started.");
|
||||||
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
|
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
|
||||||
System.out.println("Test name Total Time | Time at 1 Time at 10 Time at 100 Time at 1K Time at 10K");
|
System.out.println("Test name Total Time | Time at 1 Time at 10 Time at 100 Time at 1K Time at 10K");
|
||||||
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
|
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
|
||||||
testS("DatabaseCore creation", 3000, Performance::deleteDb, Performance::generateDb, () -> {});
|
testS("DatabaseCore creation", 300, Performance::deleteDb, Performance::generateDb, () -> {});
|
||||||
testS("DatabaseCore root creation", 3000, Performance::regenDb, () -> db.loadRoot(PreloadedListContainer::new), () -> {});
|
testS("DatabaseCore root creation", 300, Performance::regenDb, () -> db.loadRoot(PreloadedListContainer::new), () -> {});
|
||||||
final VariableWrapper<PreloadedListContainer> preloadedListContainer = new VariableWrapper<>(null);
|
final VariableWrapper<PreloadedListContainer> preloadedListContainer = new VariableWrapper<>(null);
|
||||||
final VariableWrapper<SimpleEnhancedObject> simpleEnhancedObjectContainer = new VariableWrapper<>(null);
|
final VariableWrapper<SimpleEnhancedObject> simpleEnhancedObjectContainer = new VariableWrapper<>(null);
|
||||||
|
/*
|
||||||
testS("ObjectStrangeDbList<Int> creation", 3000, () -> {
|
testS("ObjectStrangeDbList<Int> creation", 3000, () -> {
|
||||||
regenDb();
|
regenDb();
|
||||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
|
preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
|
||||||
@ -107,9 +118,7 @@ public class Performance {
|
|||||||
preloadedListContainer.var.list.add(1000);
|
preloadedListContainer.var.list.add(1000);
|
||||||
}
|
}
|
||||||
}, () -> {
|
}, () -> {
|
||||||
for (int i = 0; i < 1000; i++) {
|
preloadedListContainer.var.list.forEachParallelUnsorted((i) -> {});
|
||||||
preloadedListContainer.var.list.get(i);
|
|
||||||
}
|
|
||||||
}, () -> {});
|
}, () -> {});
|
||||||
testS("ObjectStrangeDbList<EnhancedObject>: Loading with 1000 items", 100, () -> {
|
testS("ObjectStrangeDbList<EnhancedObject>: Loading with 1000 items", 100, () -> {
|
||||||
regenDb();
|
regenDb();
|
||||||
@ -126,9 +135,7 @@ public class Performance {
|
|||||||
preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var);
|
preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var);
|
||||||
}
|
}
|
||||||
}, () -> {
|
}, () -> {
|
||||||
for (int i = 0; i < 1000; i++) {
|
preloadedListContainer.var.listOfEnhancedObj.forEachParallelUnsorted((i) -> {});
|
||||||
preloadedListContainer.var.listOfEnhancedObj.get(i);
|
|
||||||
}
|
|
||||||
}, () -> {});
|
}, () -> {});
|
||||||
testS("ObjectStrangeDbList<Int>: Loading 10000 items", 10, () -> {
|
testS("ObjectStrangeDbList<Int>: Loading 10000 items", 10, () -> {
|
||||||
regenDb();
|
regenDb();
|
||||||
@ -138,9 +145,7 @@ public class Performance {
|
|||||||
preloadedListContainer.var.list.add(1000);
|
preloadedListContainer.var.list.add(1000);
|
||||||
}
|
}
|
||||||
}, () -> {
|
}, () -> {
|
||||||
for (int i = 0; i < 10000; i++) {
|
preloadedListContainer.var.list.forEachParallelUnsorted((i) -> {});
|
||||||
preloadedListContainer.var.list.get(i);
|
|
||||||
}
|
|
||||||
}, () -> {});
|
}, () -> {});
|
||||||
testS("ObjectStrangeDbList<Int>: getLast() with 1000 items", 100, () -> {
|
testS("ObjectStrangeDbList<Int>: getLast() with 1000 items", 100, () -> {
|
||||||
regenDb();
|
regenDb();
|
||||||
@ -179,11 +184,45 @@ public class Performance {
|
|||||||
}, () -> {
|
}, () -> {
|
||||||
preloadedListContainer.var.list.size();
|
preloadedListContainer.var.list.size();
|
||||||
}, () -> {});
|
}, () -> {});
|
||||||
|
*/
|
||||||
|
for (int items = 1000; items <= 100000; items *= 10) {
|
||||||
|
final int itemsF = items;
|
||||||
|
testS("ListQuery: query with " + items + " items", 100 / (items / 1000), () -> {
|
||||||
|
regenDb();
|
||||||
|
preloadedListContainer.var = db.loadRoot(PreloadedListContainer::new);
|
||||||
|
preloadedListContainer.var.listOfMessages = new EnhancedObjectStrangeDbList<>(db);
|
||||||
|
|
||||||
|
Random random = new Random();
|
||||||
|
for (int i = 0; i < itemsF; i++) {
|
||||||
|
EMessageContent content;
|
||||||
|
if (random.nextBoolean()) {
|
||||||
|
List<String> stringList = new ArrayList<>();
|
||||||
|
for (int j = 0; j < 10; j++) {
|
||||||
|
stringList.add("[entity]");
|
||||||
|
}
|
||||||
|
byte[] stringBytes = new byte[200];
|
||||||
|
random.nextBytes(stringBytes);
|
||||||
|
content = new EMessageText(db, new EFormattedText(db, new String(stringBytes, StandardCharsets.UTF_8) + (random.nextBoolean() ? "not found" : " text to find!"), stringList.toArray(new String[0])));
|
||||||
|
} else {
|
||||||
|
content = new EMessageOtherContent(db, "EMPTY ABCDEFG");
|
||||||
|
}
|
||||||
|
EMessage message = new EMessage(db, content);
|
||||||
|
preloadedListContainer.var.listOfMessages.add(message);
|
||||||
|
}
|
||||||
|
}, () -> {
|
||||||
|
ListQuery query = ListQuery.create(
|
||||||
|
ValuePointer.ofField(EMessage.class, "content").field(EMessageText.class, "text").field(EFormattedText.class, "text"),
|
||||||
|
ContainsIgnoreCase.containsValue("text to find"));
|
||||||
|
ArrayList<EMessage> results = preloadedListContainer.var.listOfMessages.query(query).asList();
|
||||||
|
}, () -> {});
|
||||||
|
}
|
||||||
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
|
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
|
||||||
System.out.println("Performance test finished.");
|
System.out.println("Performance test finished.");
|
||||||
deleteDb();
|
deleteDb();
|
||||||
|
if (tempDirectory) {
|
||||||
Files.deleteIfExists(rootDirectory);
|
Files.deleteIfExists(rootDirectory);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void NtestS(String description, int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException {
|
private static void NtestS(String description, int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException {
|
||||||
}
|
}
|
||||||
@ -272,6 +311,15 @@ public class Performance {
|
|||||||
Files.createFile(dbBlocksFile);
|
Files.createFile(dbBlocksFile);
|
||||||
Files.createFile(dbReferencesFile);
|
Files.createFile(dbReferencesFile);
|
||||||
db = new DatabaseJava(dbDataFile, dbBlocksFile, dbReferencesFile);
|
db = new DatabaseJava(dbDataFile, dbBlocksFile, dbReferencesFile);
|
||||||
|
int i = 0;
|
||||||
|
db.getObjectsIO().registerClass(SimpleEnhancedObject.class, i++);
|
||||||
|
db.getObjectsIO().registerClass(PreloadedListContainer.class, i++);
|
||||||
|
db.getObjectsIO().registerClass(DynamicListContainer.class, i++);
|
||||||
|
db.getObjectsIO().registerClass(EMessage.class, i++);
|
||||||
|
db.getObjectsIO().registerClass(EMessageContent.class, i++);
|
||||||
|
db.getObjectsIO().registerClass(EMessageText.class, i++);
|
||||||
|
db.getObjectsIO().registerClass(EMessageOtherContent.class, i++);
|
||||||
|
db.getObjectsIO().registerClass(EFormattedText.class, i++);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteDb() throws IOException {
|
public static void deleteDb() throws IOException {
|
||||||
@ -298,6 +346,9 @@ public class Performance {
|
|||||||
@DbField(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
@DbField(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||||
public EnhancedObjectStrangeDbList<SimpleEnhancedObject> listOfEnhancedObj;
|
public EnhancedObjectStrangeDbList<SimpleEnhancedObject> listOfEnhancedObj;
|
||||||
|
|
||||||
|
@DbField(id = 2, type = DbDataType.ENHANCED_OBJECT)
|
||||||
|
public EnhancedObjectStrangeDbList<EMessage> listOfMessages;
|
||||||
|
|
||||||
public PreloadedListContainer() {
|
public PreloadedListContainer() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package it.cavallium.strangedb.tests.query;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbDataType;
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbField;
|
||||||
|
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EFormattedText extends EMessageContent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text.
|
||||||
|
*/
|
||||||
|
@DbField(id = 0, type = DbDataType.OBJECT, name = "text")
|
||||||
|
public String text;
|
||||||
|
/**
|
||||||
|
* Entities contained in the text.
|
||||||
|
*/
|
||||||
|
@DbField(id = 1, type = DbDataType.OBJECT, name = "entities")
|
||||||
|
public String[] entities;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public EFormattedText() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EFormattedText(IDatabaseTools tools, String text, String[] entities) throws IOException {
|
||||||
|
super(tools);
|
||||||
|
this.text = text;
|
||||||
|
this.entities =entities;
|
||||||
|
}
|
||||||
|
}
|
138
src/test/java/it/cavallium/strangedb/tests/query/EMessage.java
Normal file
138
src/test/java/it/cavallium/strangedb/tests/query/EMessage.java
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
package it.cavallium.strangedb.tests.query;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbDataType;
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbField;
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbPrimitiveField;
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbPrimitiveType;
|
||||||
|
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
||||||
|
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EMessage extends EnhancedObject {
|
||||||
|
/**
|
||||||
|
* Message identifier, unique for the chat to which the message belongs.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 0, type = DbPrimitiveType.LONG, name = "id")
|
||||||
|
public long id;
|
||||||
|
/**
|
||||||
|
* Identifier of the user who sent the message; 0 if unknown. It is unknown for channel posts.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 1, type = DbPrimitiveType.INTEGER, name = "senderUserId")
|
||||||
|
public int senderUserId;
|
||||||
|
/**
|
||||||
|
* Chat identifier.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 2, type = DbPrimitiveType.LONG, name = "chatId")
|
||||||
|
public long chatId;
|
||||||
|
/**
|
||||||
|
* Information about the sending state of the message; may be null.
|
||||||
|
*/
|
||||||
|
@DbField(id = 0, type = DbDataType.OBJECT, name = "sendingState")
|
||||||
|
public Object sendingState;
|
||||||
|
/**
|
||||||
|
* True, if the message is outgoing.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 3, type = DbPrimitiveType.BOOLEAN, name = "isOutgoing")
|
||||||
|
public boolean isOutgoing;
|
||||||
|
/**
|
||||||
|
* True, if the message can be edited.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 4, type = DbPrimitiveType.BOOLEAN, name = "canBeEdited")
|
||||||
|
public boolean canBeEdited;
|
||||||
|
/**
|
||||||
|
* True, if the message can be forwarded.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 5, type = DbPrimitiveType.BOOLEAN, name = "canBeForwarded")
|
||||||
|
public boolean canBeForwarded;
|
||||||
|
/**
|
||||||
|
* True, if the message can be deleted only for the current user while other users will continue to see it.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 6, type = DbPrimitiveType.BOOLEAN, name = "canBeDeletedOnlyForSelf")
|
||||||
|
public boolean canBeDeletedOnlyForSelf;
|
||||||
|
/**
|
||||||
|
* True, if the message can be deleted for all users.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 7, type = DbPrimitiveType.BOOLEAN, name = "canBeDeletedForAllUsers")
|
||||||
|
public boolean canBeDeletedForAllUsers;
|
||||||
|
/**
|
||||||
|
* True, if the message is a channel post. All messages to channels are channel posts, all other messages are not channel posts.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 8, type = DbPrimitiveType.BOOLEAN, name = "isChannelPost")
|
||||||
|
public boolean isChannelPost;
|
||||||
|
/**
|
||||||
|
* True, if the message contains an unread mention for the current user.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 9, type = DbPrimitiveType.BOOLEAN, name = "containsUnreadMention")
|
||||||
|
public boolean containsUnreadMention;
|
||||||
|
/**
|
||||||
|
* Point in time (Unix timestamp) when the message was sent.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 10, type = DbPrimitiveType.INTEGER, name = "date")
|
||||||
|
public int date;
|
||||||
|
/**
|
||||||
|
* Point in time (Unix timestamp) when the message was last edited.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 11, type = DbPrimitiveType.INTEGER, name = "editDate")
|
||||||
|
public int editDate;
|
||||||
|
/**
|
||||||
|
* Information about the initial message sender; may be null.
|
||||||
|
*/
|
||||||
|
@DbField(id = 1, type = DbDataType.OBJECT, name = "forwardInfo")
|
||||||
|
public Object forwardInfo;
|
||||||
|
/**
|
||||||
|
* If non-zero, the identifier of the message this message is replying to; can be the identifier of a deleted message.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 12, type = DbPrimitiveType.LONG, name = "replyToMessageId")
|
||||||
|
public long replyToMessageId;
|
||||||
|
/**
|
||||||
|
* For self-destructing messages, the message's TTL (Time To Live), in seconds; 0 if none. TDLib will send updateDeleteMessages or updateMessageContent once the TTL expires.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 13, type = DbPrimitiveType.INTEGER, name = "ttl")
|
||||||
|
public int ttl;
|
||||||
|
/**
|
||||||
|
* Time left before the message expires, in seconds.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 14, type = DbPrimitiveType.DOUBLE, name = "ttlExpiresIn")
|
||||||
|
public double ttlExpiresIn;
|
||||||
|
/**
|
||||||
|
* If non-zero, the user identifier of the bot through which this message was sent.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 15, type = DbPrimitiveType.INTEGER, name = "viaBotUserId")
|
||||||
|
public int viaBotUserId;
|
||||||
|
/**
|
||||||
|
* For channel posts, optional author signature.
|
||||||
|
*/
|
||||||
|
@DbField(id = 2, type = DbDataType.OBJECT, name = "authorSignature")
|
||||||
|
public String authorSignature;
|
||||||
|
/**
|
||||||
|
* Number of times this message was viewed.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 16, type = DbPrimitiveType.INTEGER, name = "views")
|
||||||
|
public int views;
|
||||||
|
/**
|
||||||
|
* Unique identifier of an album this message belongs to. Only photos and videos can be grouped together in albums.
|
||||||
|
*/
|
||||||
|
@DbPrimitiveField(id = 17, type = DbPrimitiveType.LONG, name = "mediaAlbumId")
|
||||||
|
public long mediaAlbumId;
|
||||||
|
/**
|
||||||
|
* Content of the message.
|
||||||
|
*/
|
||||||
|
@DbField(id = 3, type = DbDataType.ENHANCED_OBJECT, name = "content")
|
||||||
|
public EMessageContent content;
|
||||||
|
/**
|
||||||
|
* Reply markup for the message; may be null.
|
||||||
|
*/
|
||||||
|
@DbField(id = 4, type = DbDataType.OBJECT, name = "replyMarkup")
|
||||||
|
public Object replyMarkup;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public EMessage() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EMessage(IDatabaseTools tools, EMessageContent content) throws IOException {
|
||||||
|
super(tools);
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package it.cavallium.strangedb.tests.query;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
||||||
|
import it.cavallium.strangedb.java.objects.EnhancedObject;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public abstract class EMessageContent extends EnhancedObject {
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public EMessageContent() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EMessageContent(IDatabaseTools tools) throws IOException {
|
||||||
|
super(tools);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package it.cavallium.strangedb.tests.query;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbDataType;
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbField;
|
||||||
|
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EMessageOtherContent extends EMessageContent {
|
||||||
|
|
||||||
|
@DbField(id = 0, type = DbDataType.OBJECT, name = "content")
|
||||||
|
public Object content;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public EMessageOtherContent() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EMessageOtherContent(IDatabaseTools tools, Object content) throws IOException {
|
||||||
|
super(tools);
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package it.cavallium.strangedb.tests.query;
|
||||||
|
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbDataType;
|
||||||
|
import it.cavallium.strangedb.java.annotations.DbField;
|
||||||
|
import it.cavallium.strangedb.java.database.IDatabaseTools;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EMessageText extends EMessageContent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text of the message.
|
||||||
|
*/
|
||||||
|
@DbField(id = 0, type = DbDataType.ENHANCED_OBJECT, name = "text")
|
||||||
|
public EFormattedText text;
|
||||||
|
/**
|
||||||
|
* A preview of the web page that's mentioned in the text; may be null.
|
||||||
|
*/
|
||||||
|
@DbField(id = 1, type = DbDataType.OBJECT, name = "webPage")
|
||||||
|
public Object webPage;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public EMessageText() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public EMessageText(IDatabaseTools tools, EFormattedText text) throws IOException {
|
||||||
|
super(tools);
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}
|
@ -233,7 +233,7 @@ public class NTestUtils {
|
|||||||
@DbField(id = 0, type = DbDataType.OBJECT)
|
@DbField(id = 0, type = DbDataType.OBJECT)
|
||||||
public String field7;
|
public String field7;
|
||||||
|
|
||||||
@DbField(id = 1, type = DbDataType.REFERENCES_LIST)
|
@DbField(id = 1, type = DbDataType.OBJECT)
|
||||||
public LongArrayList field8;
|
public LongArrayList field8;
|
||||||
|
|
||||||
@DbField(id = 2, type = DbDataType.ENHANCED_OBJECT)
|
@DbField(id = 2, type = DbDataType.ENHANCED_OBJECT)
|
||||||
@ -253,7 +253,7 @@ public class NTestUtils {
|
|||||||
return getProperty();
|
return getProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@DbProperty(id = 1, type = DbDataType.REFERENCES_LIST)
|
@DbProperty(id = 1, type = DbDataType.OBJECT)
|
||||||
@DbPropertyGetter
|
@DbPropertyGetter
|
||||||
public LongArrayList get8() {
|
public LongArrayList get8() {
|
||||||
return getProperty();
|
return getProperty();
|
||||||
@ -271,7 +271,7 @@ public class NTestUtils {
|
|||||||
setProperty(val);
|
setProperty(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DbProperty(id = 1, type = DbDataType.REFERENCES_LIST)
|
@DbProperty(id = 1, type = DbDataType.OBJECT)
|
||||||
@DbPropertySetter
|
@DbPropertySetter
|
||||||
public void set8(LongArrayList val) {
|
public void set8(LongArrayList val) {
|
||||||
setProperty(val);
|
setProperty(val);
|
||||||
|
Loading…
Reference in New Issue
Block a user