diff --git a/jcwdb.iml b/jcwdb.iml
deleted file mode 100644
index 78b2cc5..0000000
--- a/jcwdb.iml
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/src/main/java/org/warp/jcwdb/AdvancedSaveable.java b/src/main/java/org/warp/jcwdb/AdvancedSaveable.java
deleted file mode 100644
index 991edc2..0000000
--- a/src/main/java/org/warp/jcwdb/AdvancedSaveable.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package org.warp.jcwdb;
-
-public interface AdvancedSaveable extends Saveable {
- public void save(boolean isEditFinished);
-}
diff --git a/src/main/java/org/warp/jcwdb/Editable.java b/src/main/java/org/warp/jcwdb/Editable.java
new file mode 100644
index 0000000..82008dc
--- /dev/null
+++ b/src/main/java/org/warp/jcwdb/Editable.java
@@ -0,0 +1,60 @@
+package org.warp.jcwdb;
+
+import java.io.IOException;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public interface Editable {
+ /**
+ * Reccomended way to edit the value
+ *
+ * @param editFunction
+ * @throws IOException
+ */
+ void editValue(BiFunction editFunction);
+
+ /**
+ * Reccomended way to edit the value
+ * @param editFunction
+ * @throws IOException
+ */
+ void editValue(Function editFunction);
+
+ /**
+ * Reccomended way to edit the value
+ * @param editFunction
+ * @throws IOException
+ */
+ void editValue(BiConsumer editFunction);
+
+ /**
+ * Reccomended way to edit the value
+ * @param editFunction
+ * @throws IOException
+ */
+ void editValue(Consumer editFunction);
+
+ /**
+ * Reccomended way to view the value
+ * @param viewFunction
+ * @throws IOException
+ */
+ void viewValue(Consumer viewFunction);
+
+ /**
+ * Substitute the old value with a new one
+ * @param val
+ * @throws IOException
+ */
+ void setValue(T val);
+
+
+ /**
+ * DO NOT ATTEMPT TO MODIFY THE VALUE RETURNED
+ * @return
+ */
+ T getValueReadOnlyUnsafe();
+
+}
diff --git a/src/main/java/org/warp/jcwdb/EntryReference.java b/src/main/java/org/warp/jcwdb/EntryReference.java
index 6828080..2dc4a0b 100644
--- a/src/main/java/org/warp/jcwdb/EntryReference.java
+++ b/src/main/java/org/warp/jcwdb/EntryReference.java
@@ -10,7 +10,7 @@ import java.util.function.Function;
* You must have only a maximum of 1 reference for each index
* @param
*/
-public class EntryReference implements Castable, AdvancedSaveable {
+public class EntryReference implements Editable, Saveable, Castable {
private final JCWDatabase.EntryReferenceTools db;
private final long entryIndex;
private final DBTypeParser parser;
@@ -63,6 +63,10 @@ public class EntryReference implements Castable, AdvancedSaveable {
}
}
+ public boolean isClosed() {
+ return closed;
+ }
+
/**
* Note that this method won't be called when closing without saving
*/
@@ -70,21 +74,27 @@ public class EntryReference implements Castable, AdvancedSaveable {
this.save(false);
}
- public void save(boolean isEditFinished) {
+ public void saveAndFlush() {
+ this.save(true);
+ }
+
+ private void save(boolean flush) {
synchronized(accessLock) {
if (loaded && !closed) {
try {
- if (value instanceof AdvancedSaveable) {
- ((AdvancedSaveable)value).save(isEditFinished);
- } else if (value instanceof Saveable) {
- ((Saveable)value).save();
+ if (value instanceof Saveable) {
+ if (flush) {
+ ((Saveable)value).saveAndFlush();
+ } else {
+ ((Saveable)value).save();
+ }
}
IndexDetails returnedDetails = this.db.write(entryIndex, parser.getWriter(value));
synchronized(hashCacheLock) {
this.cachedHash = returnedDetails.getHash();
this.isHashCached = true;
}
- if (isEditFinished) {
+ if (flush) {
if (!isFlushingAllowed) {
this.db.setFlushingAllowed(entryIndex, true);
this.isFlushingAllowed = true;
@@ -149,6 +159,19 @@ public class EntryReference implements Castable, AdvancedSaveable {
}
}
+ /**
+ * Reccomended way to edit the value
+ * DO NOT EDIT THE VALUE
+ * @param viewFunction
+ * @throws IOException
+ */
+ public void viewValue(Consumer viewFunction) {
+ synchronized(accessLock) {
+ load();
+ viewFunction.accept(this.value);
+ }
+ }
+
/**
* Substitute the old value with a new one
* @param val
@@ -171,14 +194,14 @@ public class EntryReference implements Castable, AdvancedSaveable {
*/
@Deprecated()
public T getValue() {
- return getValueReadOnly();
+ return getValueReadOnlyUnsafe();
}
/**
* DO NOT ATTEMPT TO MODIFY THE VALUE RETURNED
* @return
*/
- public T getValueReadOnly() {
+ public T getValueReadOnlyUnsafe() {
synchronized(accessLock) {
load();
return this.value;
diff --git a/src/main/java/org/warp/jcwdb/JCWDatabase.java b/src/main/java/org/warp/jcwdb/JCWDatabase.java
index c8c21d0..c38b57e 100644
--- a/src/main/java/org/warp/jcwdb/JCWDatabase.java
+++ b/src/main/java/org/warp/jcwdb/JCWDatabase.java
@@ -1,7 +1,11 @@
package org.warp.jcwdb;
+import java.io.IOError;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.function.Supplier;
public class JCWDatabase implements AutoCloseable, Cleanable {
public final static long MAX_LOADED_INDICES = 1000;
@@ -13,6 +17,7 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
private volatile boolean closed;
private final Object closeLock = new Object();
private final Object indicesAccessLock = new Object();
+ private final LinkedList> usedReferences = new LinkedList<>();
public JCWDatabase(Path dataFile, Path metadataFile) throws IOException {
this.typesManager = new TypesManager(this);
@@ -29,17 +34,31 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
this.databaseCleaner.start();
}
- public EntryReference> getRoot() throws IOException {
- checkClosed();
- if (exists(0)) {
- return get(0);
- } else {
- LightList newRoot = new LightBigList<>(this);
- return set(0, newRoot);
+ public EntryReference> getRoot() {
+ try {
+ checkClosed();
+ if (exists(0)) {
+ return get(0);
+ } else {
+ LightList newRoot = new LightBigList<>(this);
+ return set(0, newRoot);
+ }
+ } catch (IOException e) {
+ throw new IOError(e);
}
}
- public EntryReference> getRoot(Class clazz) throws IOException {
+ @SuppressWarnings("unchecked")
+ public EntryReference getRootItem(int index) {
+ return ((LightList) getRoot().getValueReadOnlyUnsafe()).getReference(index);
+ }
+
+ @SuppressWarnings("unchecked")
+ public EntryReference getRootItem(int index, Supplier defaultValue) {
+ return ((LightList) getRoot().getValueReadOnlyUnsafe()).getReferenceOrInitialize(index, defaultValue);
+ }
+
+ public EntryReference> getRoot(Class clazz) {
return getRoot().cast();
}
@@ -137,6 +156,14 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
@Override
public long clean() {
long removedItems = indices.clean();
+ Iterator> usedReferencesIterator = usedReferences.iterator();
+ while(usedReferencesIterator.hasNext()) {
+ EntryReference> entryReference = usedReferencesIterator.next();
+ if (entryReference.isClosed()) {
+ usedReferencesIterator.remove();
+ removedItems += 1;
+ }
+ }
return removedItems;
}
@@ -156,6 +183,10 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
public void setFlushingAllowed(long index, boolean isFlushingAllowed) {
indices.setFlushingAllowed(index, isFlushingAllowed);
}
+
+ public void setUsed(EntryReference ref) {
+ usedReferences.add(ref);
+ }
}
@SuppressWarnings("unchecked")
diff --git a/src/main/java/org/warp/jcwdb/LightArrayList.java b/src/main/java/org/warp/jcwdb/LightArrayList.java
index b65087f..83dcf93 100644
--- a/src/main/java/org/warp/jcwdb/LightArrayList.java
+++ b/src/main/java/org/warp/jcwdb/LightArrayList.java
@@ -48,7 +48,7 @@ public class LightArrayList implements LightList {
EntryReference ref = null;
try {
ref = db.get(element);
- if (o.equals(ref.getValueReadOnly())) {
+ if (o.equals(ref.getValueReadOnlyUnsafe())) {
return true;
}
} catch (IOException e) {
@@ -70,7 +70,7 @@ public class LightArrayList implements LightList {
final ArrayList elements = new ArrayList<>();
for (long element : internalList) {
try {
- elements.add((T) db.get(element).getValueReadOnly());
+ elements.add((T) db.get(element).getValueReadOnlyUnsafe());
} catch (IOException e) {
e.printStackTrace();
}
@@ -125,7 +125,7 @@ public class LightArrayList implements LightList {
final T[] elements = (T[]) new Object[internalList.size()];
for (int i = 0; i < elements.length; i++) {
try {
- T element = (T) db.get(internalList.getLong(i)).getValueReadOnly();
+ T element = (T) db.get(internalList.getLong(i)).getValueReadOnlyUnsafe();
elements[i] = element;
} catch (IOException e) {
e.printStackTrace();
@@ -140,7 +140,7 @@ public class LightArrayList implements LightList {
final T1[] elements = (T1[]) new Objects[internalList.size()];
for (int i = 0; i < elements.length; i++) {
try {
- elements[i] = (T1) db.get(internalList.getLong(i)).getValueReadOnly();
+ elements[i] = (T1) db.get(internalList.getLong(i)).getValueReadOnlyUnsafe();
} catch (IOException e) {
e.printStackTrace();
}
@@ -265,7 +265,7 @@ public class LightArrayList implements LightList {
@SuppressWarnings("unchecked")
public T getReadOnlyValue(int index) {
try {
- return (T) db.get(internalList.getLong(index)).getValueReadOnly();
+ return (T) db.get(internalList.getLong(index)).getValueReadOnlyUnsafe();
} catch (IOException e) {
e.printStackTrace();
return null;
@@ -289,7 +289,7 @@ public class LightArrayList implements LightList {
long oldIndex = internalList.set(index, ref.getIndex());
try {
ref.close();
- return ((EntryReference) (db.get(oldIndex))).getValueReadOnly();
+ return ((EntryReference) (db.get(oldIndex))).getValueReadOnlyUnsafe();
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
@@ -306,7 +306,7 @@ public class LightArrayList implements LightList {
public T remove(int index) {
long oldIndex = internalList.removeLong(index);
try {
- return ((EntryReference) (db.get(oldIndex))).getValueReadOnly();
+ return ((EntryReference) (db.get(oldIndex))).getValueReadOnlyUnsafe();
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
@@ -340,7 +340,7 @@ public class LightArrayList implements LightList {
long index = internalList.getLong(i);
try {
EntryReference> ref2 = db.get(index);
- if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) {
+ if (ref.getValueReadOnlyUnsafe().equals(ref2.getValueReadOnlyUnsafe())) {
return i;
}
} catch (IOException e) {
@@ -372,7 +372,7 @@ public class LightArrayList implements LightList {
try {
EntryReference> ref2 = db.get(index2);
if (objToRemoveHash == ref2.calculateHash()) {
- if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) {
+ if (ref.getValueReadOnlyUnsafe().equals(ref2.getValueReadOnlyUnsafe())) {
lastValue = i;
}
}
@@ -431,7 +431,7 @@ public class LightArrayList implements LightList {
for (int i = 0; i < internalList.size(); ) {
T obj;
try {
- obj = ((EntryReference) (db.get(internalList.getLong(i)).cast())).getValueReadOnly();
+ obj = ((EntryReference) (db.get(internalList.getLong(i)).cast())).getValueReadOnlyUnsafe();
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
diff --git a/src/main/java/org/warp/jcwdb/LightBigList.java b/src/main/java/org/warp/jcwdb/LightBigList.java
index 85d68bc..915e6a4 100644
--- a/src/main/java/org/warp/jcwdb/LightBigList.java
+++ b/src/main/java/org/warp/jcwdb/LightBigList.java
@@ -4,11 +4,11 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
-import java.io.IOError;
import java.io.IOException;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.function.Supplier;
public class LightBigList implements LightList, Saveable {
@@ -65,7 +65,7 @@ public class LightBigList implements LightList, Saveable {
} catch (IOException ex) {
throw (NullPointerException) new NullPointerException().initCause(ex);
}
- this.cachedChunk = this.cachedChunkRef.getValueReadOnly();
+ this.cachedChunk = this.cachedChunkRef.getValueReadOnlyUnsafe();
}
/**
@@ -134,7 +134,7 @@ public class LightBigList implements LightList, Saveable {
for (long chunkIndex : chunks) {
try {
EntryReference> chunkRef = db.get(chunkIndex);
- LightArrayList chunk = chunkRef.getValueReadOnly();
+ LightArrayList chunk = chunkRef.getValueReadOnlyUnsafe();
if (chunk.contains(o)) {
return true;
}
@@ -211,7 +211,7 @@ public class LightBigList implements LightList, Saveable {
try {
EntryReference> chunkRef = db.get(chunkIndex);
- LightArrayList chunk = chunkRef.getValueReadOnly();
+ LightArrayList chunk = chunkRef.getValueReadOnlyUnsafe();
for (int i1 = 0; i1 < chunk.size(); i1++) {
result[(int)(chunkStartOffset + i1)] = chunk.get(i);
}
@@ -378,7 +378,7 @@ public class LightBigList implements LightList, Saveable {
@SuppressWarnings("unchecked")
public T getReadOnlyValue(int index) {
try {
- return (T) db.get(chunks.getLong(index)).getValueReadOnly();
+ return (T) db.get(chunks.getLong(index)).getValueReadOnlyUnsafe();
} catch (IOException e) {
e.printStackTrace();
return null;
@@ -387,10 +387,26 @@ public class LightBigList implements LightList, Saveable {
@Override
public EntryReference getReference(int index) {
+ return getReferenceUnsafe(index, true);
+ }
+
+ @Override
+ public EntryReference getReferenceOrInitialize(int index, Supplier initializer) {
+ EntryReference value = getReferenceUnsafe(index, false);
+ if (value != null) {
+ return value;
+ } else {
+ T initializedData = initializer.get();
+ EntryReference initializedDataRef = addToDatabase(initializedData);
+ return set(index, initializedDataRef);
+ }
+ }
+
+ private EntryReference getReferenceUnsafe(int index, boolean throwError) {
try {
return db.get(chunks.getLong(index)).cast();
} catch (IOException e) {
- e.printStackTrace();
+ if (throwError) e.printStackTrace();
return null;
}
}
@@ -398,8 +414,14 @@ public class LightBigList implements LightList, Saveable {
@SuppressWarnings("unchecked")
@Override
public T set(int setOffset, final T element) {
+ return set(setOffset, addToDatabase(element)).getValueReadOnlyUnsafe();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public EntryReference set(int setOffset, final EntryReference element) {
long nextChunkOffset = 0;
- VariableWrapper wrapper = new VariableWrapper<>(null);
+ VariableWrapper> wrapper = new VariableWrapper<>(null);
if (setOffset >= 0) {
// Iterate through all chunks
for (int i = 0; i < chunks.size(); i++) {
@@ -420,8 +442,7 @@ public class LightBigList implements LightList, Saveable {
try {
EntryReference> chunkRef = db.get(chunkIndex);
chunkRef.editValue((chunk) -> {
- chunk.set(relativeOffset, element);
- wrapper.var = element;
+ wrapper.var = chunk.set(relativeOffset, element);
});
} catch (IOException ex) {
throw (NullPointerException) new NullPointerException().initCause(ex);
@@ -463,7 +484,7 @@ public class LightBigList implements LightList, Saveable {
// Get chunk index
final long chunkIndex = chunks.getLong(i);
EntryReference> chunkRef = db.get(chunkIndex);
- final int foundIndex = chunkRef.getValueReadOnly().indexOfEntry(ref);
+ final int foundIndex = chunkRef.getValueReadOnlyUnsafe().indexOfEntry(ref);
if (foundIndex >= 0) {
return currentOffset + foundIndex;
}
@@ -492,7 +513,7 @@ public class LightBigList implements LightList, Saveable {
// Get chunk index
final long chunkIndex = chunks.getLong(i);
EntryReference> chunkRef = db.get(chunkIndex);
- final int foundIndex = chunkRef.getValueReadOnly().lastIndexOfEntry(ref);
+ final int foundIndex = chunkRef.getValueReadOnlyUnsafe().lastIndexOfEntry(ref);
if (foundIndex >= 0) {
return currentOffset + foundIndex;
}
@@ -578,4 +599,9 @@ public class LightBigList implements LightList, Saveable {
this.cachedChunkRef.save();
}
}
+
+ @Override
+ public void saveAndFlush() {
+ save();
+ }
}
diff --git a/src/main/java/org/warp/jcwdb/LightList.java b/src/main/java/org/warp/jcwdb/LightList.java
index 9c699ba..1f9fc7d 100644
--- a/src/main/java/org/warp/jcwdb/LightList.java
+++ b/src/main/java/org/warp/jcwdb/LightList.java
@@ -3,6 +3,7 @@ package org.warp.jcwdb;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
+import java.util.function.Supplier;
public interface LightList extends List {
@@ -12,10 +13,14 @@ public interface LightList extends List {
EntryReference addEntry(T o);
+ EntryReference set(int setOffset, final EntryReference element);
+
boolean remove(EntryReference ref);
EntryReference getReference(int index);
+ EntryReference getReferenceOrInitialize(int index, Supplier initializer);
+
int indexOfEntry(EntryReference ref);
int lastIndexOfEntry(EntryReference ref);
diff --git a/src/main/java/org/warp/jcwdb/Saveable.java b/src/main/java/org/warp/jcwdb/Saveable.java
index 385ee18..b8fcffb 100644
--- a/src/main/java/org/warp/jcwdb/Saveable.java
+++ b/src/main/java/org/warp/jcwdb/Saveable.java
@@ -3,5 +3,6 @@ package org.warp.jcwdb;
import java.io.IOException;
public interface Saveable {
- public void save();
+ void save();
+ void saveAndFlush();
}
diff --git a/src/main/java/org/warp/jcwdb/exampleimpl/App.java b/src/main/java/org/warp/jcwdb/exampleimpl/App.java
index b9cfe2f..60f9a49 100644
--- a/src/main/java/org/warp/jcwdb/exampleimpl/App.java
+++ b/src/main/java/org/warp/jcwdb/exampleimpl/App.java
@@ -63,7 +63,7 @@ public class App {
System.out.println("Retrieving items...");
root.forEachReference((valueReference) -> {
- Animal value = valueReference.getValueReadOnly();
+ Animal value = valueReference.getValueReadOnlyUnsafe();
if (Animal.hasFourLegs(value)) {
results.add(value);
}