Server 1.0.0

This commit is contained in:
Andrea Cavalli 2019-03-09 18:53:30 +01:00
parent 877a40df1b
commit 1def19d219
31 changed files with 1194 additions and 982 deletions

0
database.blocks.dat Normal file
View File

BIN
database.db Normal file

Binary file not shown.

0
database.references.dat Normal file
View File

0
database.structure.dat Normal file
View File

21
database.structure.txt Normal file
View 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
View File

@ -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>

View 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());
}
}

View 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());
}
}

View 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;
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,7 @@
package it.cavallium.strangedb.server;
public interface Node {
NodeType getType();
long getReference();
Node copy();
}

View File

@ -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);
}
}

View File

@ -0,0 +1,8 @@
package it.cavallium.strangedb.server;
public enum NodeType {
VALUE,
CLASS,
ARRAY,
NUMBER;
}

View 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);
}
}

View File

@ -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 &lt;database-directory&gt;</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);
}
}

View 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;
}
}

View File

@ -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];
}
}

View 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);
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}
}

View File

@ -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); };
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}