diff --git a/build.gradle b/build.gradle index 5df0cb4..463c337 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group = 'com.nucleodb' -version = '1.12.3' +version = '1.13.0' repositories { mavenCentral() diff --git a/src/main/java/com/nucleodb/library/NucleoDB.java b/src/main/java/com/nucleodb/library/NucleoDB.java index a9fc4c3..ba67acf 100644 --- a/src/main/java/com/nucleodb/library/NucleoDB.java +++ b/src/main/java/com/nucleodb/library/NucleoDB.java @@ -1,11 +1,13 @@ package com.nucleodb.library; +import com.nucleodb.library.database.index.TreeIndex; import com.nucleodb.library.database.modifications.Create; import com.nucleodb.library.database.tables.annotation.Conn; import com.nucleodb.library.database.tables.connection.ConnectionConfig; import com.nucleodb.library.database.tables.connection.ConnectionHandler; -import com.nucleodb.library.database.tables.annotation.Index; +import com.nucleodb.library.database.index.annotation.Index; import com.nucleodb.library.database.tables.annotation.Table; +import com.nucleodb.library.database.tables.table.DataTableConfig; import com.nucleodb.library.database.utils.TreeSetExt; import com.nucleodb.library.database.utils.exceptions.IncorrectDataEntryClassException; import com.nucleodb.library.database.utils.exceptions.MissingDataEntryConstructorsException; @@ -127,7 +129,7 @@ private void startTables(String bootstrap, String[] packagesToScan, DBType dbTyp Set> tableTypes = tableTypesOptional.get(); CountDownLatch latch = new CountDownLatch(tableTypes.size()); Set tables = new TreeSetExt<>(); - Map> indexes = new TreeMap<>(); + Map> indexes = new TreeMap<>(); for (Class type : tableTypes) { Table tableAnnotation = type.getAnnotation(Table.class); String tableName = tableAnnotation.tableName(); @@ -181,14 +183,14 @@ public void run(DataTable table) { } } - private Set processIndexListForClass(Class clazz) { - Set indexes = new TreeSet<>(); + private Set processIndexListForClass(Class clazz) { + Set indexes = new TreeSet<>(); getAllAnnotatedFields(clazz, Index.class, "").forEach(field->{ if (field.getAnnotation().value().isEmpty()) { - indexes.add(field.getPath()); + indexes.add(new DataTableConfig.IndexConfig(field.getPath(), field.getAnnotation().type()) ); } else { - indexes.add(field.getAnnotation().value()); + indexes.add(new DataTableConfig.IndexConfig(field.getAnnotation().value(), field.getAnnotation().type())); } }); return indexes; diff --git a/src/main/java/com/nucleodb/library/database/tables/table/index/Index.java b/src/main/java/com/nucleodb/library/database/index/IndexWrapper.java similarity index 80% rename from src/main/java/com/nucleodb/library/database/tables/table/index/Index.java rename to src/main/java/com/nucleodb/library/database/index/IndexWrapper.java index c70362a..cd29077 100644 --- a/src/main/java/com/nucleodb/library/database/tables/table/index/Index.java +++ b/src/main/java/com/nucleodb/library/database/index/IndexWrapper.java @@ -1,4 +1,4 @@ -package com.nucleodb.library.database.tables.table.index; +package com.nucleodb.library.database.index; import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.collect.Queues; @@ -15,17 +15,21 @@ import java.util.Queue; import java.util.Set; -public abstract class Index implements Serializable{ +public abstract class IndexWrapper implements Serializable{ private static final long serialVersionUID = 1; String indexedKeyStr; - public Index(String indexedKey) { + public IndexWrapper(String indexedKey) { this.indexedKeyStr = indexedKey; } - - - public List getIndexValue(DataEntry dataEntry) throws JsonProcessingException { - return getValues(Queues.newConcurrentLinkedQueue(Arrays.asList(this.indexedKeyStr.split("\\."))), dataEntry.getData()); + public List getIndexValue(T object) throws JsonProcessingException { + Object obj; + if(object instanceof DataEntry){ + obj = ((DataEntry) object).getData(); + }else{ + obj = object; + } + return getValues(Queues.newConcurrentLinkedQueue(Arrays.asList(this.indexedKeyStr.split("\\."))), object); /*String json = dataEntry.getReference().toString(); try (JsonReader reader = Json.createReader(new StringReader(json))) { System.out.println(json); @@ -86,28 +90,28 @@ public List getValues(Queue pointer, Object start) throws JsonPr } - public void add(DataEntry dataEntry) throws JsonProcessingException { + public void add(T dataEntry) throws JsonProcessingException { System.out.println("Add ERROR"); } - public void delete(DataEntry dataEntry) { + public void delete(T dataEntry) { System.out.println("Delete ERROR"); } - public void modify(DataEntry dataEntry) throws JsonProcessingException { + public void modify(T dataEntry) throws JsonProcessingException { System.out.println("Modify ERROR"); } - public Set get(Object search){ + public Set get(Object search){ return null; } - public Set getNotEqual(Object notEqualVal) { + public Set getNotEqual(Object notEqualVal) { return null; } - public Set search(Object searchObj) { + public Set contains(Object searchObj) { return null; } diff --git a/src/main/java/com/nucleodb/library/database/tables/table/index/TreeIndex.java b/src/main/java/com/nucleodb/library/database/index/TreeIndex.java similarity index 67% rename from src/main/java/com/nucleodb/library/database/tables/table/index/TreeIndex.java rename to src/main/java/com/nucleodb/library/database/index/TreeIndex.java index 40eac4d..e631030 100644 --- a/src/main/java/com/nucleodb/library/database/tables/table/index/TreeIndex.java +++ b/src/main/java/com/nucleodb/library/database/index/TreeIndex.java @@ -1,4 +1,4 @@ -package com.nucleodb.library.database.tables.table.index; +package com.nucleodb.library.database.index; import com.fasterxml.jackson.core.JsonProcessingException; import com.nucleodb.library.database.tables.table.DataEntry; @@ -6,13 +6,13 @@ import java.io.Serializable; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.SortedMap; import java.util.TreeMap; import java.util.TreeSet; -public class TreeIndex extends Index implements Serializable{ +public class TreeIndex extends IndexWrapper implements Serializable{ private static final long serialVersionUID = 1; public TreeIndex() { super(null); @@ -21,8 +21,8 @@ public TreeIndex() { private boolean unique; - private Map>> reverseMap = new TreeMap<>(); - private Map> index = new TreeMap<>(); + private TreeMap>> reverseMap = new TreeMap<>(); + private TreeMap> index = new TreeMap<>(); public TreeIndex(String indexedKey) { @@ -33,11 +33,11 @@ public TreeIndex(String indexedKey) { @Override - public void add(DataEntry dataEntry) throws JsonProcessingException { + public void add(T dataEntry) throws JsonProcessingException { List values = getIndexValue(dataEntry); //System.out.println(Serializer.getObjectMapper().getOm().writeValueAsString(values)); values.forEach(val->{ - Set entries; + Set entries; synchronized (index) { entries = index.get(val); if (entries == null) { @@ -46,7 +46,7 @@ public void add(DataEntry dataEntry) throws JsonProcessingException { } } entries.add(dataEntry); - Set> rMap; + Set> rMap; synchronized (reverseMap) { rMap = reverseMap.get(dataEntry); if (rMap == null) { @@ -61,9 +61,9 @@ public void add(DataEntry dataEntry) throws JsonProcessingException { } @Override - public void delete(DataEntry dataEntry) { + public void delete(T dataEntry) { //System.out.println("Delete "+dataEntry); - Set> i = reverseMap.get(dataEntry); + Set> i = reverseMap.get(dataEntry); if(i!=null) i.forEach(c -> c.remove(dataEntry)); reverseMap.remove(dataEntry); @@ -71,14 +71,14 @@ public void delete(DataEntry dataEntry) { } @Override - public void modify(DataEntry dataEntry) throws JsonProcessingException { + public void modify(T dataEntry) throws JsonProcessingException { //System.out.println("Modify, "+ this.getIndexedKey() + " = " +dataEntry); delete(dataEntry); add(dataEntry); } @Override - public Set get(Object search) { + public Set get(Object search) { Optional optionalO = index.keySet().stream().findFirst(); if(optionalO.isPresent()) { Object o = optionalO.get(); @@ -102,7 +102,7 @@ public Set get(Object search) { @Override - public Set search(Object searchObj) { + public Set contains(Object searchObj) { return index.keySet().stream().filter(key->{ if(key instanceof String && searchObj instanceof String){ return ((String) key).contains((String)searchObj); @@ -114,20 +114,45 @@ public Set search(Object searchObj) { return a; }); } + Set reduce(SortedMap> objectSetSortedMap){ + return objectSetSortedMap.entrySet() + .stream() + .map(c->c.getValue()).reduce(new TreeSetExt<>(), (a,b)->{ + a.addAll(b); + return a; + }); + } + + public Set lessThan(Object searchObj) { + return reduce(index.headMap(searchObj)); + } + + public Set lessThanEqualTo(Object searchObj) { + return reduce(index.headMap(searchObj, true)); + } + + public Set greaterThan(Object searchObj) { + return reduce(index.tailMap(searchObj)); + } + + public Set greaterThanEqual(Object searchObj) { + return reduce(index.tailMap(searchObj, true)); + } + - public Map>> getReverseMap() { + public TreeMap>> getReverseMap() { return reverseMap; } - public void setReverseMap(Map>> reverseMap) { + public void setReverseMap(TreeMap>> reverseMap) { this.reverseMap = reverseMap; } - public Map> getIndex() { + public TreeMap> getIndex() { return index; } - public void setIndex(Map> index) { + public void setIndex(TreeMap> index) { this.index = index; } diff --git a/src/main/java/com/nucleodb/library/database/index/TrieIndex.java b/src/main/java/com/nucleodb/library/database/index/TrieIndex.java new file mode 100644 index 0000000..f367c98 --- /dev/null +++ b/src/main/java/com/nucleodb/library/database/index/TrieIndex.java @@ -0,0 +1,244 @@ +package com.nucleodb.library.database.index; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.nucleodb.library.database.index.trie.Entry; +import com.nucleodb.library.database.index.trie.Node; +import com.nucleodb.library.database.index.trie.Root; +import com.nucleodb.library.database.tables.connection.Connection; +import com.nucleodb.library.database.tables.table.DataEntry; + +import java.util.LinkedList; +import java.util.List; +import java.util.PrimitiveIterator; +import java.util.Set; +import java.util.Stack; +import java.util.TreeMap; +import java.util.stream.Collectors; + +public class TrieIndex extends IndexWrapper{ + Root[] rootPartialNodes = new Root[256]; + Node root = new Node(0); + + TreeMap entries = new TreeMap<>(); + + public TrieIndex(String indexedKey) { + super(indexedKey); + } + + void addRoot(Node n) { + if (rootPartialNodes[n.getCharacter()] == null) { + rootPartialNodes[n.getCharacter()] = new Root(); + } + rootPartialNodes[n.getCharacter()].add(n); + } + + Node getNodeFromIntBuffer(TreeMap treeMap, int character) { + try { + return treeMap.get(character); + } catch (Exception e) { + return null; + } + } + + @Override + public void add(T obj) throws JsonProcessingException { + for (Object o : getIndexValue(obj)) { + if(o instanceof String){ + insert(obj, (String) o); + } + } + } + + @Override + public void modify(T obj) throws JsonProcessingException { + String key = getKey(obj); + Entry entry = entries.get(key); + if(entry!=null) { + delete(entry); + for (Object o : getIndexValue(obj)) { + if (o instanceof String) { + insert(obj, (String) o); + } + } + } + } + + @Override + public Set get(Object search) { + if(search instanceof String) { + return searchData((String)search).stream().collect(Collectors.toSet()); + } + return (Set) Sets.newTreeSet(); + } + + @Override + public Set contains(Object searchStr) { + if(searchStr instanceof String) { + return partialData((String) searchStr); + } + return (Set) Sets.newTreeSet(); + } + + String getKey(T obj){ + String key = null; + if(obj instanceof DataEntry){ + key = ((DataEntry) obj).getKey(); + }else if(obj instanceof Connection){ + key = ((Connection) obj).getUuid(); + } + return key; + } + public void update(Entry entry, String newString){ + delete(entry); + insert(entry, newString); + } + public void delete(T obj){ + String key = getKey(obj); + if(key!=null){ + Entry entry = entries.get(key); + if(entry!=null) delete(entry); + } + } + public void delete(Entry entry){ + if(entry!=null){ + Stack stack = entry.getLastNodes(); + Node tmp; + while(!stack.isEmpty()){ + Node leaf = stack.lastElement(); + tmp = leaf; + while(tmp!=null) { + tmp.getEntries().remove(entry); + tmp.getPartialEntries().remove(entry); + if (tmp.getPartialEntries().isEmpty() && tmp.getEntries().isEmpty()) { + if (tmp.getParent() != null) { + tmp.getParent().getNodes().remove(tmp.getCharacter()); + } + } + tmp = tmp.getParent(); + } + stack.remove(leaf); + } + entries.remove(getKey((T)entry.getData())); + } + } + + public void insert(T obj, String val) { + Entry entry = new Entry(obj, new Stack<>()); + insert(entry, val); + } + + public void insert(Entry entry, String val) { + String key = getKey((T)entry.getData()); + PrimitiveIterator.OfInt iterator = val.chars().iterator(); + Node tmp = this.root; + Stack nodePath = entry.getLastNodes(); + while (iterator.hasNext()) { + int character = iterator.next(); + Node nodeTraversal = getNodeFromIntBuffer(tmp.getNodes(), character); + if (nodeTraversal == null) { + nodeTraversal = new Node(character); + nodeTraversal.setParent(tmp); + tmp.getNodes().put(character, nodeTraversal); + + this.addRoot(nodeTraversal); + } + tmp = nodeTraversal; + tmp.getPartialEntries().add(entry); + } + nodePath.add(tmp); // add leaf + entries.put(key, entry); + tmp.getEntries().add(entry); + } + + public Set searchData(String findString) { + return search(findString).stream().map(e->(T)e.getData()).collect(Collectors.toSet()); + } + public List search(String findString) { + PrimitiveIterator.OfInt iterator = findString.chars().iterator(); + Node tmp = this.root; + while (iterator.hasNext()) { + int character = iterator.next(); + Node nodeTmp = getNodeFromIntBuffer(tmp.getNodes(), character); + if (tmp.getNodes() != null && nodeTmp == null) { + tmp = null; + break; + } + tmp = nodeTmp; + } + if (tmp == null) { + return Lists.newLinkedList(); + } + return tmp.getEntries().stream().collect(Collectors.toList()); + } + + public Set partialData(String findString) { + return partial(findString).stream().map(e->(T)e.getData()).collect(Collectors.toSet()); + } + public List partial(String findString) { + LinkedList objects = Lists.newLinkedList(); + Root partialRoot = null; + int start = findString.charAt(0); + partialRoot = this.rootPartialNodes[start]; + if (partialRoot == null) + return objects; + char[] charArray = findString.toCharArray(); + partialRoot.getRoots().stream().forEach(r -> { + Node tmp = (Node) r; + for (int i = 1; i < charArray.length; i++) { + int character = charArray[i]; + Node nodeTmp = getNodeFromIntBuffer(tmp.getNodes(), character); + if (nodeTmp == null) { + tmp = null; + break; + } + tmp = nodeTmp; + } + if (tmp == null) return; + objects.addAll(tmp.getPartialEntries()); + }); + return objects.stream().distinct().collect(Collectors.toList()); + } + + public List endsWith(String findString) { + LinkedList objects = Lists.newLinkedList(); + Root partialRoot = null; + int start = findString.charAt(0); + partialRoot = this.rootPartialNodes[start]; + if (partialRoot == null) + return objects; + char[] charArray = findString.toCharArray(); + partialRoot.getRoots().stream().forEach(r -> { + Node tmp = (Node) r; + for (int i = 1; i < charArray.length; i++) { + int character = charArray[i]; + Node nodeTmp = getNodeFromIntBuffer(tmp.getNodes(), character); + if (nodeTmp == null) { + tmp = null; + break; + } + tmp = nodeTmp; + } + if (tmp == null) return; + objects.addAll(tmp.getEntries()); + }); + return objects.stream().distinct().collect(Collectors.toList()); + } + + public List startsWith(String findString) { + char[] charArray = findString.toCharArray(); + Node tmp = this.root; + for (int i = 0; i < charArray.length; i++) { + int character = charArray[i]; + Node nodeTmp = getNodeFromIntBuffer(tmp.getNodes(), character); + if (nodeTmp == null) { + tmp = null; + break; + } + tmp = nodeTmp; + } + if (tmp == null) return new LinkedList<>(); + return tmp.getPartialEntries().stream().collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/src/main/java/com/nucleodb/library/database/tables/annotation/Index.java b/src/main/java/com/nucleodb/library/database/index/annotation/Index.java similarity index 54% rename from src/main/java/com/nucleodb/library/database/tables/annotation/Index.java rename to src/main/java/com/nucleodb/library/database/index/annotation/Index.java index 6f40f70..d5922d3 100644 --- a/src/main/java/com/nucleodb/library/database/tables/annotation/Index.java +++ b/src/main/java/com/nucleodb/library/database/index/annotation/Index.java @@ -1,4 +1,7 @@ -package com.nucleodb.library.database.tables.annotation; +package com.nucleodb.library.database.index.annotation; + +import com.nucleodb.library.database.index.IndexWrapper; +import com.nucleodb.library.database.index.TreeIndex; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -9,4 +12,5 @@ @Target(ElementType.FIELD) public @interface Index { String value() default ""; + Class type() default TreeIndex.class; } \ No newline at end of file diff --git a/src/main/java/com/nucleodb/library/database/index/trie/Entry.java b/src/main/java/com/nucleodb/library/database/index/trie/Entry.java new file mode 100644 index 0000000..3c48eda --- /dev/null +++ b/src/main/java/com/nucleodb/library/database/index/trie/Entry.java @@ -0,0 +1,33 @@ +package com.nucleodb.library.database.index.trie; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import java.util.Stack; + +public class Entry{ + T data; + + Stack lastNodes; + + public Entry(T data, Stack nodes) { + this.data = data; + this.lastNodes = nodes; + } + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + @JsonIgnore + public Stack getLastNodes() { + return lastNodes; + } + + public void setLastNodes(Stack lastNodes) { + this.lastNodes = lastNodes; + } +} \ No newline at end of file diff --git a/src/main/java/com/nucleodb/library/database/index/trie/Node.java b/src/main/java/com/nucleodb/library/database/index/trie/Node.java new file mode 100644 index 0000000..be9188c --- /dev/null +++ b/src/main/java/com/nucleodb/library/database/index/trie/Node.java @@ -0,0 +1,43 @@ +package com.nucleodb.library.database.index.trie; + +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.TreeMap; + +public class Node{ + int character; + Node parent; + TreeMap nodes = new TreeMap<>(); + List entries = Lists.newLinkedList(); + List partialEntries = Lists.newLinkedList(); + + public Node(int character) { + this.character = character; + } + + public int getCharacter() { + return character; + } + + public TreeMap getNodes() { + return nodes; + } + + public Node getParent() { + return parent; + } + + public void setParent(Node parent) { + this.parent = parent; + } + + public List getEntries() { + return entries; + } + + public List getPartialEntries() { + return partialEntries; + } + +} \ No newline at end of file diff --git a/src/main/java/com/nucleodb/library/database/index/trie/Root.java b/src/main/java/com/nucleodb/library/database/index/trie/Root.java new file mode 100644 index 0000000..2820beb --- /dev/null +++ b/src/main/java/com/nucleodb/library/database/index/trie/Root.java @@ -0,0 +1,26 @@ +package com.nucleodb.library.database.index.trie; + +import com.google.common.collect.Lists; + +import java.util.List; + +public class Root { + List roots = Lists.newLinkedList(); + + public Root() { + } + + public void add(Node n){ + roots.add(n); + } + public void remove(Node n){ + roots.remove(n); + } + public List getRoots() { + return roots; + } + + public void setRoots(List roots) { + this.roots = roots; + } + } \ No newline at end of file diff --git a/src/main/java/com/nucleodb/library/database/tables/table/DataTable.java b/src/main/java/com/nucleodb/library/database/tables/table/DataTable.java index c74c505..9df024e 100644 --- a/src/main/java/com/nucleodb/library/database/tables/table/DataTable.java +++ b/src/main/java/com/nucleodb/library/database/tables/table/DataTable.java @@ -18,8 +18,8 @@ import com.nucleodb.library.database.utils.TreeSetExt; import com.nucleodb.library.database.utils.Utils; import com.nucleodb.library.database.utils.exceptions.IncorrectDataEntryObjectException; -import com.nucleodb.library.database.tables.table.index.Index; -import com.nucleodb.library.database.tables.table.index.TreeIndex; +import com.nucleodb.library.database.index.IndexWrapper; +import com.nucleodb.library.database.index.TreeIndex; import com.nucleodb.library.kafkaLedger.ConsumerHandler; import com.nucleodb.library.kafkaLedger.ProducerHandler; import org.apache.kafka.clients.admin.*; @@ -51,7 +51,7 @@ public class DataTable implements Serializable{ private Set entries = new TreeSetExt<>(); private DataTableConfig config; @JsonIgnore - private transient Map indexes = new TreeMap<>(); + private transient Map> indexes = new TreeMap<>(); private Set dataEntries = new TreeSetExt<>(); private Map keyToEntry = new TreeMap<>(); private Map partitionOffsets = new TreeMap<>(); @@ -115,7 +115,7 @@ public void loadSavedData() { this.partitionOffsets = tmpTable.partitionOffsets; this.keyToEntry = tmpTable.keyToEntry; this.entries.forEach(e -> { - for (Index i : this.indexes.values()) { + for (IndexWrapper i : this.indexes.values()) { try { i.add(e); } catch (JsonProcessingException ex) { @@ -193,7 +193,19 @@ public void createTopics() { public DataTable(DataTableConfig config) { this.config = config; - config.getIndexes().stream().map(i -> new TreeIndex(i)).collect(Collectors.toSet()).forEach(i -> { + config.getIndexes().stream().map(i -> { + try { + return i.getIndexType().getDeclaredConstructor(String.class).newInstance(i.getName()); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + }).collect(Collectors.toSet()).forEach(i -> { if (!this.indexes.containsKey(i.getIndexedKey())) { this.indexes.put(i.getIndexedKey(), i); } @@ -326,7 +338,7 @@ public Set search(String key, Object searchObject, DataEntryProjectio dataEntryProjection = new DataEntryProjection(); } try { - Stream process = dataEntryProjection.process(this.indexes.get(key).search(searchObject).stream()); + Stream process = dataEntryProjection.process(this.indexes.get(key).contains(searchObject).stream()); if(dataEntryProjection.isWritable()) { return process.map(de -> (DataEntry) de.copy(this.getConfig().getDataEntryClass())).collect(Collectors.toSet()); }else{ @@ -575,7 +587,7 @@ public void modify(Modification mod, Object modification) { entries.add(dataEntry); dataEntries.add(dataEntry); keyToEntry.put(dataEntry.getKey(), dataEntry); - for (Index i : this.indexes.values()) { + for (IndexWrapper i : this.indexes.values()) { try { i.add(dataEntry); } catch (JsonProcessingException e) { @@ -691,9 +703,9 @@ public void modify(Modification mod, Object modification) { case "copy": try { synchronized (entries) { - Index index = this.indexes.get(op.getPath()); - if (index != null) { - index.modify(de); + IndexWrapper indexWrapper = this.indexes.get(op.getPath()); + if (indexWrapper != null) { + indexWrapper.modify(de); } } } catch (JsonProcessingException e) { @@ -704,8 +716,8 @@ public void modify(Modification mod, Object modification) { break; case "remove": synchronized (entries) { - Index index = this.indexes.get(op.getPath()); - if (index != null) index.delete(de); + IndexWrapper indexWrapper = this.indexes.get(op.getPath()); + if (indexWrapper != null) indexWrapper.delete(de); } break; } @@ -809,11 +821,11 @@ public void setUnsavedIndexModifications(boolean unsavedIndexModifications) { this.unsavedIndexModifications = unsavedIndexModifications; } - public Map getIndexes() { + public Map> getIndexes() { return indexes; } - public void setIndexes(Map indexes) { + public void setIndexes(Map> indexes) { this.indexes = indexes; } diff --git a/src/main/java/com/nucleodb/library/database/tables/table/DataTableBuilder.java b/src/main/java/com/nucleodb/library/database/tables/table/DataTableBuilder.java index 431f964..763a50a 100644 --- a/src/main/java/com/nucleodb/library/database/tables/table/DataTableBuilder.java +++ b/src/main/java/com/nucleodb/library/database/tables/table/DataTableBuilder.java @@ -95,7 +95,7 @@ public DataTableBuilder setTableFileName(String tableFileName) { return this; } - public DataTableBuilder addIndexes(Set indexes) { + public DataTableBuilder addIndexes(Set indexes) { this.config.getIndexes().addAll(indexes); return this; } diff --git a/src/main/java/com/nucleodb/library/database/tables/table/DataTableConfig.java b/src/main/java/com/nucleodb/library/database/tables/table/DataTableConfig.java index 15c9119..fec9b20 100644 --- a/src/main/java/com/nucleodb/library/database/tables/table/DataTableConfig.java +++ b/src/main/java/com/nucleodb/library/database/tables/table/DataTableConfig.java @@ -1,6 +1,7 @@ package com.nucleodb.library.database.tables.table; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.nucleodb.library.database.index.IndexWrapper; import com.nucleodb.library.database.utils.StartupRun; import java.io.Serializable; @@ -11,6 +12,31 @@ public class DataTableConfig implements Serializable{ private static final long serialVersionUID = 4416983891804575837L; + public static class IndexConfig { + String name; + Class indexType; + + public IndexConfig(String name, Class indexType) { + this.name = name; + this.indexType = indexType; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Class getIndexType() { + return indexType; + } + + public void setIndexType(Class indexType) { + this.indexType = indexType; + } + } String bootstrap = "127.0.0.1:19092"; String table; @JsonIgnore @@ -22,7 +48,7 @@ public class DataTableConfig implements Serializable{ Class dataEntryClass; boolean read = true; boolean write = true; - Set indexes = new TreeSet<>(); + Set indexes = new TreeSet<>(); @JsonIgnore private transient StartupRun startupRun = null; @@ -68,7 +94,7 @@ public boolean isWrite() { return write; } - public Set getIndexes() { + public Set getIndexes() { return indexes; } @@ -109,7 +135,7 @@ public void setWrite(boolean write) { this.write = write; } - public void setIndexes(Set indexes) { + public void setIndexes(Set indexes) { this.indexes = indexes; } diff --git a/src/main/java/com/nucleodb/library/examples/anime/AnimeDTO.java b/src/main/java/com/nucleodb/library/examples/anime/AnimeDTO.java deleted file mode 100644 index 3c34e6c..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/AnimeDTO.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.nucleodb.library.examples.anime; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JacksonException; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.nucleodb.library.database.utils.sql.PrimaryKey; -import com.nucleodb.library.examples.anime.tables.nested.VoiceActor; - -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; -import java.util.stream.Collectors; - -public class AnimeDTO{ - public static class CustomActorNameDeserializer - extends StdDeserializer>{ - public CustomActorNameDeserializer() { - this(null); - } - public CustomActorNameDeserializer(Class vc) { - super(vc); - } - @Override - public List deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException, JacksonException { - List actorz = jsonparser.readValueAs(new TypeReference>(){}); - return actorz.stream().map(a-> a.getName()).collect(Collectors.toList()); - } - } - - @PrimaryKey - String uniqueKey; - @JsonProperty("name") - String name; - - @JsonProperty("actors") - @JsonDeserialize(using = CustomActorNameDeserializer.class) - List actors = new LinkedList<>(); - - @JsonProperty("rating") - Float rating; - - - - public AnimeDTO() { - } - - public String getUniqueKey() { - return uniqueKey; - } - - public void setUniqueKey(String uniqueKey) { - this.uniqueKey = uniqueKey; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getActors() { - return actors; - } - - public void setActors(List actors) { - this.actors = actors; - } - - public Float getRating() { - return rating; - } - - public void setRating(Float rating) { - this.rating = rating; - } -} diff --git a/src/main/java/com/nucleodb/library/examples/anime/AnimeTest.java b/src/main/java/com/nucleodb/library/examples/anime/AnimeTest.java deleted file mode 100644 index 362211f..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/AnimeTest.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.nucleodb.library.examples.anime; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.nucleodb.library.NucleoDB; -import com.nucleodb.library.database.tables.connection.Connection; -import com.nucleodb.library.database.tables.table.DataTable; -import com.nucleodb.library.database.utils.InvalidConnectionException; -import com.nucleodb.library.database.utils.Serializer; -import com.nucleodb.library.database.utils.exceptions.IncorrectDataEntryClassException; -import com.nucleodb.library.database.utils.exceptions.IncorrectDataEntryObjectException; -import com.nucleodb.library.database.utils.exceptions.MissingDataEntryConstructorsException; -import com.nucleodb.library.examples.anime.connections.WatchingConnection; -import com.nucleodb.library.examples.anime.definitions.UserDE; -import com.nucleodb.library.examples.anime.definitions.AnimeDE; -import com.nucleodb.library.examples.anime.tables.Anime; -import com.nucleodb.library.examples.anime.tables.User; -import com.nucleodb.library.examples.anime.tables.nested.VoiceActor; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.util.Set; -import java.util.TreeMap; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Logger; -import java.util.stream.Collectors; - - -public class AnimeTest{ - private static Logger logger = Logger.getLogger(DataTable.class.getName()); - static ObjectMapper om = new ObjectMapper().findAndRegisterModules(); - public static void main(String[] args) throws IOException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IncorrectDataEntryObjectException, IncorrectDataEntryClassException, MissingDataEntryConstructorsException { - NucleoDB nucleoDB = new NucleoDB( - "127.0.0.1:19092,127.0.0.1:29092,127.0.0.1:39092", - NucleoDB.DBType.ALL, - "com.nucleocore.library.negotiator.examples.anime", - "com.nucleocore.library.examples.anime.tables", - "com.nucleocore.library.examples.anime.connections" - ); - logger.info(String.format("indexes: %s",Serializer.getObjectMapper().getOm().writeValueAsString(nucleoDB.getTable(Anime.class).getIndexes()))); - logger.info(String.format("tables: %s", nucleoDB.getTables().keySet().stream().collect(Collectors.joining(", ")))); - logger.info(String.format("connections: %s", nucleoDB.getConnections().keySet().stream().collect(Collectors.joining(", ")))); - DataTable userTable = nucleoDB.getTable(User.class); - DataTable animeTable = nucleoDB.getTable(Anime.class); - logger.info("animes: "+animeTable.getEntries().size()); - logger.info("users: "+userTable.getEntries().size()); - - if(nucleoDB.getTables().size()==0){ - System.exit(1); - } - String userName = UUID.randomUUID().toString(); - String animeName = UUID.randomUUID().toString(); - int x=0; - while(x<100000) { - x++; - logger.info(om.writeValueAsString(animeTable.getEntries().size())); - logger.info("running "+x); - - Anime a = new Anime(); - a.setName(animeName); - a.getActors().add(new VoiceActor("Maaya Sakamoto")); - a.setOwner("firestar"); - - AtomicReference animeReference = new AtomicReference<>(); - animeTable.saveAsync(a, dataEntry -> { - if(dataEntry instanceof AnimeDE) { - animeReference.set((AnimeDE)dataEntry); - synchronized (animeReference) { - animeReference.notify(); - } - } - }); - try { - synchronized (animeReference) { - animeReference.wait(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - //logger.info(String.format("indexes: %s",Serializer.getObjectMapper().getOm().writeValueAsString(nucleoDB.getTable(Anime.class).getIndexes()))); - - - AtomicReference userReference = new AtomicReference<>(); - userTable.saveAsync(new User(userName, "me"), (dataEntry -> { - userReference.set((UserDE) dataEntry); - synchronized (userReference) { - userReference.notify(); - } - })); - try { - synchronized (userReference) { - userReference.wait(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - try { - String user = ((UserDE) userTable.getEntries().stream().findFirst().get()).getData().getUser(); - }catch (Exception e){ - e.printStackTrace(); - } - logger.info("returned anime class "+nucleoDB - .getTable(Anime.class) - .get("name", animeName, null) - .stream().map(AnimeDE.class::cast).findFirst().get().getData().getName()); - - if (userReference.get()!=null) { - try { - if (animeReference.get()!=null) { - nucleoDB.getConnectionHandler(WatchingConnection.class).saveSync(new WatchingConnection(userReference.get(), animeReference.get(), new TreeMap<>(){{ - put("time", "2.0402042"); - }})); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (InvalidConnectionException e) { - e.printStackTrace(); - } - - Set connectionOptional = nucleoDB.getConnectionHandler(WatchingConnection.class).getByFrom(userReference.get(), null); - if (connectionOptional.size() > 0) { - WatchingConnection connection = (WatchingConnection)connectionOptional.stream().findFirst().get(); - logger.info("connection found type is "+connection.getClass().getName()); - logger.info("anime name is "+connection.toEntry().getData().getName()); - connection.setTime(555.222f); - try { - nucleoDB.getConnectionHandler(WatchingConnection.class).saveSync(connection); - } catch (InvalidConnectionException e) { - throw new RuntimeException(e); - } - nucleoDB.getConnectionHandler(WatchingConnection.class).deleteSync(connectionOptional.stream().findFirst().get()); - } - - connectionOptional = nucleoDB.getConnectionHandler(WatchingConnection.class).getByFrom(userReference.get(), null); - if (connectionOptional.size() > 0) { - logger.info("connection failed to delete."); - logger.info("expect connection"+om.writeValueAsString(connectionOptional.stream().findFirst().get())); - } else { - logger.info("connection not found, successfully deleted connection."); - } - try { - animeTable.deleteSync(animeReference.get()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - try { - userTable.deleteSync(userReference.get()); - } catch (InterruptedException e) { - e.printStackTrace(); - } - }else{ - logger.info("ERROR"); - System.exit(1); - } - Thread.sleep(1000); - } - - -// Set entries = nucleoDB.getTable("anime").get("name", "Zoku Owarimonogatari"); -// nucleoDB.getConnectionHandler().save(new Connection()); -// logger.info(entries); -// -// entries.retainAll(nucleoDB.getRelated(new DataEntry(), Anime.class)); -// logger.info(entries); - //}); - } -} diff --git a/src/main/java/com/nucleodb/library/examples/anime/connections/WatchingConnection.java b/src/main/java/com/nucleodb/library/examples/anime/connections/WatchingConnection.java deleted file mode 100644 index 172f11f..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/connections/WatchingConnection.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.nucleodb.library.examples.anime.connections; - -import com.nucleodb.library.database.tables.annotation.Conn; -import com.nucleodb.library.database.tables.connection.Connection; -import com.nucleodb.library.database.utils.SkipCopy; -import com.nucleodb.library.examples.anime.definitions.AnimeDE; -import com.nucleodb.library.examples.anime.definitions.UserDE; - -import java.util.Map; - -@Conn("WATCHING") -public class WatchingConnection extends Connection{ - @SkipCopy - private static final long serialVersionUID = 1; - public WatchingConnection() { - } - - public WatchingConnection(UserDE from, AnimeDE to) { - super(from, to); - } - - public WatchingConnection(UserDE from, AnimeDE to, Map metadata) { - super(from, to, metadata); - } - - private float time = 0f; - - public float getTime() { - return time; - } - - public void setTime(float time) { - this.time = time; - } -} diff --git a/src/main/java/com/nucleodb/library/examples/anime/definitions/AnimeDE.java b/src/main/java/com/nucleodb/library/examples/anime/definitions/AnimeDE.java deleted file mode 100644 index 44fa113..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/definitions/AnimeDE.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.nucleodb.library.examples.anime.definitions; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.nucleodb.library.database.modifications.Create; -import com.nucleodb.library.database.tables.table.DataEntry; -import com.nucleodb.library.examples.anime.tables.Anime; - -public class AnimeDE extends DataEntry{ - public AnimeDE(Anime obj) { - super(obj); - } - - public AnimeDE(Create create) throws ClassNotFoundException, JsonProcessingException { - super(create); - } - - public AnimeDE() { - } - - public AnimeDE(String key) { - super(key); - } - - @Override - public Anime getData() { - return (Anime) data; - } - - public void setData(Anime data) { - this.data = data; - } -} diff --git a/src/main/java/com/nucleodb/library/examples/anime/definitions/UserDE.java b/src/main/java/com/nucleodb/library/examples/anime/definitions/UserDE.java deleted file mode 100644 index 8bef11d..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/definitions/UserDE.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.nucleodb.library.examples.anime.definitions; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.nucleodb.library.database.modifications.Create; -import com.nucleodb.library.database.tables.table.DataEntry; -import com.nucleodb.library.examples.anime.tables.User; - -public class UserDE extends DataEntry{ - public UserDE(User obj) { - super(obj); - } - - public UserDE(Create create) throws ClassNotFoundException, JsonProcessingException { - super(create); - } - - public UserDE() { - } - - public UserDE(String key) { - super(key); - } -} diff --git a/src/main/java/com/nucleodb/library/examples/anime/tables/Anime.java b/src/main/java/com/nucleodb/library/examples/anime/tables/Anime.java deleted file mode 100644 index 39dbea7..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/tables/Anime.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.nucleodb.library.examples.anime.tables; - -import com.nucleodb.library.database.tables.annotation.Index; -import com.nucleodb.library.database.tables.annotation.Table; -import com.nucleodb.library.examples.anime.tables.nested.VoiceActor; -import com.nucleodb.library.examples.anime.definitions.AnimeDE; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -@Table(tableName = "anime", dataEntryClass = AnimeDE.class) -public class Anime implements Serializable{ - private static final long serialVersionUID = 1; - @Index() - String name; - List tags = new ArrayList<>(); - List actors = new ArrayList<>(); - String image; - - String owner; - - Float rating; - - List votes; - - public Anime() { - } - - public Anime(String name, List tags) { - this.name = name; - this.tags = tags; - } - - public Anime(String name, List tags, List actors) { - this.name = name; - this.tags = tags; - this.actors = actors; - } - - public Anime(String name, Float rating) { - this.name = name; - this.rating = rating; - } - - public Anime(String name, List tags, Float rating) { - this.name = name; - this.tags = tags; - this.rating = rating; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public List getTags() { - return tags; - } - - public void setTags(List tags) { - this.tags = tags; - } - - public String getImage() { - return image; - } - - public void setImage(String image) { - this.image = image; - } - - public List getActors() { - return actors; - } - - public void setActors(List actors) { - this.actors = actors; - } - - public Float getRating() { - return rating; - } - - public void setRating(Float rating) { - this.rating = rating; - } - - public List getVotes() { - return votes; - } - - public void setVotes(List votes) { - this.votes = votes; - } - - public String getOwner() { - return owner; - } - - public void setOwner(String owner) { - this.owner = owner; - } -} diff --git a/src/main/java/com/nucleodb/library/examples/anime/tables/User.java b/src/main/java/com/nucleodb/library/examples/anime/tables/User.java deleted file mode 100644 index 958509b..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/tables/User.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.nucleodb.library.examples.anime.tables; - - -import com.nucleodb.library.database.tables.annotation.Index; -import com.nucleodb.library.database.tables.annotation.Table; -import com.nucleodb.library.examples.anime.definitions.UserDE; -import com.nucleodb.library.examples.anime.tables.nested.UserNested; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - - -@Table(tableName= "user", dataEntryClass = UserDE.class) -public class User implements Serializable{ - private static final long serialVersionUID = 1; - - - @Index("name") - private String name; - - private UserNested nested; - - private List testingNested = new ArrayList<>(); - - private String user; - - public User() { - this.testingNested.add(new UserNested()); - } - - public User(User t) { - this.name = t.name; - this.user = t.user; - this.testingNested.add(new UserNested()); - } - - - public User(String name, String user) { - this.name = name; - this.user = user; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getUser() { - return user; - } - - public void setUser(String user) { - this.user = user; - } - - public List getTestingNested() { - return testingNested; - } - - public void setTestingNested(List testingNested) { - this.testingNested = testingNested; - } - - public UserNested getNested() { - return nested; - } - - public void setNested(UserNested nested) { - this.nested = nested; - } -} diff --git a/src/main/java/com/nucleodb/library/examples/anime/tables/nested/UserNested.java b/src/main/java/com/nucleodb/library/examples/anime/tables/nested/UserNested.java deleted file mode 100644 index ae45156..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/tables/nested/UserNested.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.nucleodb.library.examples.anime.tables.nested; - -import java.io.Serializable; - -public class UserNested implements Serializable{ - private static final long serialVersionUID = 1; - public UserNested() { - nestedValue = "woot"; - } - private String nestedValue; - - public String getNestedValue() { - return nestedValue; - } - - public void setNestedValue(String nestedValue) { - this.nestedValue = nestedValue; - } -} \ No newline at end of file diff --git a/src/main/java/com/nucleodb/library/examples/anime/tables/nested/VoiceActor.java b/src/main/java/com/nucleodb/library/examples/anime/tables/nested/VoiceActor.java deleted file mode 100644 index e36930e..0000000 --- a/src/main/java/com/nucleodb/library/examples/anime/tables/nested/VoiceActor.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.nucleodb.library.examples.anime.tables.nested; - -import com.nucleodb.library.database.tables.annotation.Index; - -import java.io.Serializable; -import java.util.List; - -public class VoiceActor implements Serializable{ - private static final long serialVersionUID = 1; - @Index - String name; - String character; - - List tags; - - public VoiceActor() { - } - - public VoiceActor(String name) { - this.name = name; - } - - public VoiceActor(String name, String character) { - this.name = name; - this.character = character; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getCharacter() { - return character; - } - - public void setCharacter(String character) { - this.character = character; - } - - public List getTags() { - return tags; - } - - public void setTags(List tags) { - this.tags = tags; - } -} diff --git a/src/main/java/com/nucleodb/library/utils/field/EqualityCheck.java b/src/main/java/com/nucleodb/library/utils/field/EqualityCheck.java new file mode 100644 index 0000000..bebfcfe --- /dev/null +++ b/src/main/java/com/nucleodb/library/utils/field/EqualityCheck.java @@ -0,0 +1,29 @@ +package com.nucleodb.library.utils.field; + +public class EqualityCheck{ + public static boolean areEqual(Object obj1, Object obj2) { + if (obj1 == null || obj2 == null) { + return obj1 == obj2; + } + + if (obj1 instanceof Byte && obj2 instanceof Byte) { + return (Byte) obj1 == (Byte) obj2; + } else if (obj1 instanceof Short && obj2 instanceof Short) { + return (Short) obj1 == (Short) obj2; + } else if (obj1 instanceof Integer && obj2 instanceof Integer) { + return (Integer) obj1 == (Integer) obj2; + } else if (obj1 instanceof Long && obj2 instanceof Long) { + return (Long) obj1 == (Long) obj2; + } else if (obj1 instanceof Float && obj2 instanceof Float) { + return (Float) obj1 == (Float) obj2; + } else if (obj1 instanceof Double && obj2 instanceof Double) { + return (Double) obj1 == (Double) obj2; + } else if (obj1 instanceof Character && obj2 instanceof Character) { + return (Character) obj1 == (Character) obj2; + } else if (obj1 instanceof Boolean && obj2 instanceof Boolean) { + return (Boolean) obj1 == (Boolean) obj2; + } else { + return obj1.equals(obj2); + } + } +}