Merge branch 'master' into origin/better
This commit is contained in:
commit
20dbb31ac4
@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4" />
|
@ -1,5 +0,0 @@
|
||||
package org.warp.jcwdb;
|
||||
|
||||
public interface AdvancedSaveable extends Saveable {
|
||||
public void save(boolean isEditFinished);
|
||||
}
|
60
src/main/java/org/warp/jcwdb/Editable.java
Normal file
60
src/main/java/org/warp/jcwdb/Editable.java
Normal file
@ -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<T> {
|
||||
/**
|
||||
* Reccomended way to edit the value
|
||||
*
|
||||
* @param editFunction
|
||||
* @throws IOException
|
||||
*/
|
||||
void editValue(BiFunction<T, Saveable, T> editFunction);
|
||||
|
||||
/**
|
||||
* Reccomended way to edit the value
|
||||
* @param editFunction
|
||||
* @throws IOException
|
||||
*/
|
||||
void editValue(Function<T, T> editFunction);
|
||||
|
||||
/**
|
||||
* Reccomended way to edit the value
|
||||
* @param editFunction
|
||||
* @throws IOException
|
||||
*/
|
||||
void editValue(BiConsumer<T, Saveable> editFunction);
|
||||
|
||||
/**
|
||||
* Reccomended way to edit the value
|
||||
* @param editFunction
|
||||
* @throws IOException
|
||||
*/
|
||||
void editValue(Consumer<T> editFunction);
|
||||
|
||||
/**
|
||||
* Reccomended way to view the value
|
||||
* @param viewFunction
|
||||
* @throws IOException
|
||||
*/
|
||||
void viewValue(Consumer<T> 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();
|
||||
|
||||
}
|
@ -10,7 +10,7 @@ import java.util.function.Function;
|
||||
* You must have only a maximum of 1 reference for each index
|
||||
* @param <T>
|
||||
*/
|
||||
public class EntryReference<T> implements Castable, AdvancedSaveable {
|
||||
public class EntryReference<T> implements Editable<T>, Saveable, Castable {
|
||||
private final JCWDatabase.EntryReferenceTools db;
|
||||
private final long entryIndex;
|
||||
private final DBTypeParser<T> parser;
|
||||
@ -63,6 +63,10 @@ public class EntryReference<T> 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<T> 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<T> implements Castable, AdvancedSaveable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reccomended way to edit the value
|
||||
* DO NOT EDIT THE VALUE
|
||||
* @param viewFunction
|
||||
* @throws IOException
|
||||
*/
|
||||
public void viewValue(Consumer<T> 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<T> 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;
|
||||
|
@ -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<EntryReference<?>> 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 <T> EntryReference<LightList<T>> getRoot() throws IOException {
|
||||
checkClosed();
|
||||
if (exists(0)) {
|
||||
return get(0);
|
||||
} else {
|
||||
LightList<T> newRoot = new LightBigList<>(this);
|
||||
return set(0, newRoot);
|
||||
public <T> EntryReference<LightList<T>> getRoot() {
|
||||
try {
|
||||
checkClosed();
|
||||
if (exists(0)) {
|
||||
return get(0);
|
||||
} else {
|
||||
LightList<T> newRoot = new LightBigList<>(this);
|
||||
return set(0, newRoot);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> EntryReference<LightList<T>> getRoot(Class<T> clazz) throws IOException {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> EntryReference<T> getRootItem(int index) {
|
||||
return ((LightList<T>) getRoot().getValueReadOnlyUnsafe()).getReference(index);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> EntryReference<T> getRootItem(int index, Supplier<T> defaultValue) {
|
||||
return ((LightList<T>) getRoot().getValueReadOnlyUnsafe()).getReferenceOrInitialize(index, defaultValue);
|
||||
}
|
||||
|
||||
public <T> EntryReference<LightList<T>> getRoot(Class<T> clazz) {
|
||||
return getRoot().cast();
|
||||
}
|
||||
|
||||
@ -137,6 +156,14 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
|
||||
@Override
|
||||
public long clean() {
|
||||
long removedItems = indices.clean();
|
||||
Iterator<EntryReference<?>> 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 <T> void setUsed(EntryReference<T> ref) {
|
||||
usedReferences.add(ref);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -48,7 +48,7 @@ public class LightArrayList<T> implements LightList<T> {
|
||||
EntryReference<T> 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<T> implements LightList<T> {
|
||||
final ArrayList<T> 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<T> implements LightList<T> {
|
||||
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<T> implements LightList<T> {
|
||||
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<T> implements LightList<T> {
|
||||
@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<T> implements LightList<T> {
|
||||
long oldIndex = internalList.set(index, ref.getIndex());
|
||||
try {
|
||||
ref.close();
|
||||
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnly();
|
||||
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnlyUnsafe();
|
||||
} catch (IOException e) {
|
||||
throw (NullPointerException) new NullPointerException().initCause(e);
|
||||
}
|
||||
@ -306,7 +306,7 @@ public class LightArrayList<T> implements LightList<T> {
|
||||
public T remove(int index) {
|
||||
long oldIndex = internalList.removeLong(index);
|
||||
try {
|
||||
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnly();
|
||||
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnlyUnsafe();
|
||||
} catch (IOException e) {
|
||||
throw (NullPointerException) new NullPointerException().initCause(e);
|
||||
}
|
||||
@ -340,7 +340,7 @@ public class LightArrayList<T> implements LightList<T> {
|
||||
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<T> implements LightList<T> {
|
||||
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<T> implements LightList<T> {
|
||||
for (int i = 0; i < internalList.size(); ) {
|
||||
T obj;
|
||||
try {
|
||||
obj = ((EntryReference<T>) (db.get(internalList.getLong(i)).cast())).getValueReadOnly();
|
||||
obj = ((EntryReference<T>) (db.get(internalList.getLong(i)).cast())).getValueReadOnlyUnsafe();
|
||||
} catch (IOException e) {
|
||||
throw (NullPointerException) new NullPointerException().initCause(e);
|
||||
}
|
||||
|
@ -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<T> implements LightList<T>, Saveable {
|
||||
|
||||
@ -65,7 +65,7 @@ public class LightBigList<T> implements LightList<T>, 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<T> implements LightList<T>, Saveable {
|
||||
for (long chunkIndex : chunks) {
|
||||
try {
|
||||
EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex);
|
||||
LightArrayList<T> chunk = chunkRef.getValueReadOnly();
|
||||
LightArrayList<T> chunk = chunkRef.getValueReadOnlyUnsafe();
|
||||
if (chunk.contains(o)) {
|
||||
return true;
|
||||
}
|
||||
@ -211,7 +211,7 @@ public class LightBigList<T> implements LightList<T>, Saveable {
|
||||
|
||||
try {
|
||||
EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex);
|
||||
LightArrayList<T> chunk = chunkRef.getValueReadOnly();
|
||||
LightArrayList<T> 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<T> implements LightList<T>, 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<T> implements LightList<T>, Saveable {
|
||||
|
||||
@Override
|
||||
public EntryReference<T> getReference(int index) {
|
||||
return getReferenceUnsafe(index, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntryReference<T> getReferenceOrInitialize(int index, Supplier<T> initializer) {
|
||||
EntryReference<T> value = getReferenceUnsafe(index, false);
|
||||
if (value != null) {
|
||||
return value;
|
||||
} else {
|
||||
T initializedData = initializer.get();
|
||||
EntryReference<T> initializedDataRef = addToDatabase(initializedData);
|
||||
return set(index, initializedDataRef);
|
||||
}
|
||||
}
|
||||
|
||||
private EntryReference<T> 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<T> implements LightList<T>, Saveable {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T set(int setOffset, final T element) {
|
||||
return set(setOffset, addToDatabase(element)).getValueReadOnlyUnsafe();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public EntryReference<T> set(int setOffset, final EntryReference<T> element) {
|
||||
long nextChunkOffset = 0;
|
||||
VariableWrapper<T> wrapper = new VariableWrapper<>(null);
|
||||
VariableWrapper<EntryReference<T>> 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<T> implements LightList<T>, Saveable {
|
||||
try {
|
||||
EntryReference<LightArrayList<T>> 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<T> implements LightList<T>, Saveable {
|
||||
// Get chunk index
|
||||
final long chunkIndex = chunks.getLong(i);
|
||||
EntryReference<LightArrayList<T>> 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<T> implements LightList<T>, Saveable {
|
||||
// Get chunk index
|
||||
final long chunkIndex = chunks.getLong(i);
|
||||
EntryReference<LightArrayList<T>> 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<T> implements LightList<T>, Saveable {
|
||||
this.cachedChunkRef.save();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAndFlush() {
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
@ -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<T> extends List<T> {
|
||||
|
||||
@ -12,10 +13,14 @@ public interface LightList<T> extends List<T> {
|
||||
|
||||
EntryReference<T> addEntry(T o);
|
||||
|
||||
EntryReference<T> set(int setOffset, final EntryReference<T> element);
|
||||
|
||||
boolean remove(EntryReference<T> ref);
|
||||
|
||||
EntryReference<T> getReference(int index);
|
||||
|
||||
EntryReference<T> getReferenceOrInitialize(int index, Supplier<T> initializer);
|
||||
|
||||
int indexOfEntry(EntryReference<T> ref);
|
||||
|
||||
int lastIndexOfEntry(EntryReference<T> ref);
|
||||
|
@ -3,5 +3,6 @@ package org.warp.jcwdb;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Saveable {
|
||||
public void save();
|
||||
void save();
|
||||
void saveAndFlush();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user