Server 1.0.0
This commit is contained in:
parent
877a40df1b
commit
1def19d219
0
database.blocks.dat
Normal file
0
database.blocks.dat
Normal file
BIN
database.db
Normal file
BIN
database.db
Normal file
Binary file not shown.
0
database.references.dat
Normal file
0
database.references.dat
Normal file
0
database.structure.dat
Normal file
0
database.structure.dat
Normal file
21
database.structure.txt
Normal file
21
database.structure.txt
Normal file
@ -0,0 +1,21 @@
|
||||
types:
|
||||
- name: Long2IntMap
|
||||
model: map: [LONG, INTEGER]
|
||||
definitions:
|
||||
- name: ChatLog
|
||||
version: 0
|
||||
fields:
|
||||
- name: chatId
|
||||
type: LONG
|
||||
- name: messageIds
|
||||
type: Long2IntMap
|
||||
preloaded: true
|
||||
- name: messages
|
||||
type: ARRAY
|
||||
preloaded: true
|
||||
- name: chatDetailsHistory
|
||||
type: ChatSnapshotList
|
||||
preloaded: true
|
||||
- name: MessageList
|
||||
fields:
|
||||
- name: message
|
18
pom.xml
18
pom.xml
@ -8,7 +8,7 @@
|
||||
<artifactId>strangedb-server</artifactId>
|
||||
<version>1.5.4</version>
|
||||
|
||||
<name>strangedb</name>
|
||||
<name>strangedb-server</name>
|
||||
<url>https://git.ignuranza.net/andreacavalli/strangedb</url>
|
||||
|
||||
<properties>
|
||||
@ -49,8 +49,8 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.cavallium</groupId>
|
||||
<artifactId>strangedb</artifactId>
|
||||
<version>1.5.4</version>
|
||||
<artifactId>strangedb-core</artifactId>
|
||||
<version>1.5.5</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
|
||||
<dependency>
|
||||
@ -64,6 +64,18 @@
|
||||
<version>RELEASE</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20170516</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>27.0-jre</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
52
src/main/java/it/cavallium/strangedb/server/ArrayNode.java
Normal file
52
src/main/java/it/cavallium/strangedb/server/ArrayNode.java
Normal file
@ -0,0 +1,52 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ArrayNode implements Node {
|
||||
|
||||
private final long reference;
|
||||
private long[] items;
|
||||
|
||||
public ArrayNode(long reference, long[] items) {
|
||||
this.reference = reference;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public long[] getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public long getItem(int index) {
|
||||
return items[index];
|
||||
}
|
||||
|
||||
public int countItems() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
public void setItem(int index, long value) {
|
||||
if (index >= items.length) {
|
||||
items = Arrays.copyOf(items, index + 1);
|
||||
}
|
||||
items[index] = value;
|
||||
}
|
||||
|
||||
public boolean hasItem(int index) {
|
||||
return index >= 0 && index < items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeType getType() {
|
||||
return NodeType.ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node copy() {
|
||||
return new ArrayNode(reference, items.clone());
|
||||
}
|
||||
}
|
89
src/main/java/it/cavallium/strangedb/server/ClassNode.java
Normal file
89
src/main/java/it/cavallium/strangedb/server/ClassNode.java
Normal file
@ -0,0 +1,89 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ClassNode implements Node {
|
||||
|
||||
private final long reference;
|
||||
private NodeProperty[] properties;
|
||||
|
||||
public ClassNode(long reference, NodeProperty[] properties) {
|
||||
this.reference = reference;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public NodeProperty[] getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public long getProperty(byte[] propertyName) {
|
||||
int propertyIndex = getPropertyIndex(propertyName);
|
||||
if (propertyIndex == -1) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return properties[propertyIndex].getReference();
|
||||
}
|
||||
|
||||
public boolean hasProperty(byte[] name) {
|
||||
for (int i = 0; i < properties.length; i++) {
|
||||
NodeProperty property = properties[i];
|
||||
if (DatabaseNodesIO.nameEquals(property.getName(), name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public NodeProperty getProperty(int index) {
|
||||
return properties[index];
|
||||
}
|
||||
|
||||
public int countProperties() {
|
||||
return properties.length;
|
||||
}
|
||||
|
||||
|
||||
public void setProperty(byte[] propertyName, long valueReference) {
|
||||
setProperty(new NodeProperty(propertyName, valueReference));
|
||||
}
|
||||
|
||||
public void setProperty(NodeProperty value) {
|
||||
// Find if property exists
|
||||
int propertyToEditIndex = getPropertyIndex(value.getName());
|
||||
|
||||
// Add new property
|
||||
if (propertyToEditIndex < 0) {
|
||||
properties = Arrays.copyOf(properties, properties.length + 1);
|
||||
properties[properties.length - 1] = value;
|
||||
} else {
|
||||
properties[propertyToEditIndex] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int getPropertyIndex(byte[] name) {
|
||||
int propIndex = -1;
|
||||
for (int i = 0; i < properties.length; i++) {
|
||||
NodeProperty property = properties[i];
|
||||
if (DatabaseNodesIO.nameEquals(property.getName(), name)) {
|
||||
propIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return propIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeType getType() {
|
||||
return NodeType.CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node copy() {
|
||||
return new ClassNode(reference, properties.clone());
|
||||
}
|
||||
}
|
452
src/main/java/it/cavallium/strangedb/server/DatabaseNodesIO.java
Normal file
452
src/main/java/it/cavallium/strangedb/server/DatabaseNodesIO.java
Normal file
@ -0,0 +1,452 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import it.cavallium.strangedb.database.IReferencesIO;
|
||||
import it.cavallium.strangedb.database.references.DatabaseReferencesMetadata;
|
||||
import org.json.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import static it.cavallium.strangedb.server.TreePath.stringToNode;
|
||||
|
||||
public class DatabaseNodesIO {
|
||||
private final IReferencesIO referencesIO;
|
||||
private static final int isArrayMask = 0b10000000000000000000000000000000;
|
||||
private static final int isValueMask = 0b01000000000000000000000000000000;
|
||||
private static final int isNumberMask = 0b11000000000000000000000000000000;
|
||||
private static final int nodeCountMask = 0b01111111111111111111111111111111;
|
||||
private static final int arrayCountMask = 0b01111111111111111111111111111111;
|
||||
|
||||
public DatabaseNodesIO(IReferencesIO referencesIO, DatabaseReferencesMetadata referencesMetadata) throws IOException {
|
||||
this.referencesIO = referencesIO;
|
||||
if (referencesMetadata.getFirstFreeReference() == 0) {
|
||||
long ref = this.referencesIO.allocateReference();
|
||||
if (ref != 0) throw new IOException("Root must be 0");
|
||||
ClassNode rootNode = new ClassNode(ref, new NodeProperty[0]);
|
||||
this.setNode(rootNode);
|
||||
}
|
||||
}
|
||||
|
||||
public String get(CharSequence path) throws IOException {
|
||||
return get(TreePath.get(path));
|
||||
}
|
||||
|
||||
public String get(TreePath path) throws IOException {
|
||||
Node foundNode = getNode(path);
|
||||
return toJson(foundNode);
|
||||
}
|
||||
|
||||
private String toJson(Node foundNode) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toJson(sb, foundNode);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void toJson(StringBuilder sb, long nodeReference) throws IOException {
|
||||
toJson(sb, loadNode(nodeReference));
|
||||
}
|
||||
|
||||
private void toJson(StringBuilder sb, Node foundNode) throws IOException {
|
||||
switch (foundNode.getType()) {
|
||||
case ARRAY: {
|
||||
ArrayNode arrayNode = (ArrayNode) foundNode;
|
||||
sb.append('[');
|
||||
for (int i = 0; i < arrayNode.countItems(); i++) {
|
||||
toJson(sb, arrayNode.getItem(i));
|
||||
if (i + 1 < arrayNode.countItems()) {
|
||||
sb.append(',');
|
||||
}
|
||||
}
|
||||
sb.append(']');
|
||||
break;
|
||||
}
|
||||
case CLASS: {
|
||||
ClassNode classNode = (ClassNode) foundNode;
|
||||
sb.append('{');
|
||||
for (int i = 0; i < classNode.countProperties(); i++) {
|
||||
NodeProperty property = classNode.getProperty(i);
|
||||
sb.append(property.getNameAsString());
|
||||
sb.append(':');
|
||||
toJson(sb, property.getReference());
|
||||
if (i + 1 < classNode.countProperties()) {
|
||||
sb.append(',');
|
||||
}
|
||||
}
|
||||
sb.append('}');
|
||||
break;
|
||||
}
|
||||
case VALUE: {
|
||||
ValueNode valueNode = (ValueNode) foundNode;
|
||||
sb.append(org.json.JSONObject.quote(loadValue(valueNode.getValueReference())));
|
||||
break;
|
||||
}
|
||||
case NUMBER: {
|
||||
NumberNode valueNode = (NumberNode) foundNode;
|
||||
sb.append(loadNumber(valueNode.getNumberReference()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setValue(long reference, String value) throws IOException {
|
||||
ByteBuffer valueBytes = StandardCharsets.UTF_8.encode(value);
|
||||
referencesIO.writeToReference(reference, valueBytes.limit(), valueBytes);
|
||||
}
|
||||
|
||||
private String loadValue(long reference) throws IOException {
|
||||
ByteBuffer buffer = referencesIO.readFromReference(reference);
|
||||
return StandardCharsets.UTF_8.decode(buffer).toString();
|
||||
}
|
||||
|
||||
private void setNumber(long reference, double value) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES);
|
||||
buffer.putDouble(value);
|
||||
buffer.flip();
|
||||
referencesIO.writeToReference(reference, buffer.limit(), buffer);
|
||||
}
|
||||
|
||||
private double loadNumber(long reference) throws IOException {
|
||||
ByteBuffer buffer = referencesIO.readFromReference(reference);
|
||||
return buffer.getDouble();
|
||||
}
|
||||
|
||||
public void set(CharSequence path, String value) throws IOException {
|
||||
TreePath treePath = TreePath.get(path);
|
||||
if (treePath.isRoot()) {
|
||||
set(treePath, importNode(value, 0));
|
||||
} else {
|
||||
set(treePath, importNode(value));
|
||||
}
|
||||
}
|
||||
|
||||
public void set(TreePath path, long valueReference) throws IOException {
|
||||
Node node;
|
||||
if (path.isRoot()) {
|
||||
if (valueReference != 0)
|
||||
throw new IOException("Root must be zero");
|
||||
} else {
|
||||
node = getNode(path.getParent());
|
||||
switch (node.getType()) {
|
||||
case ARRAY: {
|
||||
if (!path.isArrayOffset()) {
|
||||
throw new IOException("Required a property inside an array node");
|
||||
}
|
||||
ArrayNode arrayNode = (ArrayNode) node;
|
||||
int index = path.getArrayOffset();
|
||||
arrayNode.setItem(index, valueReference);
|
||||
break;
|
||||
}
|
||||
case CLASS: {
|
||||
if (!path.isNodeProperty())
|
||||
throw new IOException("Required array offset inside a non-array node");
|
||||
ClassNode classNode = (ClassNode) node;
|
||||
byte[] propertyName = path.getNodeValue();
|
||||
classNode.setProperty(propertyName, valueReference);
|
||||
break;
|
||||
}
|
||||
case NUMBER:
|
||||
case VALUE: {
|
||||
throw new IOException("WTF you shouldn't be here!");
|
||||
}
|
||||
}
|
||||
setNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private long importNode(String value) throws IOException {
|
||||
return importNode(value, referencesIO.allocateReference());
|
||||
}
|
||||
|
||||
private long importNode(String value, long reference) throws IOException {
|
||||
switch (value.charAt(0)) {
|
||||
case '[':
|
||||
JSONArray array = new JSONArray(value);
|
||||
return importJsonNode(array, reference);
|
||||
case '{':
|
||||
JSONObject obj = new JSONObject(value);
|
||||
return importJsonNode(obj, reference);
|
||||
case '"':
|
||||
return importJsonNode(value.substring(1, value.length() - 1), reference);
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '.':
|
||||
return importJsonNode(Double.parseDouble(value), reference);
|
||||
default:
|
||||
throw new IOException("Unrecognized input");
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private long importJsonNode(Object o) throws IOException {
|
||||
return importJsonNode(o, referencesIO.allocateReference());
|
||||
}
|
||||
|
||||
private long importJsonNode(Object o, long reference) throws IOException {
|
||||
if (o instanceof ArrayList<?>) {
|
||||
o = new JSONArray((ArrayList<?>) o);
|
||||
}
|
||||
if (o instanceof JSONArray) {
|
||||
JSONArray array = (JSONArray) o;
|
||||
int length = array.length();
|
||||
long[] arrayReferences = new long[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
arrayReferences[i] = importJsonNode(array.get(i));
|
||||
}
|
||||
Node node = createNewArrayNode(arrayReferences, reference);
|
||||
setNode(node);
|
||||
return node.getReference();
|
||||
} else if (o instanceof JSONObject) {
|
||||
JSONObject obj = (JSONObject) o;
|
||||
Map<String, Object> jsonProperties = obj.toMap();
|
||||
NodeProperty[] properties = new NodeProperty[jsonProperties.size()];
|
||||
int i = 0;
|
||||
for (Map.Entry<String, Object> entry : jsonProperties.entrySet()) {
|
||||
NodeProperty nodeProperty = new NodeProperty(stringToNode(entry.getKey()), importJsonNode(entry.getValue()));
|
||||
properties[i] = nodeProperty;
|
||||
}
|
||||
Node node = createNewNodeNode(properties, reference);
|
||||
setNode(node);
|
||||
return node.getReference();
|
||||
} else if (o instanceof String) {
|
||||
Node node = createNewValueNode((String) o, reference);
|
||||
setNode(node);
|
||||
return node.getReference();
|
||||
} else if (o instanceof Double || o instanceof Float || o instanceof Integer || o instanceof Long) {
|
||||
double number;
|
||||
if (o instanceof Integer) {
|
||||
number = (Integer) o;
|
||||
} else if (o instanceof Long) {
|
||||
number = (Long) o;
|
||||
} else if (o instanceof Float) {
|
||||
number = (Float) o;
|
||||
} else if (o instanceof Double) {
|
||||
number = (Double) o;
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
Node node = createNewNumberNode(number+0, reference);
|
||||
setNode(node);
|
||||
return node.getReference();
|
||||
} else {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean exists(CharSequence path) throws IOException {
|
||||
return exists(TreePath.get(path));
|
||||
}
|
||||
|
||||
public boolean exists(TreePath path) throws IOException {
|
||||
TreePathWalker pathWalker = new TreePathWalker(path);
|
||||
Node node = loadNode(0);
|
||||
while (pathWalker.hasNext()) {
|
||||
TreePath nodePath = pathWalker.next();
|
||||
if (nodePath.isArrayOffset()) {
|
||||
if (node.getType() != NodeType.ARRAY) {
|
||||
return false;
|
||||
}
|
||||
int offset = nodePath.getArrayOffset();
|
||||
if (!((ArrayNode)node).hasItem(offset)) {
|
||||
return false;
|
||||
}
|
||||
long nodeReference = ((ArrayNode) node).getItem(offset);
|
||||
node = loadNode(nodeReference);
|
||||
} else if (nodePath.isNodeProperty()) {
|
||||
if (node.getType() == NodeType.ARRAY) {
|
||||
return false;
|
||||
}
|
||||
byte[] propertyName = nodePath.getNodeValue();
|
||||
if (!((ClassNode) node).hasProperty(propertyName)) {
|
||||
return false;
|
||||
}
|
||||
long nodeReference = ((ClassNode) node).getProperty(propertyName);
|
||||
node = loadNode(nodeReference);
|
||||
}
|
||||
}
|
||||
return node != null;
|
||||
}
|
||||
|
||||
private Node getNode(TreePath path) throws IOException {
|
||||
TreePathWalker pathWalker = new TreePathWalker(path);
|
||||
pathWalker.walkToRoot();
|
||||
Node node = loadNode(0);
|
||||
while (pathWalker.hasNext()) {
|
||||
TreePath nodePath = pathWalker.next();
|
||||
if (nodePath.isArrayOffset()) {
|
||||
if (node.getType() != NodeType.ARRAY) {
|
||||
throw new IOException("Required array offset inside a non-array node");
|
||||
}
|
||||
int offset = nodePath.getArrayOffset();
|
||||
long nodeReference = ((ArrayNode) node).getItem(offset);
|
||||
node = loadNode(nodeReference);
|
||||
} else if (nodePath.isNodeProperty()) {
|
||||
if (node.getType() == NodeType.ARRAY) {
|
||||
throw new IOException("Required a property inside an array node");
|
||||
}
|
||||
byte[] propertyName = nodePath.getNodeValue();
|
||||
long nodeReference = ((ClassNode) node).getProperty(propertyName);
|
||||
node = loadNode(nodeReference);
|
||||
}
|
||||
}
|
||||
if (node == null)
|
||||
throw new NullPointerException();
|
||||
return node;
|
||||
}
|
||||
|
||||
private Node createNewArrayNode() throws IOException {
|
||||
long reference = referencesIO.allocateReference();
|
||||
return new ArrayNode(reference, new long[0]);
|
||||
}
|
||||
|
||||
private Node createNewArrayNode(long[] items) throws IOException {
|
||||
return createNewArrayNode(items, referencesIO.allocateReference());
|
||||
}
|
||||
|
||||
private Node createNewArrayNode(long[] items, long reference) throws IOException {
|
||||
return new ArrayNode(reference, items);
|
||||
}
|
||||
|
||||
private Node createNewValueNode() throws IOException {
|
||||
long reference = referencesIO.allocateReference();
|
||||
return new ValueNode(reference, referencesIO.allocateReference());
|
||||
}
|
||||
|
||||
private Node createNewValueNode(String value) throws IOException {
|
||||
return createNewValueNode(value, referencesIO.allocateReference());
|
||||
}
|
||||
|
||||
private Node createNewValueNode(String value, long reference) throws IOException {
|
||||
byte[] string = value.getBytes(StandardCharsets.UTF_8);
|
||||
long dataReference = referencesIO.allocateReference(string.length, ByteBuffer.wrap(string));
|
||||
return new ValueNode(reference, dataReference);
|
||||
}
|
||||
|
||||
private Node createNewNumberNode(double value, long reference) throws IOException {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(Double.BYTES);
|
||||
buffer.putDouble(value);
|
||||
buffer.flip();
|
||||
long dataReference = referencesIO.allocateReference(buffer.limit(), buffer);
|
||||
return new NumberNode(reference, dataReference);
|
||||
}
|
||||
|
||||
private Node createNewNodeNode() throws IOException {
|
||||
return createNewNodeNode(referencesIO.allocateReference());
|
||||
}
|
||||
|
||||
private Node createNewNodeNode(long reference) {
|
||||
return createNewNodeNode(new NodeProperty[0], reference);
|
||||
}
|
||||
|
||||
private Node createNewNodeNode(NodeProperty[] properties) throws IOException {
|
||||
return createNewNodeNode(properties, referencesIO.allocateReference());
|
||||
}
|
||||
|
||||
private Node createNewNodeNode(NodeProperty[] properties, long reference) {
|
||||
return new ClassNode(reference, properties);
|
||||
}
|
||||
|
||||
private void setNode(Node node) throws IOException {
|
||||
ByteBuffer buffer;
|
||||
switch (node.getType()) {
|
||||
case ARRAY:
|
||||
ArrayNode arrayNode = ((ArrayNode) node);
|
||||
buffer = ByteBuffer.allocate(Integer.BYTES + arrayNode.countItems() * Long.BYTES);
|
||||
buffer.putInt((arrayNode.countItems() & arrayCountMask) | isArrayMask);
|
||||
for (long ref : arrayNode.getItems()) {
|
||||
buffer.putLong(ref);
|
||||
}
|
||||
buffer.flip();
|
||||
break;
|
||||
case CLASS:
|
||||
ClassNode classNode = ((ClassNode) node);
|
||||
ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput();
|
||||
dataOutput.writeInt(classNode.countProperties() & nodeCountMask);
|
||||
for (NodeProperty ref : classNode.getProperties()) {
|
||||
dataOutput.write(ref.getName().length);
|
||||
dataOutput.write(ref.getName());
|
||||
dataOutput.writeLong(ref.getReference());
|
||||
}
|
||||
buffer = ByteBuffer.wrap(dataOutput.toByteArray());
|
||||
break;
|
||||
case VALUE:
|
||||
buffer = ByteBuffer.allocate(Integer.BYTES + Long.BYTES);
|
||||
buffer.putInt(isValueMask);
|
||||
buffer.putLong(((ValueNode) node).getValueReference());
|
||||
buffer.flip();
|
||||
break;
|
||||
case NUMBER:
|
||||
buffer = ByteBuffer.allocate(Integer.BYTES + Long.BYTES);
|
||||
buffer.putInt(isNumberMask);
|
||||
buffer.putLong(((NumberNode) node).getNumberReference());
|
||||
buffer.flip();
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException();
|
||||
}
|
||||
referencesIO.writeToReference(node.getReference(), buffer.limit(), buffer);
|
||||
}
|
||||
|
||||
private Node loadNode(long reference) throws IOException {
|
||||
Node node;
|
||||
ByteBuffer nodeData = referencesIO.readFromReference(reference);
|
||||
int propertiesCount = nodeData.getInt();
|
||||
boolean isNumber = (propertiesCount & isNumberMask) == isNumberMask;
|
||||
boolean isArray = !isNumber && (propertiesCount & isArrayMask) != 0;
|
||||
if (isArray) {
|
||||
int arrayElementsCount = propertiesCount & arrayCountMask;
|
||||
long[] arrayElementsReferences = new long[arrayElementsCount];
|
||||
for (int i = 0; i < arrayElementsCount; i++) {
|
||||
arrayElementsReferences[i] = nodeData.getLong();
|
||||
}
|
||||
node = new ArrayNode(reference, arrayElementsReferences);
|
||||
} else {
|
||||
boolean isValue = !isNumber && (propertiesCount & isValueMask) != 0;
|
||||
if (isValue) {
|
||||
long valueReference = nodeData.getLong();
|
||||
node = new ValueNode(reference, valueReference);
|
||||
} else if (isNumber) {
|
||||
long numberReference = nodeData.getLong();
|
||||
node = new NumberNode(reference, numberReference);
|
||||
} else {
|
||||
NodeProperty[] nodeProperties = new NodeProperty[propertiesCount & nodeCountMask];
|
||||
for (int i = 0; i < propertiesCount; i++) {
|
||||
byte nameLength = nodeData.get();
|
||||
byte[] name = new byte[nameLength];
|
||||
nodeData.get(name);
|
||||
long nodeReference = nodeData.getLong();
|
||||
nodeProperties[i] = new NodeProperty(name, nodeReference);
|
||||
}
|
||||
node = new ClassNode(reference, nodeProperties);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public static boolean nameEquals(byte[] name1, byte[] name2) {
|
||||
if (name1 == null || name2 == null || name1.length == 0 || name2.length == 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (name1.length != name2.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < name1.length; i++) {
|
||||
if (name1[i] != name2[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import it.cavallium.strangedb.database.DatabaseCore;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class DatabaseSimple extends DatabaseCore {
|
||||
private final DatabaseNodesIO databaseNodesIO;
|
||||
|
||||
public DatabaseSimple(Path dataFile, Path blocksMetaFile, Path referencesMetaFile) throws IOException {
|
||||
super(dataFile, blocksMetaFile, referencesMetaFile);
|
||||
this.databaseNodesIO = new DatabaseNodesIO(referencesIO, referencesMetadata);
|
||||
}
|
||||
|
||||
public String get(CharSequence path) throws IOException {
|
||||
return databaseNodesIO.get(path);
|
||||
}
|
||||
|
||||
public void set(CharSequence path, String value) throws IOException {
|
||||
databaseNodesIO.set(path, value);
|
||||
}
|
||||
|
||||
public boolean exists(CharSequence path) throws IOException {
|
||||
return databaseNodesIO.exists(path);
|
||||
}
|
||||
}
|
7
src/main/java/it/cavallium/strangedb/server/Node.java
Normal file
7
src/main/java/it/cavallium/strangedb/server/Node.java
Normal file
@ -0,0 +1,7 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
public interface Node {
|
||||
NodeType getType();
|
||||
long getReference();
|
||||
Node copy();
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class NodeProperty {
|
||||
private final byte[] name;
|
||||
private final long reference;
|
||||
|
||||
public NodeProperty(byte[] name, long reference) {
|
||||
this.name = name;
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
public byte[] getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public long getReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
public String getNameAsString() {
|
||||
return new String(name, StandardCharsets.US_ASCII);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
public enum NodeType {
|
||||
VALUE,
|
||||
CLASS,
|
||||
ARRAY,
|
||||
NUMBER;
|
||||
}
|
35
src/main/java/it/cavallium/strangedb/server/NumberNode.java
Normal file
35
src/main/java/it/cavallium/strangedb/server/NumberNode.java
Normal file
@ -0,0 +1,35 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
public class NumberNode implements Node {
|
||||
|
||||
private final long reference;
|
||||
private long value;
|
||||
|
||||
public NumberNode(long reference, long value) {
|
||||
this.reference = reference;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public long getNumberReference() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeType getType() {
|
||||
return NodeType.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node copy() {
|
||||
return new NumberNode(reference, value);
|
||||
}
|
||||
}
|
@ -1,4 +1,51 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import it.cavallium.strangedb.server.http.ExistsHandler;
|
||||
import it.cavallium.strangedb.server.http.GetHandler;
|
||||
import it.cavallium.strangedb.server.http.SetHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class Server {
|
||||
private final DatabaseSimple database;
|
||||
|
||||
public Server(DatabaseSimple database) throws IOException {
|
||||
this.database = database;
|
||||
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
|
||||
server.createContext("/get", new GetHandler(this));
|
||||
server.createContext("/set", new SetHandler(this));
|
||||
server.createContext("/exists", new ExistsHandler(this));
|
||||
server.setExecutor(null);
|
||||
server.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Start the server</p>
|
||||
* <code>java -jar server.jar <database-directory></code>
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
if (args.length != 1) {
|
||||
System.err.println("Usage: java -jar server.jar <database-directory>");
|
||||
}
|
||||
Path databasePath = Paths.get(args[0]);
|
||||
DatabaseSimple database = new DatabaseSimple(databasePath.resolve("database.db"), databasePath.resolve("database.blocks.dat"), databasePath.resolve("database.references.dat"));
|
||||
new Server(database);
|
||||
}
|
||||
|
||||
public boolean exists(CharSequence path) throws IOException {
|
||||
return database.exists(path);
|
||||
}
|
||||
|
||||
public String get(CharSequence path) throws IOException {
|
||||
return database.get(path);
|
||||
}
|
||||
|
||||
public void set(CharSequence path, String value) throws IOException {
|
||||
database.set(path, value);
|
||||
}
|
||||
}
|
||||
|
159
src/main/java/it/cavallium/strangedb/server/TreePath.java
Normal file
159
src/main/java/it/cavallium/strangedb/server/TreePath.java
Normal file
@ -0,0 +1,159 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TreePath {
|
||||
public final TreePath parent;
|
||||
private final byte[] node;
|
||||
private final int offset;
|
||||
|
||||
private TreePath() {
|
||||
parent = null;
|
||||
node = null;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
private TreePath(TreePath parent, byte[] node) {
|
||||
this.parent = parent;
|
||||
this.node = node;
|
||||
this.offset = 0;
|
||||
}
|
||||
|
||||
private TreePath(TreePath parent, int offset) {
|
||||
this.parent = parent;
|
||||
this.node = null;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public TreePath resolveArrayElement(int offset) {
|
||||
return new TreePath(this, offset);
|
||||
}
|
||||
|
||||
public TreePath resolveNode(byte[] child) {
|
||||
return new TreePath(this, child);
|
||||
}
|
||||
|
||||
public boolean isNodeProperty() {
|
||||
return (isRoot() || node != null);
|
||||
}
|
||||
|
||||
public boolean isArrayOffset() {
|
||||
return !isNodeProperty();
|
||||
}
|
||||
|
||||
public byte[] getNodeValue() {
|
||||
if(node == null || isRoot())
|
||||
throw new NullPointerException();
|
||||
return node;
|
||||
}
|
||||
|
||||
public int getArrayOffset() {
|
||||
if(node != null || isRoot())
|
||||
throw new NullPointerException();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public boolean hasParent() {
|
||||
return parent != null;
|
||||
}
|
||||
|
||||
public TreePath getParent() {
|
||||
if (parent == null)
|
||||
throw new NullPointerException();
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringBuilder().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to string the actual TreePath
|
||||
* @return The TreePath as a string
|
||||
*/
|
||||
private StringBuilder toStringBuilder() {
|
||||
StringBuilder builder;
|
||||
if (parent == null) {
|
||||
builder = new StringBuilder();
|
||||
} else {
|
||||
builder = parent.toStringBuilder();
|
||||
}
|
||||
if (isRoot()) {
|
||||
return builder;
|
||||
}
|
||||
if (node != null) {
|
||||
if (parent != null && !parent.isRoot())
|
||||
builder.append('.');
|
||||
builder.append(nodeToString(node));
|
||||
} else {
|
||||
builder.append('[').append(offset).append(']');
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert node bytes to a StringBuilder
|
||||
* @param node node letters
|
||||
* @return node letters joined together
|
||||
*/
|
||||
public static StringBuilder nodeToString(byte[] node) {
|
||||
StringBuilder string = new StringBuilder();
|
||||
for (byte letter : node) {
|
||||
string.append((char) letter);
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
public static byte[] stringToNode(String text) {
|
||||
return text.getBytes(StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a char sequence to a TreePath
|
||||
* @param str char sequence
|
||||
* @return The tree path
|
||||
*/
|
||||
public static TreePath get(CharSequence str) {
|
||||
byte[] currentName = new byte[32];
|
||||
byte currentNamePosition = 0;
|
||||
TreePath currentTreePath = new TreePath();
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
byte character = (byte) str.charAt(i);
|
||||
if (character >= '0' && character <= '9'
|
||||
|| character >= 'A' && character <= 'Z'
|
||||
|| character >= 'a' && character <= 'z'
|
||||
|| character == '_') {
|
||||
currentName[currentNamePosition] = character;
|
||||
currentNamePosition++;
|
||||
} else if((character == '.' || character == '[') && currentNamePosition > 0) {
|
||||
currentTreePath = currentTreePath.resolveNode(Arrays.copyOf(currentName, currentNamePosition));
|
||||
currentNamePosition = 0;
|
||||
} else if (character == ']') {
|
||||
if (currentNamePosition == 0) throw new NullPointerException();
|
||||
int arrayOffset = toInt(Arrays.copyOf(currentName, currentNamePosition));
|
||||
currentTreePath = currentTreePath.resolveArrayElement(arrayOffset);
|
||||
currentNamePosition = 0;
|
||||
}
|
||||
}
|
||||
if (currentNamePosition != 0) {
|
||||
currentTreePath = currentTreePath.resolveNode(Arrays.copyOf(currentName, currentNamePosition));
|
||||
}
|
||||
return currentTreePath;
|
||||
}
|
||||
|
||||
private static int toInt(byte[] number) {
|
||||
int result = 0;
|
||||
int tenpower = 1;
|
||||
for (int i = number.length - 1; i >= 0; i--) {
|
||||
result += (number[i] - '0') * tenpower;
|
||||
tenpower *= 10;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return parent == null;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class TreePathWalker {
|
||||
private TreePath parts[];
|
||||
private int currentPosition;
|
||||
|
||||
public TreePathWalker(TreePath path) {
|
||||
List<TreePath> parts = new LinkedList<>();
|
||||
parts.add(path);
|
||||
while (path.hasParent()) {
|
||||
path = path.getParent();
|
||||
parts.add(path);
|
||||
}
|
||||
Collections.reverse(parts);
|
||||
this.parts = parts.toArray(new TreePath[0]);
|
||||
currentPosition = this.parts.length - 1;
|
||||
}
|
||||
|
||||
public TreePath walkToRoot() {
|
||||
return parts[currentPosition = 0];
|
||||
}
|
||||
|
||||
public TreePath current() {
|
||||
return parts[currentPosition];
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return currentPosition + 1 < parts.length;
|
||||
}
|
||||
|
||||
public boolean hasPrevious() {
|
||||
return currentPosition - 1 >= 0;
|
||||
}
|
||||
|
||||
public TreePath next() {
|
||||
return parts[++currentPosition];
|
||||
}
|
||||
|
||||
public TreePath previous() {
|
||||
return parts[--currentPosition];
|
||||
}
|
||||
}
|
37
src/main/java/it/cavallium/strangedb/server/ValueNode.java
Normal file
37
src/main/java/it/cavallium/strangedb/server/ValueNode.java
Normal file
@ -0,0 +1,37 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ValueNode implements Node {
|
||||
|
||||
private final long reference;
|
||||
private long value;
|
||||
|
||||
public ValueNode(long reference, long value) {
|
||||
this.reference = reference;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public long getValueReference() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NodeType getType() {
|
||||
return NodeType.VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node copy() {
|
||||
return new ValueNode(reference, value);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package it.cavallium.strangedb.server.http;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import it.cavallium.strangedb.server.Server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ExistsHandler implements HttpHandler {
|
||||
|
||||
private final Server server;
|
||||
|
||||
public ExistsHandler(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
String requestPath = exchange.getRequestURI().toString().split("/exists/", 2)[1].replace('(', '[').replace(')', ']');
|
||||
int responseCode = 500;
|
||||
String response;
|
||||
try {
|
||||
response = "" + server.exists(requestPath);
|
||||
responseCode = 200;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
response = "Error";
|
||||
}
|
||||
byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
|
||||
exchange.sendResponseHeaders(responseCode, responseBytes.length);
|
||||
OutputStream os = exchange.getResponseBody();
|
||||
os.write(responseBytes);
|
||||
os.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package it.cavallium.strangedb.server.http;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import it.cavallium.strangedb.server.Server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class GetHandler implements HttpHandler {
|
||||
|
||||
private final Server server;
|
||||
|
||||
public GetHandler(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
String requestPath = exchange.getRequestURI().toString().split("/get/", 2)[1].replace('(', '[').replace(')', ']');
|
||||
int responseCode = 500;
|
||||
String response;
|
||||
try {
|
||||
response = server.get(requestPath);
|
||||
responseCode = 200;
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
response = "Error";
|
||||
}
|
||||
byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
|
||||
exchange.sendResponseHeaders(responseCode, responseBytes.length);
|
||||
OutputStream os = exchange.getResponseBody();
|
||||
os.write(responseBytes);
|
||||
os.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package it.cavallium.strangedb.server.http;
|
||||
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import it.cavallium.strangedb.server.Server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class SetHandler implements HttpHandler {
|
||||
|
||||
private final Server server;
|
||||
|
||||
public SetHandler(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
String requestPath = exchange.getRequestURI().toString().split("/set/", 2)[1].replace('(', '[').replace(')', ']');
|
||||
String requestBody = new String(exchange.getRequestBody().readAllBytes(), StandardCharsets.UTF_8);
|
||||
int responseCode = 500;
|
||||
String response;
|
||||
try {
|
||||
if (exchange.getRequestMethod().equalsIgnoreCase("POST")) {
|
||||
server.set(requestPath, requestBody);
|
||||
response = "ok";
|
||||
responseCode = 200;
|
||||
} else {
|
||||
response = "The request method is not a POST";
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
response = "Error";
|
||||
}
|
||||
byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
|
||||
exchange.sendResponseHeaders(responseCode, responseBytes.length);
|
||||
OutputStream os = exchange.getResponseBody();
|
||||
os.write(responseBytes);
|
||||
os.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package it.cavallium.strangedb.server;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
|
||||
public class GetSetExistsTest {
|
||||
|
||||
private Path path1;
|
||||
private Path path2;
|
||||
private Path path3;
|
||||
private DatabaseSimple db;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
path1 = Files.createTempFile("db-tests-", ".db");
|
||||
path2 = Files.createTempFile("db-tests-", ".db");
|
||||
path3 = Files.createTempFile("db-tests-", ".db");
|
||||
db = new DatabaseSimple(path1, path2, path3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSetObject() throws IOException {
|
||||
assertTrue(db.exists(""));
|
||||
assertEquals(db.get(""), "{}");
|
||||
db.set("", "{}");
|
||||
assertTrue(db.exists(""));
|
||||
assertEquals(db.get(""), "{}");
|
||||
db.set("brightness", "\"15\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetObject() throws IOException {
|
||||
assertFalse(db.exists("brightness"));
|
||||
db.set("brightness", "\"15\"");
|
||||
assertTrue(db.exists("brightness"));
|
||||
assertEquals(db.get("brightness"), "\"15\"");
|
||||
assertEquals(db.get(""), "{brightness:\"15\"}");
|
||||
db.set("brightness", "\"16\"");
|
||||
assertEquals(db.get("brightness"), "\"16\"");
|
||||
assertEquals(db.get(""), "{brightness:\"16\"}");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
db.close();
|
||||
Files.deleteIfExists(path1);
|
||||
Files.deleteIfExists(path2);
|
||||
Files.deleteIfExists(path3);
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.tests;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObject;
|
||||
import it.cavallium.strangedb.server.strangedb.database.IDatabaseTools;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbDataType;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbField;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPropertyGetter;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPropertySetter;
|
||||
import it.cavallium.strangedb.server.strangedb.utils.NTestUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Clean {
|
||||
private NTestUtils.WrappedDb db;
|
||||
private RootTwoClasses root;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
db = NTestUtils.wrapDb().create((db) -> {
|
||||
root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
|
||||
});
|
||||
root.class1 = new NTestUtils.RootClass(db.get());
|
||||
db.setRootClassValues(root.class1);
|
||||
root.class2 = new NTestUtils.RootClass(db.get());
|
||||
db.setRootClassValues(root.class2);
|
||||
root.setClass3(new NTestUtils.RootClass(db.get()));
|
||||
db.setRootClassValues(root.getClass3());
|
||||
root.setClass4(new NTestUtils.RootClass(db.get()));
|
||||
db.setRootClassValues(root.getClass4());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMatchMultipleEnhancedObjects() throws IOException {
|
||||
db.testRootClassValues(root.class1);
|
||||
db.testRootClassValues(root.class2);
|
||||
db.testRootClassValues(root.getClass3());
|
||||
db.testRootClassValues(root.getClass4());
|
||||
db.get().closeAndClean();
|
||||
db = NTestUtils.wrapDb().create((db) -> {
|
||||
root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
db.delete();
|
||||
}
|
||||
|
||||
public static class RootTwoClasses extends EnhancedObject {
|
||||
|
||||
@DbField(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass class1;
|
||||
|
||||
@DbField(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass class2;
|
||||
|
||||
public RootTwoClasses() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RootTwoClasses(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
|
||||
@DbPropertyGetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass getClass3() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public void setClass3(NTestUtils.RootClass value) {
|
||||
setProperty(value);
|
||||
}
|
||||
|
||||
@DbPropertyGetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass getClass4() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public void setClass4(NTestUtils.RootClass value) {
|
||||
setProperty(value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.tests;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import it.cavallium.strangedb.server.strangedb.database.Database;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class EnhancedClassUpdate {
|
||||
|
||||
private Path path1;
|
||||
private Path path2;
|
||||
private Path path3;
|
||||
private Database db;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
path1 = Files.createTempFile("db-tests-", ".db");
|
||||
path2 = Files.createTempFile("db-tests-", ".db");
|
||||
path3 = Files.createTempFile("db-tests-", ".db");
|
||||
db = new Database(path1, path2, path3);
|
||||
OldClass root = db.loadRoot(OldClass.class, OldClass::new);
|
||||
root.field1 = "Abc";
|
||||
root.field2 = 12;
|
||||
root.field4 = 13;
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUpdateClass() throws IOException {
|
||||
db = new Database(path1, path2, path3);
|
||||
V2Class root = db.loadRoot(V2Class.class, V2Class::new);
|
||||
assertEquals(root.field4, "Abc");
|
||||
assertEquals(root.field2, 12);
|
||||
assertEquals(root.field1, 13L);
|
||||
db.close();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
Files.deleteIfExists(path1);
|
||||
Files.deleteIfExists(path2);
|
||||
Files.deleteIfExists(path3);
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.tests;
|
||||
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObject;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbDataType;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbField;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPropertyGetter;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPropertySetter;
|
||||
import it.cavallium.strangedb.server.strangedb.database.IDatabaseTools;
|
||||
import it.cavallium.strangedb.server.strangedb.utils.NTestUtils;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class MultipleEnhancedObjects {
|
||||
private NTestUtils.WrappedDb db;
|
||||
private RootTwoClasses root;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
db = NTestUtils.wrapDb().create((db) -> {
|
||||
root = db.get().loadRoot(RootTwoClasses.class, RootTwoClasses::new);
|
||||
});
|
||||
root.class1 = new NTestUtils.RootClass(db.get());
|
||||
db.setRootClassValues(root.class1);
|
||||
root.class2 = new NTestUtils.RootClass(db.get());
|
||||
db.setRootClassValues(root.class2);
|
||||
root.setClass3(new NTestUtils.RootClass(db.get()));
|
||||
db.setRootClassValues(root.getClass3());
|
||||
root.setClass4(new NTestUtils.RootClass(db.get()));
|
||||
db.setRootClassValues(root.getClass4());
|
||||
db.closeAndReopen();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMatchMultipleEnhancedObjects() {
|
||||
db.testRootClassValues(root.class1);
|
||||
db.testRootClassValues(root.class2);
|
||||
db.testRootClassValues(root.getClass3());
|
||||
db.testRootClassValues(root.getClass4());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
db.delete();
|
||||
}
|
||||
|
||||
public static class RootTwoClasses extends EnhancedObject {
|
||||
|
||||
@DbField(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass class1;
|
||||
|
||||
@DbField(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass class2;
|
||||
|
||||
public RootTwoClasses() {
|
||||
super();
|
||||
}
|
||||
|
||||
public RootTwoClasses(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
|
||||
@DbPropertyGetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass getClass3() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public void setClass3(NTestUtils.RootClass value) {
|
||||
setProperty(value);
|
||||
}
|
||||
|
||||
@DbPropertyGetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NTestUtils.RootClass getClass4() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public void setClass4(NTestUtils.RootClass value) {
|
||||
setProperty(value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.tests;
|
||||
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPrimitiveField;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPrimitiveType;
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObject;
|
||||
import it.cavallium.strangedb.server.strangedb.database.IDatabaseTools;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbDataType;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbField;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class OldClass extends EnhancedObject {
|
||||
|
||||
@DbField(id = 0, type = DbDataType.OBJECT)
|
||||
public String field1;
|
||||
|
||||
@DbPrimitiveField(id = 0, type = DbPrimitiveType.INTEGER)
|
||||
public int field2;
|
||||
|
||||
@DbPrimitiveField(id = 2, type = DbPrimitiveType.INTEGER)
|
||||
public int field4;
|
||||
|
||||
public OldClass() {
|
||||
|
||||
}
|
||||
|
||||
public OldClass(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
}
|
@ -1,343 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.tests;
|
||||
|
||||
import it.cavallium.strangedb.annotations.*;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.*;
|
||||
import it.cavallium.strangedb.server.strangedb.functionalinterfaces.RunnableWithIO;
|
||||
import it.cavallium.strangedb.server.strangedb.lists.EnhancedObjectStrandeDbList;
|
||||
import it.cavallium.strangedb.server.strangedb.lists.ObjectStrandeDbList;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.cavallium.strangedb.server.strangedb.database.Database;
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObject;
|
||||
import it.cavallium.strangedb.server.strangedb.database.IDatabaseTools;
|
||||
import it.cavallium.strangedb.server.strangedb.VariableWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Performance {
|
||||
private static boolean FAST_TESTS;
|
||||
|
||||
private static Path rootDirectory;
|
||||
private static Path dbDataFile;
|
||||
private static Path dbBlocksFile;
|
||||
private static Path dbReferencesFile;
|
||||
private static Database db;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param args args[0] = true for fast tests
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public static void main(String[] args) throws IOException, InterruptedException {
|
||||
FAST_TESTS = args.length > 0 && args[0].equalsIgnoreCase("true");
|
||||
if (args.length >= 2) {
|
||||
rootDirectory = Paths.get(args[1]);
|
||||
try {
|
||||
Files.createDirectory(rootDirectory);
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
} else {
|
||||
rootDirectory = Files.createTempDirectory("performance-tests");
|
||||
}
|
||||
generateDb();
|
||||
System.out.println("Performance test started.");
|
||||
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("-------------------------------------------------------+-----------------------------------------------------------------");
|
||||
testS("Database creation", 3000, Performance::deleteDb, Performance::generateDb, () -> {});
|
||||
testS("Database root creation", 3000, Performance::regenDb, () -> db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new), () -> {});
|
||||
final VariableWrapper<PreloadedListContainer> preloadedListContainer = new VariableWrapper<>(null);
|
||||
final VariableWrapper<SimpleEnhancedObject> simpleEnhancedObjectContainer = new VariableWrapper<>(null);
|
||||
testS("ObjectStrandeDbList<Int> creation", 3000, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
}, () -> preloadedListContainer.var.list = new ObjectStrandeDbList<>(db), () -> {});
|
||||
testS("ObjectStrandeDbList<Int>: Filling with 1000 items", 100, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.list = new ObjectStrandeDbList<>(db);
|
||||
}, () -> {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.list.add(1000);
|
||||
}
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<EnhancedObject>: Filling with 1000 items", 100, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrandeDbList<>(db, SimpleEnhancedObject.class);
|
||||
simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db);
|
||||
simpleEnhancedObjectContainer.var.integerNumber = 10;
|
||||
simpleEnhancedObjectContainer.var.longNumber = 10L;
|
||||
simpleEnhancedObjectContainer.var.object = new ArrayList<>();
|
||||
simpleEnhancedObjectContainer.var.object.add("XHIghicuiHUCB UIVY");
|
||||
simpleEnhancedObjectContainer.var.object.add("ioZ>UIHZXGHXYGY");
|
||||
simpleEnhancedObjectContainer.var.object.add("XJIOUIhcgGuigscwvyv");
|
||||
}, () -> {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var);
|
||||
}
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<Int>: Filling with 10000 items", 10, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.list = new ObjectStrandeDbList<>(db);
|
||||
}, () -> {
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
preloadedListContainer.var.list.add(1000);
|
||||
}
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<Int>: Filling with 100000 items", 1, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.list = new ObjectStrandeDbList<>(db);
|
||||
}, () -> {
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
preloadedListContainer.var.list.add(1000);
|
||||
}
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<Int>: Loading 1000 items", 100, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.list = new ObjectStrandeDbList<>(db);
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.list.add(1000);
|
||||
}
|
||||
}, () -> {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.list.get(i);
|
||||
}
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<EnhancedObject>: Loading with 1000 items", 100, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrandeDbList<>(db, SimpleEnhancedObject.class);
|
||||
simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db);
|
||||
simpleEnhancedObjectContainer.var.integerNumber = 10;
|
||||
simpleEnhancedObjectContainer.var.longNumber = 10L;
|
||||
simpleEnhancedObjectContainer.var.object = new ArrayList<>();
|
||||
simpleEnhancedObjectContainer.var.object.add("XHIghicuiHUCB UIVY");
|
||||
simpleEnhancedObjectContainer.var.object.add("ioZ>UIHZXGHXYGY");
|
||||
simpleEnhancedObjectContainer.var.object.add("XJIOUIhcgGuigscwvyv");
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var);
|
||||
}
|
||||
}, () -> {
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.listOfEnhancedObj.get(i);
|
||||
}
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<Int>: Loading 10000 items", 10, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.list = new ObjectStrandeDbList<>(db);
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
preloadedListContainer.var.list.add(1000);
|
||||
}
|
||||
}, () -> {
|
||||
for (int i = 0; i < 10000; i++) {
|
||||
preloadedListContainer.var.list.get(i);
|
||||
}
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<Int>: getLast() with 1000 items", 100, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.list = new ObjectStrandeDbList<>(db);
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.list.add(1000);
|
||||
}
|
||||
}, () -> {
|
||||
preloadedListContainer.var.list.getLast();
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<EnhancedObject>: getLast() with 1000 items", 100, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.listOfEnhancedObj = new EnhancedObjectStrandeDbList<>(db, SimpleEnhancedObject.class);
|
||||
simpleEnhancedObjectContainer.var = new SimpleEnhancedObject(db);
|
||||
simpleEnhancedObjectContainer.var.integerNumber = 10;
|
||||
simpleEnhancedObjectContainer.var.longNumber = 10L;
|
||||
simpleEnhancedObjectContainer.var.object = new ArrayList<>();
|
||||
simpleEnhancedObjectContainer.var.object.add("XHIghicuiHUCB UIVY");
|
||||
simpleEnhancedObjectContainer.var.object.add("ioZ>UIHZXGHXYGY");
|
||||
simpleEnhancedObjectContainer.var.object.add("XJIOUIhcgGuigscwvyv");
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.listOfEnhancedObj.add(simpleEnhancedObjectContainer.var);
|
||||
}
|
||||
}, () -> {
|
||||
preloadedListContainer.var.listOfEnhancedObj.getLast();
|
||||
}, () -> {});
|
||||
testS("ObjectStrandeDbList<Int>: size() with 1000 items", 100, () -> {
|
||||
regenDb();
|
||||
preloadedListContainer.var = db.loadRoot(PreloadedListContainer.class, PreloadedListContainer::new);
|
||||
preloadedListContainer.var.list = new ObjectStrandeDbList<>(db);
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
preloadedListContainer.var.list.add(1000);
|
||||
}
|
||||
}, () -> {
|
||||
preloadedListContainer.var.list.size();
|
||||
}, () -> {});
|
||||
System.out.println("-------------------------------------------------------+-----------------------------------------------------------------");
|
||||
System.out.println("Performance test finished.");
|
||||
deleteDb();
|
||||
Files.deleteIfExists(rootDirectory);
|
||||
}
|
||||
|
||||
private static void NtestS(String description, int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException {
|
||||
}
|
||||
|
||||
|
||||
private static void testS(String description, int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException {
|
||||
if (FAST_TESTS) {
|
||||
if (times >= 5) {
|
||||
times /= 5;
|
||||
} else if (times >= 2) {
|
||||
times /= 2;
|
||||
}
|
||||
}
|
||||
description = description + " time is";
|
||||
int spacesCount = 40 - description.length();
|
||||
int cutAt = 0;
|
||||
if (spacesCount < 0) {
|
||||
spacesCount = 40 - (description.length() - 40);
|
||||
cutAt = 40;
|
||||
}
|
||||
StringBuilder spaces = new StringBuilder();
|
||||
for (int i = 0; i < spacesCount; i++) {
|
||||
spaces.append(' ');
|
||||
}
|
||||
double[] results = test(times, beforeAction, action, afterAction);
|
||||
if (cutAt > 0) {
|
||||
System.out.println(description.substring(0, cutAt) + " |");
|
||||
}
|
||||
System.out.printf("%s:%s%s%s%n", description.substring(cutAt), spaces, format(results[0]) + " |", results.length > 1 ? (format(results[1]) + (results.length > 2 ? (format(results[2]) + (results.length > 3 ? (format(results[3]) + (results.length > 4 ? (format(results[4]) + (results.length > 5 ? format(results[5]) : "")) : "")) : "")) : "")) : "");
|
||||
}
|
||||
|
||||
private static String format(double result) {
|
||||
String spaces;
|
||||
if (result < 10) {
|
||||
spaces = " ";
|
||||
} else if (result < 100) {
|
||||
spaces = " ";
|
||||
} else if (result < 1000) {
|
||||
spaces = " ";
|
||||
} else {
|
||||
spaces = " ";
|
||||
}
|
||||
return spaces + String.format("%.2fms", result);
|
||||
}
|
||||
|
||||
private static double[] test(int times, RunnableWithIO beforeAction, RunnableWithIO action, RunnableWithIO afterAction) throws IOException, InterruptedException {
|
||||
LongArrayList results = new LongArrayList(times);
|
||||
Thread.sleep(100);
|
||||
System.gc();
|
||||
Thread.sleep(100);
|
||||
for (int i = 0; i < times; i++) {
|
||||
beforeAction.run();
|
||||
long startTime = System.nanoTime();
|
||||
action.run();
|
||||
long elapsedTime = System.nanoTime() - startTime;
|
||||
afterAction.run();
|
||||
results.add(elapsedTime);
|
||||
}
|
||||
double result1 = results.stream().limit(1).mapToLong(val -> val).average().orElse(0.0) / 1000000d;
|
||||
double result10 = results.stream().limit(10).mapToLong(val -> val).average().orElse(0.0) / 1000000d;
|
||||
double result100 = results.stream().limit(100).mapToLong(val -> val).average().orElse(0.0) / 1000000d;
|
||||
double result1000 = results.stream().limit(1000).mapToLong(val -> val).average().orElse(0.0) / 1000000d;
|
||||
double result10000 = results.stream().limit(10000).mapToLong(val -> val).average().orElse(0.0) / 1000000d;
|
||||
double resultMax = results.stream().mapToLong(val -> val).average().orElse(0.0) / 1000000d;
|
||||
if (times <= 1) {
|
||||
return new double[]{resultMax};
|
||||
} else if (times <= 10) {
|
||||
return new double[]{resultMax, result1};
|
||||
} else if (times <= 100) {
|
||||
return new double[]{resultMax, result1, result10};
|
||||
} else if (times <= 1000) {
|
||||
return new double[]{resultMax, result1, result10, result100};
|
||||
} else if (times <= 10000) {
|
||||
return new double[]{resultMax, result1, result10, result100, result1000};
|
||||
} else {
|
||||
return new double[]{resultMax, result1, result10, result100, result1000, result10000};
|
||||
}
|
||||
}
|
||||
|
||||
public static void generateDb() throws IOException {
|
||||
dbDataFile = Files.createFile(rootDirectory.resolve("db_data.dat"));
|
||||
dbBlocksFile = Files.createFile(rootDirectory.resolve("db_blocks.dat"));
|
||||
dbReferencesFile = Files.createFile(rootDirectory.resolve("db_references.dat"));
|
||||
db = new Database(dbDataFile, dbBlocksFile, dbReferencesFile);
|
||||
}
|
||||
|
||||
public static void deleteDb() throws IOException {
|
||||
db.close();
|
||||
Files.deleteIfExists(dbDataFile);
|
||||
Files.deleteIfExists(dbBlocksFile);
|
||||
Files.deleteIfExists(dbReferencesFile);
|
||||
}
|
||||
|
||||
public static void regenDb() throws IOException {
|
||||
deleteDb();
|
||||
generateDb();
|
||||
}
|
||||
|
||||
public static class PreloadedListContainer extends EnhancedObject {
|
||||
|
||||
@DbField(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public ObjectStrandeDbList<Integer> list;
|
||||
|
||||
@DbField(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public EnhancedObjectStrandeDbList<SimpleEnhancedObject> listOfEnhancedObj;
|
||||
|
||||
public PreloadedListContainer() {
|
||||
|
||||
}
|
||||
|
||||
public PreloadedListContainer(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DynamicListContainer extends EnhancedObject {
|
||||
|
||||
public DynamicListContainer() {
|
||||
|
||||
}
|
||||
|
||||
public DynamicListContainer(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
|
||||
|
||||
@DbPropertyGetter(id = 0, type = DbDataType.ENHANCED_OBJECT)
|
||||
public ObjectStrandeDbList<Integer> getList() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 1, type = DbDataType.ENHANCED_OBJECT)
|
||||
public void setList(ObjectStrandeDbList<Integer> list) {
|
||||
setProperty(list);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleEnhancedObject extends EnhancedObject {
|
||||
public SimpleEnhancedObject() {
|
||||
|
||||
}
|
||||
|
||||
public SimpleEnhancedObject(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
|
||||
@DbField(id = 0, type = DbDataType.OBJECT)
|
||||
public ArrayList<String> object;
|
||||
|
||||
@DbPrimitiveField(id = 0, type = DbPrimitiveType.INTEGER)
|
||||
public int integerNumber;
|
||||
|
||||
@DbPrimitiveField(id = 1, type = DbPrimitiveType.LONG)
|
||||
public long longNumber;
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.tests;
|
||||
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObjectUpgrader;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbDataType;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbField;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPrimitiveField;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPrimitiveType;
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObject;
|
||||
import it.cavallium.strangedb.server.strangedb.database.IDatabaseTools;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbClass;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@DbClass(version = 1)
|
||||
public class V2Class extends EnhancedObject {
|
||||
@DbPrimitiveField(id = 0, type = DbPrimitiveType.LONG)
|
||||
public long field1;
|
||||
|
||||
@DbPrimitiveField(id = 1, type = DbPrimitiveType.INTEGER)
|
||||
public int field2;
|
||||
|
||||
@DbField(id = 0, type = DbDataType.OBJECT)
|
||||
public String field4;
|
||||
|
||||
public V2Class() {
|
||||
|
||||
}
|
||||
|
||||
public V2Class(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(int oldObjectVersion, EnhancedObjectUpgrader enhancedObjectUpgrader) throws IOException {
|
||||
switch (oldObjectVersion) {
|
||||
case 0: {
|
||||
field1 = (long) enhancedObjectUpgrader.getPrimitiveInt(2);
|
||||
field2 = enhancedObjectUpgrader.getPrimitiveInt(0);
|
||||
field4 = (String) enhancedObjectUpgrader.getField(0, DbDataType.OBJECT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConsumerWithIO<T> {
|
||||
|
||||
/**
|
||||
* Performs this operation on the given argument.
|
||||
*
|
||||
* @param t the input argument
|
||||
*/
|
||||
void accept(T t) throws IOException;
|
||||
|
||||
/**
|
||||
* Returns a composed {@code Consumer} that performs, in sequence, this
|
||||
* operation followed by the {@code after} operation. If performing either
|
||||
* operation throws an exception, it is relayed to the caller of the
|
||||
* composed operation. If performing this operation throws an exception,
|
||||
* the {@code after} operation will not be performed.
|
||||
*
|
||||
* @param after the operation to perform after this operation
|
||||
* @return a composed {@code Consumer} that performs in sequence this
|
||||
* operation followed by the {@code after} operation
|
||||
* @throws NullPointerException if {@code after} is null
|
||||
*/
|
||||
default ConsumerWithIO<T> andThen(ConsumerWithIO<? super T> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return (T t) -> { accept(t); after.accept(t); };
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.utils;
|
||||
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPrimitiveField;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.DbPrimitiveType;
|
||||
import it.cavallium.strangedb.server.strangedb.database.Database;
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NSimplestClass extends EnhancedObject {
|
||||
|
||||
@DbPrimitiveField(id = 0, type = DbPrimitiveType.BOOLEAN)
|
||||
public boolean field1;
|
||||
|
||||
public NSimplestClass() {
|
||||
|
||||
}
|
||||
|
||||
public NSimplestClass(Database database) throws IOException {
|
||||
super(database);
|
||||
field1 = true;
|
||||
}
|
||||
}
|
@ -1,284 +0,0 @@
|
||||
package it.cavallium.strangedb.server.strangedb.utils;
|
||||
|
||||
import it.cavallium.strangedb.annotations.*;
|
||||
import it.cavallium.strangedb.server.strangedb.annotations.*;
|
||||
import it.cavallium.strangedb.server.strangedb.functionalinterfaces.RunnableWithIO;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.cavallium.strangedb.server.strangedb.database.Database;
|
||||
import it.cavallium.strangedb.server.strangedb.EnhancedObject;
|
||||
import it.cavallium.strangedb.server.strangedb.database.IDatabaseTools;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Comparator;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class NTestUtils {
|
||||
public static WrappedDb wrapDb() {
|
||||
return new WrappedDb();
|
||||
}
|
||||
|
||||
public static class WrappedDb {
|
||||
|
||||
private Database db;
|
||||
private Path tempDir;
|
||||
private RunnableWithIO r;
|
||||
|
||||
private WrappedDb() {
|
||||
|
||||
}
|
||||
|
||||
public WrappedDb create() throws IOException {
|
||||
tempDir = Files.createTempDirectory("tests-");
|
||||
db = openDatabase();
|
||||
if (r != null) {
|
||||
r.run();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public WrappedDb create(ConsumerWithIO<NTestUtils.WrappedDb> r) throws IOException {
|
||||
this.r = () -> r.accept(WrappedDb.this);
|
||||
this.create();
|
||||
return this;
|
||||
}
|
||||
|
||||
private Database openDatabase() throws IOException {
|
||||
return new Database(tempDir.resolve(Paths.get("data.db")), tempDir.resolve(Paths.get("blocks.dat")), tempDir.resolve(Paths.get("references.dat")));
|
||||
}
|
||||
|
||||
public void delete() throws IOException {
|
||||
db.close();
|
||||
deleteDir(tempDir);
|
||||
}
|
||||
|
||||
public Database get() {
|
||||
return db;
|
||||
}
|
||||
|
||||
private void deleteDir(Path p) throws IOException {
|
||||
Files.walk(p)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
.map(Path::toFile)
|
||||
.forEach(File::delete);
|
||||
}
|
||||
|
||||
public void closeAndReopen() throws IOException {
|
||||
db.close();
|
||||
db = openDatabase();
|
||||
r.run();
|
||||
}
|
||||
|
||||
public void setRootClassValues(RootClass root) throws IOException {
|
||||
setRootClassFields(root);
|
||||
setRootClassProperties(root);
|
||||
}
|
||||
|
||||
public void setRootClassFields(RootClass root) throws IOException {
|
||||
root.field1 = true;
|
||||
root.field2 = 2;
|
||||
root.field3 = 3;
|
||||
root.field4 = 4;
|
||||
root.field5 = 5;
|
||||
root.field6 = 6;
|
||||
root.field7 = "Test";
|
||||
root.field8 = new LongArrayList();
|
||||
root.field8.add(0);
|
||||
root.field8.add(1);
|
||||
root.field8.add(2);
|
||||
root.field8.add(Long.MAX_VALUE/2);
|
||||
root.field8.add(Long.MIN_VALUE/2);
|
||||
root.field8.add(Long.MAX_VALUE);
|
||||
root.field8.add(Long.MIN_VALUE);
|
||||
root.field9 = new NSimplestClass(db);
|
||||
root.field9.field1 = true;
|
||||
|
||||
}
|
||||
|
||||
public void setRootClassProperties(RootClass root) throws IOException {
|
||||
root.set7("Test");
|
||||
LongArrayList lArrayList = new LongArrayList();
|
||||
lArrayList.add(0);
|
||||
lArrayList.add(1);
|
||||
lArrayList.add(2);
|
||||
lArrayList.add(Long.MAX_VALUE/2);
|
||||
lArrayList.add(Long.MIN_VALUE/2);
|
||||
lArrayList.add(Long.MAX_VALUE);
|
||||
lArrayList.add(Long.MIN_VALUE);
|
||||
root.set8(lArrayList);
|
||||
NSimplestClass simplestClass9 = new NSimplestClass(db);
|
||||
simplestClass9.field1 = true;
|
||||
root.set9(simplestClass9);
|
||||
}
|
||||
|
||||
public void testRootClassValues(RootClass root) {
|
||||
testRootClassFields(root);
|
||||
testRootClassProperties(root);
|
||||
}
|
||||
|
||||
public void testRootClassFields(RootClass root) {
|
||||
shouldGetFieldBoolean(root);
|
||||
shouldGetFieldByte(root);
|
||||
shouldGetFieldShort(root);
|
||||
shouldGetFieldCharacter(root);
|
||||
shouldGetFieldInteger(root);
|
||||
shouldGetFieldLong(root);
|
||||
shouldGetFieldObject(root);
|
||||
shouldGetFieldUID(root);
|
||||
shouldGetFieldDBObject(root);
|
||||
}
|
||||
|
||||
public void testRootClassProperties(RootClass root) {
|
||||
shouldGetPropertyObject(root);
|
||||
shouldGetPropertyUID(root);
|
||||
shouldGetPropertyDBObject(root);
|
||||
}
|
||||
|
||||
|
||||
private void shouldGetFieldBoolean(RootClass root) {
|
||||
assertTrue(root.field1);
|
||||
}
|
||||
|
||||
private void shouldGetFieldByte(RootClass root) {
|
||||
assertEquals(2, root.field2);
|
||||
}
|
||||
|
||||
private void shouldGetFieldShort(RootClass root) {
|
||||
assertEquals(3, root.field3);
|
||||
}
|
||||
|
||||
private void shouldGetFieldCharacter(RootClass root) {
|
||||
assertEquals(4, root.field4);
|
||||
}
|
||||
|
||||
private void shouldGetFieldInteger(RootClass root) {
|
||||
assertEquals(5, root.field5);
|
||||
}
|
||||
|
||||
private void shouldGetFieldLong(RootClass root) {
|
||||
assertEquals(6, root.field6);
|
||||
}
|
||||
|
||||
private void shouldGetFieldObject(RootClass root) {
|
||||
shouldGetObject(root.field7);
|
||||
}
|
||||
|
||||
private void shouldGetPropertyObject(RootClass root) {
|
||||
shouldGetObject(root.get7());
|
||||
}
|
||||
|
||||
private void shouldGetFieldDBObject(RootClass root) {
|
||||
assertTrue(root.field9.field1);
|
||||
}
|
||||
|
||||
private void shouldGetPropertyDBObject(RootClass root) {
|
||||
assertTrue(root.get9().field1);
|
||||
}
|
||||
|
||||
private void shouldGetObject(String val) {
|
||||
assertNotNull(val);
|
||||
assertEquals("Test", val);
|
||||
}
|
||||
|
||||
private void shouldGetDBObject(NSimplestClass val) {
|
||||
assertNotNull(val);
|
||||
assertTrue(val.field1);
|
||||
}
|
||||
|
||||
private void shouldGetFieldUID(RootClass root) {
|
||||
shouldGetUID(root.field8);
|
||||
}
|
||||
|
||||
private void shouldGetPropertyUID(RootClass root) {
|
||||
shouldGetUID(root.get8());
|
||||
}
|
||||
|
||||
private void shouldGetUID(LongArrayList val) {
|
||||
assertNotNull(val);
|
||||
assertEquals(7, val.size());
|
||||
assertEquals(0, val.getLong(0));
|
||||
assertEquals(val.getLong(5), Long.MAX_VALUE);
|
||||
assertEquals(val.getLong(6), Long.MIN_VALUE);
|
||||
}
|
||||
|
||||
public void onLoad(RunnableWithIO r) {
|
||||
this.r = r;
|
||||
}
|
||||
}
|
||||
|
||||
public static class RootClass extends EnhancedObject {
|
||||
|
||||
@DbPrimitiveField(id = 0, type = DbPrimitiveType.BOOLEAN)
|
||||
public boolean field1;
|
||||
|
||||
@DbPrimitiveField(id = 1, type = DbPrimitiveType.BYTE)
|
||||
public byte field2;
|
||||
|
||||
@DbPrimitiveField(id = 2, type = DbPrimitiveType.SHORT)
|
||||
public short field3;
|
||||
|
||||
@DbPrimitiveField(id = 3, type = DbPrimitiveType.CHAR)
|
||||
public char field4;
|
||||
|
||||
@DbPrimitiveField(id = 4, type = DbPrimitiveType.INTEGER)
|
||||
public int field5;
|
||||
|
||||
@DbPrimitiveField(id = 5, type = DbPrimitiveType.LONG)
|
||||
public long field6;
|
||||
|
||||
@DbField(id = 0, type = DbDataType.OBJECT)
|
||||
public String field7;
|
||||
|
||||
@DbField(id = 1, type = DbDataType.REFERENCES_LIST)
|
||||
public LongArrayList field8;
|
||||
|
||||
@DbField(id = 2, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NSimplestClass field9;
|
||||
|
||||
public RootClass() {
|
||||
|
||||
}
|
||||
|
||||
public RootClass(IDatabaseTools databaseTools) throws IOException {
|
||||
super(databaseTools);
|
||||
}
|
||||
|
||||
@DbPropertyGetter(id = 0, type = DbDataType.OBJECT)
|
||||
public String get7() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertyGetter(id = 1, type = DbDataType.REFERENCES_LIST)
|
||||
public LongArrayList get8() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertyGetter(id = 2, type = DbDataType.ENHANCED_OBJECT)
|
||||
public NSimplestClass get9() {
|
||||
return getProperty();
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 0, type = DbDataType.OBJECT)
|
||||
public void set7(String val) {
|
||||
setProperty(val);
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 1, type = DbDataType.REFERENCES_LIST)
|
||||
public void set8(LongArrayList val) {
|
||||
setProperty(val);
|
||||
}
|
||||
|
||||
@DbPropertySetter(id = 2, type = DbDataType.ENHANCED_OBJECT)
|
||||
public void set9(NSimplestClass val) {
|
||||
setProperty(val);
|
||||
}
|
||||
|
||||
public boolean test() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user