mirror of
https://github.com/ChronosX88/JGUN.git
synced 2024-11-09 16:51:02 +00:00
[WIP] Removing Put/GetBuilders, renamed project to JGUN (final), added get operation.
This commit is contained in:
parent
7d61993a3c
commit
ee98da62a3
@ -1,47 +0,0 @@
|
||||
package io.github.chronosx88.GunJava;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class Dup {
|
||||
private static char[] randomSeed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
|
||||
private static Random random = new Random(System.currentTimeMillis());
|
||||
private Map<String, Long> s = new ConcurrentHashMap<>();
|
||||
private DupOpt opt = new DupOpt();
|
||||
private Thread to = null;
|
||||
|
||||
public Dup() {
|
||||
opt.max = 1000;
|
||||
opt.age = 1000 * 9;
|
||||
}
|
||||
|
||||
public String track(String id) {
|
||||
s.put(id, System.currentTimeMillis());
|
||||
if(to == null) {
|
||||
Utils.setTimeout(() -> {
|
||||
for(Map.Entry<String, Long> entry : s.entrySet()) {
|
||||
if(opt.age > (System.currentTimeMillis() - entry.getValue()))
|
||||
continue;
|
||||
s.remove(entry.getKey());
|
||||
}
|
||||
to = null;
|
||||
}, opt.age);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean check(String id) {
|
||||
if(s.containsKey(id)) {
|
||||
track(id);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String random() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package io.github.chronosx88.GunJava;
|
||||
|
||||
public class DupOpt {
|
||||
public int max;
|
||||
public int age;
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
package io.github.chronosx88.GunJava;
|
||||
|
||||
import io.github.chronosx88.GunJava.storageBackends.MemoryBackend;
|
||||
import io.github.chronosx88.GunJava.storageBackends.StorageBackend;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class HAM {
|
||||
private static long defer = Long.MAX_VALUE;
|
||||
|
||||
static class HAMResult {
|
||||
public boolean defer = false;
|
||||
public boolean historical = false;
|
||||
public boolean converge = false;
|
||||
public boolean incoming = false;
|
||||
public boolean current = false;
|
||||
public boolean state = false;
|
||||
public String err = null;
|
||||
}
|
||||
|
||||
public static HAMResult ham(long machineState, long incomingState, long currentState, Object incomingValue, Object currentValue) {
|
||||
HAMResult result = new HAMResult();
|
||||
|
||||
if(machineState < incomingState) {
|
||||
result.defer = true;
|
||||
return result;
|
||||
}
|
||||
if(incomingState < currentState){
|
||||
result.historical = true;
|
||||
return result;
|
||||
}
|
||||
if(currentState < incomingState) {
|
||||
result.converge = true;
|
||||
result.incoming = true;
|
||||
return result;
|
||||
}
|
||||
if(incomingState == currentState) {
|
||||
if(incomingValue.equals(currentValue)) {
|
||||
result.state = true;
|
||||
return result;
|
||||
}
|
||||
if((incomingValue.toString().compareTo(currentValue.toString())) < 0) {
|
||||
result.converge = true;
|
||||
result.current = true;
|
||||
return result;
|
||||
}
|
||||
if((currentValue.toString().compareTo(incomingValue.toString())) < 0) {
|
||||
result.converge = true;
|
||||
result.incoming = true;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result.err = "Invalid CRDT Data: "+ incomingValue +" to "+ currentValue +" at "+ incomingState +" to "+ currentState +"!";
|
||||
return result;
|
||||
}
|
||||
|
||||
public static MemoryBackend mix(MemoryBackend change, StorageBackend data) {
|
||||
long machine = System.currentTimeMillis();
|
||||
MemoryBackend diff = null;
|
||||
for(Map.Entry<String, Node> entry : change.entries()) {
|
||||
Node node = entry.getValue();
|
||||
for(String key : node.values.keySet()) {
|
||||
Object value = node.values.get(key);
|
||||
if ("_".equals(key)) { continue; }
|
||||
long state = node.states.getLong(key);
|
||||
long was = -1;
|
||||
Object known = null;
|
||||
if(data == null) {
|
||||
data = new MemoryBackend();
|
||||
}
|
||||
if(data.hasNode(node.soul)) {
|
||||
if(data.getNode(node.soul).states.opt(key) != null) {
|
||||
was = data.getNode(node.soul).states.getLong(key);
|
||||
}
|
||||
known = data.getNode(node.soul).values.opt(key) == null ? 0 : data.getNode(node.soul).values.opt(key);
|
||||
}
|
||||
|
||||
HAMResult ham = ham(machine, state, was, value, known);
|
||||
if(!ham.incoming) {
|
||||
if(ham.defer) {
|
||||
System.out.println("DEFER: " + key + " " + value);
|
||||
// Hack for accessing value in lambda without making the variable final
|
||||
StorageBackend[] graph = new StorageBackend[] {data};
|
||||
Utils.setTimeout(() -> mix(node, graph[0]), (int) (state - System.currentTimeMillis()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(diff == null) {
|
||||
diff = new MemoryBackend();
|
||||
}
|
||||
|
||||
if(!diff.hasNode(node.soul)) {
|
||||
diff.addNode(node.soul, Utils.newNode(node.soul, new JSONObject()));
|
||||
}
|
||||
|
||||
if(!data.hasNode(node.soul)) {
|
||||
data.addNode(node.soul, Utils.newNode(node.soul, new JSONObject()));
|
||||
}
|
||||
|
||||
data.getNode(node.soul).values.put(key, value);
|
||||
diff.getNode(node.soul).values.put(key, value);
|
||||
|
||||
diff.getNode(node.soul).states.put(key, state);
|
||||
data.getNode(node.soul).states.put(key, state);
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
public static MemoryBackend mix(Node incomingNode, StorageBackend data) {
|
||||
long machine = System.currentTimeMillis();
|
||||
MemoryBackend diff = null;
|
||||
|
||||
for(String key : incomingNode.values.keySet()) {
|
||||
Object value = incomingNode.values.get(key);
|
||||
if ("_".equals(key)) { continue; }
|
||||
long state = incomingNode.states.getLong(key);
|
||||
long was = -1;
|
||||
Object known = null;
|
||||
if(data == null) {
|
||||
data = new MemoryBackend();
|
||||
}
|
||||
if(data.hasNode(incomingNode.soul)) {
|
||||
if(data.getNode(incomingNode.soul).states.opt(key) != null) {
|
||||
was = data.getNode(incomingNode.soul).states.getLong(key);
|
||||
}
|
||||
known = data.getNode(incomingNode.soul).values.opt(key) == null ? 0 : data.getNode(incomingNode.soul).values.opt(key);
|
||||
}
|
||||
|
||||
HAMResult ham = ham(machine, state, was, value, known);
|
||||
if(!ham.incoming) {
|
||||
if(ham.defer) {
|
||||
System.out.println("DEFER: " + key + " " + value);
|
||||
// Hack for accessing value in lambda without making the variable final
|
||||
StorageBackend[] graph = new StorageBackend[] {data};
|
||||
Utils.setTimeout(() -> mix(incomingNode, graph[0]), (int) (state - System.currentTimeMillis()));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(diff == null) {
|
||||
diff = new MemoryBackend();
|
||||
}
|
||||
|
||||
if(!diff.hasNode(incomingNode.soul)) {
|
||||
diff.addNode(incomingNode.soul, Utils.newNode(incomingNode.soul, new JSONObject()));
|
||||
}
|
||||
|
||||
if(!data.hasNode(incomingNode.soul)) {
|
||||
data.addNode(incomingNode.soul, Utils.newNode(incomingNode.soul, new JSONObject()));
|
||||
}
|
||||
|
||||
data.getNode(incomingNode.soul).values.put(key, value);
|
||||
diff.getNode(incomingNode.soul).values.put(key, value);
|
||||
|
||||
diff.getNode(incomingNode.soul).states.put(key, state);
|
||||
data.getNode(incomingNode.soul).states.put(key, state);
|
||||
}
|
||||
return diff;
|
||||
}
|
||||
}
|
@ -1,76 +0,0 @@
|
||||
package io.github.chronosx88.GunJava;
|
||||
|
||||
import io.github.chronosx88.GunJava.storageBackends.MemoryBackend;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Node implements Comparable<Node> {
|
||||
public JSONObject values; // Data
|
||||
public JSONObject states; // Metadata for diff
|
||||
public String soul; // i.e. ID of node
|
||||
|
||||
/**
|
||||
* Create a Node from a JSON object.
|
||||
*
|
||||
* @param rawData JSON object, which contains the data
|
||||
*/
|
||||
public Node(JSONObject rawData) {
|
||||
this.values = new JSONObject(rawData.toString());
|
||||
this.states = values.getJSONObject("_").getJSONObject(">");
|
||||
this.soul = values.getJSONObject("_").getString("#");
|
||||
values.remove("_");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Node other) {
|
||||
return soul.compareTo(other.soul);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == null)
|
||||
return false;
|
||||
if (other instanceof String)
|
||||
return soul.equals(other);
|
||||
if (other instanceof Node)
|
||||
return compareTo((Node) other) == 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return soul.hashCode();
|
||||
}
|
||||
|
||||
public boolean isNode(String key) {
|
||||
return values.optJSONObject(key) != null;
|
||||
}
|
||||
|
||||
public Node getNode(String key, MemoryBackend g) {
|
||||
String soulRef = values.getJSONObject(key).getString("#");
|
||||
return g.getNode(soulRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
JSONObject jsonObject = new JSONObject(values.toString());
|
||||
jsonObject.put("_", new JSONObject().put("#", soul).put(">", states));
|
||||
return jsonObject.toString();
|
||||
}
|
||||
|
||||
public JSONObject toJSONObject() {
|
||||
JSONObject jsonObject = new JSONObject(values.toString());
|
||||
jsonObject.put("_", new JSONObject().put("#", soul).put(">", states));
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public JSONObject getMetadata() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("_", new JSONObject().put("#", soul).put(">", states));
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public void setMetadata(JSONObject metadata) {
|
||||
soul = metadata.getJSONObject("_").getString("#");
|
||||
states = metadata.getJSONObject("_").getJSONObject(">");
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
package io.github.chronosx88.GunJava;
|
||||
|
||||
import io.github.chronosx88.GunJava.storageBackends.MemoryBackend;
|
||||
import io.github.chronosx88.GunJava.storageBackends.StorageBackend;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Utils {
|
||||
public static Thread setTimeout(Runnable runnable, int delay){
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(delay);
|
||||
runnable.run();
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
return thread;
|
||||
}
|
||||
|
||||
public static Node newNode(String soul, JSONObject data) {
|
||||
JSONObject states = new JSONObject();
|
||||
for (String key : data.keySet()) {
|
||||
states.put(key, System.currentTimeMillis());
|
||||
}
|
||||
data.put("_", new JSONObject().put("#", soul).put(">", states));
|
||||
return new Node(data);
|
||||
}
|
||||
|
||||
public static MemoryBackend getRequest(JSONObject lex, StorageBackend graph) {
|
||||
String soul = lex.getString("#");
|
||||
String key = lex.optString(".", null);
|
||||
Node node = graph.getNode(soul);
|
||||
Object tmp;
|
||||
if(node == null) {
|
||||
return new MemoryBackend();
|
||||
}
|
||||
if(key != null) {
|
||||
tmp = node.values.opt(key);
|
||||
if(tmp == null) {
|
||||
return new MemoryBackend();
|
||||
}
|
||||
Node node1 = new Node(node.toJSONObject());
|
||||
node = Utils.newNode(node.soul, new JSONObject());
|
||||
node.setMetadata(node1.getMetadata());
|
||||
node.values.put(key, tmp);
|
||||
JSONObject tmpStates = node1.states;
|
||||
node.states.put(key, tmpStates.get(key));
|
||||
}
|
||||
MemoryBackend ack = new MemoryBackend();
|
||||
ack.addNode(soul, node);
|
||||
return ack;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package io.github.chronosx88.GunJava.storageBackends;
|
||||
|
||||
import io.github.chronosx88.GunJava.Node;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class MemoryBackend implements StorageBackend {
|
||||
|
||||
private final HashMap<String, Node> nodes;
|
||||
|
||||
public MemoryBackend(JSONObject source) {
|
||||
nodes = new LinkedHashMap<>();
|
||||
|
||||
for (String soul : source.keySet())
|
||||
nodes.put(soul, new Node(source.getJSONObject(soul)));
|
||||
}
|
||||
|
||||
public MemoryBackend() {
|
||||
nodes = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public Node getNode(String soul) {
|
||||
return nodes.getOrDefault(soul, null);
|
||||
}
|
||||
|
||||
public void addNode(String soul, Node incomingNode) {
|
||||
nodes.put(soul, incomingNode);
|
||||
}
|
||||
|
||||
public boolean hasNode(String soul) {
|
||||
return nodes.containsKey(soul);
|
||||
}
|
||||
|
||||
public Set<Map.Entry<String, Node>> entries() {
|
||||
return nodes.entrySet();
|
||||
}
|
||||
|
||||
public Collection<Node> nodes() { return nodes.values(); }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
for(Map.Entry<String, Node> entry : nodes.entrySet()) {
|
||||
jsonObject.put(entry.getKey(), entry.getValue().toJSONObject());
|
||||
}
|
||||
return jsonObject.toString();
|
||||
}
|
||||
|
||||
public String toPrettyString() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
for(Map.Entry<String, Node> entry : nodes.entrySet()) {
|
||||
jsonObject.put(entry.getKey(), entry.getValue().toJSONObject());
|
||||
}
|
||||
return jsonObject.toString(2);
|
||||
}
|
||||
|
||||
public JSONObject toJSONObject() {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
for(Map.Entry<String, Node> entry : nodes.entrySet()) {
|
||||
jsonObject.put(entry.getKey(), entry.getValue().toJSONObject());
|
||||
}
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return nodes.isEmpty();
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package io.github.chronosx88.GunJava.storageBackends;
|
||||
|
||||
import io.github.chronosx88.GunJava.Node;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface StorageBackend {
|
||||
Node getNode(String soul);
|
||||
void addNode(String soul, Node node);
|
||||
boolean hasNode(String soul);
|
||||
Set<Map.Entry<String, Node>> entries();
|
||||
Collection<Node> nodes();
|
||||
String toString();
|
||||
String toPrettyString();
|
||||
JSONObject toJSONObject();
|
||||
boolean isEmpty();
|
||||
}
|
@ -46,13 +46,6 @@ public class Dispatcher {
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void sendGetRequest(String key) {
|
||||
new Thread(() -> {
|
||||
JSONObject jsonGet = Utils.formatGetRequest(key, null);
|
||||
peer.emit(jsonGet.toString());
|
||||
}).start();
|
||||
}
|
||||
|
||||
public void sendGetRequest(String key, String field) {
|
||||
new Thread(() -> {
|
||||
JSONObject jsonGet = Utils.formatGetRequest(key, field);
|
||||
|
@ -1,10 +1,13 @@
|
||||
package io.github.chronosx88.JGUN;
|
||||
|
||||
import io.github.chronosx88.JGUN.futures.builders.GetBuilder;
|
||||
import io.github.chronosx88.JGUN.futures.FutureGet;
|
||||
import io.github.chronosx88.JGUN.futures.builders.PutBuilder;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class PathRef {
|
||||
private final ArrayList<String> path = new ArrayList<>();
|
||||
@ -19,8 +22,50 @@ public class PathRef {
|
||||
return this;
|
||||
}
|
||||
|
||||
public GetBuilder getData() {
|
||||
return new GetBuilder(path);
|
||||
public FutureGet getData() {
|
||||
FutureGet futureGet = new FutureGet(Dup.random());
|
||||
Iterator<String> iterator = path.iterator();
|
||||
new Thread(() -> {
|
||||
CompletableFuture<JSONObject> future = CompletableFuture.supplyAsync(() -> {
|
||||
String rootSoul = iterator.next();
|
||||
String field = iterator.hasNext() ? iterator.next() : null;
|
||||
FutureGet futureGetRootSoul = new FutureGet(Dup.random());
|
||||
dispatcher.addPendingFuture(futureGetRootSoul);
|
||||
dispatcher.sendGetRequest(rootSoul, field);
|
||||
futureGetRootSoul.awaitUninterruptibly();
|
||||
if(futureGetRootSoul.isSuccess() && futureGetRootSoul.getData() != null) {
|
||||
return futureGetRootSoul.getData();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
while(iterator.hasNext()) {
|
||||
future = future.thenApply(jsonObject -> {
|
||||
String soul = iterator.next();
|
||||
String field = iterator.hasNext() ? iterator.next() : null;
|
||||
if(jsonObject != null) {
|
||||
String nodeRef = jsonObject.getJSONObject(soul).getString("#");
|
||||
FutureGet get = new FutureGet(Dup.random());
|
||||
dispatcher.addPendingFuture(get);
|
||||
dispatcher.sendGetRequest(nodeRef, field);
|
||||
get.awaitUninterruptibly();
|
||||
if(get.isSuccess() && get.getData() != null) {
|
||||
return get.getData();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
try {
|
||||
JSONObject data = future.get();
|
||||
futureGet.done(data);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
return futureGet;
|
||||
}
|
||||
|
||||
public PutBuilder put(JSONObject data) {
|
||||
|
@ -28,14 +28,17 @@ public class FutureGet extends BaseFuture<FutureGet> {
|
||||
|
||||
public FutureGet done(JSONObject data) {
|
||||
synchronized (lock) {
|
||||
if(!data.isEmpty()) {
|
||||
this.getStatus = GetStatus.OK;
|
||||
this.type = FutureType.OK;
|
||||
if(data != null) {
|
||||
if (!data.isEmpty()) {
|
||||
this.getStatus = GetStatus.OK;
|
||||
this.type = FutureType.OK;
|
||||
}
|
||||
} else {
|
||||
this.getStatus = GetStatus.NOT_FOUND;
|
||||
this.type = FutureType.FAILED;
|
||||
this.reason = "Not found";
|
||||
}
|
||||
|
||||
this.data = data;
|
||||
if (!completedAndNotify()) {
|
||||
return this;
|
||||
|
@ -1,11 +0,0 @@
|
||||
package io.github.chronosx88.JGUN.futures.builders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GetBuilder {
|
||||
private final ArrayList<String> path;
|
||||
|
||||
public GetBuilder(ArrayList<String> path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user