Merge branch 'master' into origin/better

This commit is contained in:
Andrea Cavalli 2019-01-09 19:06:34 +01:00
commit 20dbb31ac4
10 changed files with 186 additions and 47 deletions

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4" />

View File

@ -1,5 +0,0 @@
package org.warp.jcwdb;
public interface AdvancedSaveable extends Saveable {
public void save(boolean isEditFinished);
}

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

View File

@ -10,7 +10,7 @@ import java.util.function.Function;
* You must have only a maximum of 1 reference for each index * You must have only a maximum of 1 reference for each index
* @param <T> * @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 JCWDatabase.EntryReferenceTools db;
private final long entryIndex; private final long entryIndex;
private final DBTypeParser<T> parser; 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 * 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); this.save(false);
} }
public void save(boolean isEditFinished) { public void saveAndFlush() {
this.save(true);
}
private void save(boolean flush) {
synchronized(accessLock) { synchronized(accessLock) {
if (loaded && !closed) { if (loaded && !closed) {
try { try {
if (value instanceof AdvancedSaveable) { if (value instanceof Saveable) {
((AdvancedSaveable)value).save(isEditFinished); if (flush) {
} else if (value instanceof Saveable) { ((Saveable)value).saveAndFlush();
} else {
((Saveable)value).save(); ((Saveable)value).save();
} }
}
IndexDetails returnedDetails = this.db.write(entryIndex, parser.getWriter(value)); IndexDetails returnedDetails = this.db.write(entryIndex, parser.getWriter(value));
synchronized(hashCacheLock) { synchronized(hashCacheLock) {
this.cachedHash = returnedDetails.getHash(); this.cachedHash = returnedDetails.getHash();
this.isHashCached = true; this.isHashCached = true;
} }
if (isEditFinished) { if (flush) {
if (!isFlushingAllowed) { if (!isFlushingAllowed) {
this.db.setFlushingAllowed(entryIndex, true); this.db.setFlushingAllowed(entryIndex, true);
this.isFlushingAllowed = 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 * Substitute the old value with a new one
* @param val * @param val
@ -171,14 +194,14 @@ public class EntryReference<T> implements Castable, AdvancedSaveable {
*/ */
@Deprecated() @Deprecated()
public T getValue() { public T getValue() {
return getValueReadOnly(); return getValueReadOnlyUnsafe();
} }
/** /**
* DO NOT ATTEMPT TO MODIFY THE VALUE RETURNED * DO NOT ATTEMPT TO MODIFY THE VALUE RETURNED
* @return * @return
*/ */
public T getValueReadOnly() { public T getValueReadOnlyUnsafe() {
synchronized(accessLock) { synchronized(accessLock) {
load(); load();
return this.value; return this.value;

View File

@ -1,7 +1,11 @@
package org.warp.jcwdb; package org.warp.jcwdb;
import java.io.IOError;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; 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 class JCWDatabase implements AutoCloseable, Cleanable {
public final static long MAX_LOADED_INDICES = 1000; public final static long MAX_LOADED_INDICES = 1000;
@ -13,6 +17,7 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
private volatile boolean closed; private volatile boolean closed;
private final Object closeLock = new Object(); private final Object closeLock = new Object();
private final Object indicesAccessLock = new Object(); private final Object indicesAccessLock = new Object();
private final LinkedList<EntryReference<?>> usedReferences = new LinkedList<>();
public JCWDatabase(Path dataFile, Path metadataFile) throws IOException { public JCWDatabase(Path dataFile, Path metadataFile) throws IOException {
this.typesManager = new TypesManager(this); this.typesManager = new TypesManager(this);
@ -29,7 +34,8 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
this.databaseCleaner.start(); this.databaseCleaner.start();
} }
public <T> EntryReference<LightList<T>> getRoot() throws IOException { public <T> EntryReference<LightList<T>> getRoot() {
try {
checkClosed(); checkClosed();
if (exists(0)) { if (exists(0)) {
return get(0); return get(0);
@ -37,9 +43,22 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
LightList<T> newRoot = new LightBigList<>(this); LightList<T> newRoot = new LightBigList<>(this);
return set(0, newRoot); 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(); return getRoot().cast();
} }
@ -137,6 +156,14 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
@Override @Override
public long clean() { public long clean() {
long removedItems = indices.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; return removedItems;
} }
@ -156,6 +183,10 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
public void setFlushingAllowed(long index, boolean isFlushingAllowed) { public void setFlushingAllowed(long index, boolean isFlushingAllowed) {
indices.setFlushingAllowed(index, isFlushingAllowed); indices.setFlushingAllowed(index, isFlushingAllowed);
} }
public <T> void setUsed(EntryReference<T> ref) {
usedReferences.add(ref);
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -48,7 +48,7 @@ public class LightArrayList<T> implements LightList<T> {
EntryReference<T> ref = null; EntryReference<T> ref = null;
try { try {
ref = db.get(element); ref = db.get(element);
if (o.equals(ref.getValueReadOnly())) { if (o.equals(ref.getValueReadOnlyUnsafe())) {
return true; return true;
} }
} catch (IOException e) { } catch (IOException e) {
@ -70,7 +70,7 @@ public class LightArrayList<T> implements LightList<T> {
final ArrayList<T> elements = new ArrayList<>(); final ArrayList<T> elements = new ArrayList<>();
for (long element : internalList) { for (long element : internalList) {
try { try {
elements.add((T) db.get(element).getValueReadOnly()); elements.add((T) db.get(element).getValueReadOnlyUnsafe());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -125,7 +125,7 @@ public class LightArrayList<T> implements LightList<T> {
final T[] elements = (T[]) new Object[internalList.size()]; final T[] elements = (T[]) new Object[internalList.size()];
for (int i = 0; i < elements.length; i++) { for (int i = 0; i < elements.length; i++) {
try { try {
T element = (T) db.get(internalList.getLong(i)).getValueReadOnly(); T element = (T) db.get(internalList.getLong(i)).getValueReadOnlyUnsafe();
elements[i] = element; elements[i] = element;
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -140,7 +140,7 @@ public class LightArrayList<T> implements LightList<T> {
final T1[] elements = (T1[]) new Objects[internalList.size()]; final T1[] elements = (T1[]) new Objects[internalList.size()];
for (int i = 0; i < elements.length; i++) { for (int i = 0; i < elements.length; i++) {
try { try {
elements[i] = (T1) db.get(internalList.getLong(i)).getValueReadOnly(); elements[i] = (T1) db.get(internalList.getLong(i)).getValueReadOnlyUnsafe();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -265,7 +265,7 @@ public class LightArrayList<T> implements LightList<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T getReadOnlyValue(int index) { public T getReadOnlyValue(int index) {
try { try {
return (T) db.get(internalList.getLong(index)).getValueReadOnly(); return (T) db.get(internalList.getLong(index)).getValueReadOnlyUnsafe();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@ -289,7 +289,7 @@ public class LightArrayList<T> implements LightList<T> {
long oldIndex = internalList.set(index, ref.getIndex()); long oldIndex = internalList.set(index, ref.getIndex());
try { try {
ref.close(); ref.close();
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnly(); return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnlyUnsafe();
} catch (IOException e) { } catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e); throw (NullPointerException) new NullPointerException().initCause(e);
} }
@ -306,7 +306,7 @@ public class LightArrayList<T> implements LightList<T> {
public T remove(int index) { public T remove(int index) {
long oldIndex = internalList.removeLong(index); long oldIndex = internalList.removeLong(index);
try { try {
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnly(); return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnlyUnsafe();
} catch (IOException e) { } catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e); throw (NullPointerException) new NullPointerException().initCause(e);
} }
@ -340,7 +340,7 @@ public class LightArrayList<T> implements LightList<T> {
long index = internalList.getLong(i); long index = internalList.getLong(i);
try { try {
EntryReference<?> ref2 = db.get(index); EntryReference<?> ref2 = db.get(index);
if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) { if (ref.getValueReadOnlyUnsafe().equals(ref2.getValueReadOnlyUnsafe())) {
return i; return i;
} }
} catch (IOException e) { } catch (IOException e) {
@ -372,7 +372,7 @@ public class LightArrayList<T> implements LightList<T> {
try { try {
EntryReference<?> ref2 = db.get(index2); EntryReference<?> ref2 = db.get(index2);
if (objToRemoveHash == ref2.calculateHash()) { if (objToRemoveHash == ref2.calculateHash()) {
if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) { if (ref.getValueReadOnlyUnsafe().equals(ref2.getValueReadOnlyUnsafe())) {
lastValue = i; lastValue = i;
} }
} }
@ -431,7 +431,7 @@ public class LightArrayList<T> implements LightList<T> {
for (int i = 0; i < internalList.size(); ) { for (int i = 0; i < internalList.size(); ) {
T obj; T obj;
try { try {
obj = ((EntryReference<T>) (db.get(internalList.getLong(i)).cast())).getValueReadOnly(); obj = ((EntryReference<T>) (db.get(internalList.getLong(i)).cast())).getValueReadOnlyUnsafe();
} catch (IOException e) { } catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e); throw (NullPointerException) new NullPointerException().initCause(e);
} }

View File

@ -4,11 +4,11 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.io.IOError;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier;
public class LightBigList<T> implements LightList<T>, Saveable { public class LightBigList<T> implements LightList<T>, Saveable {
@ -65,7 +65,7 @@ public class LightBigList<T> implements LightList<T>, Saveable {
} catch (IOException ex) { } catch (IOException ex) {
throw (NullPointerException) new NullPointerException().initCause(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) { for (long chunkIndex : chunks) {
try { try {
EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex); EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex);
LightArrayList<T> chunk = chunkRef.getValueReadOnly(); LightArrayList<T> chunk = chunkRef.getValueReadOnlyUnsafe();
if (chunk.contains(o)) { if (chunk.contains(o)) {
return true; return true;
} }
@ -211,7 +211,7 @@ public class LightBigList<T> implements LightList<T>, Saveable {
try { try {
EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex); 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++) { for (int i1 = 0; i1 < chunk.size(); i1++) {
result[(int)(chunkStartOffset + i1)] = chunk.get(i); result[(int)(chunkStartOffset + i1)] = chunk.get(i);
} }
@ -378,7 +378,7 @@ public class LightBigList<T> implements LightList<T>, Saveable {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public T getReadOnlyValue(int index) { public T getReadOnlyValue(int index) {
try { try {
return (T) db.get(chunks.getLong(index)).getValueReadOnly(); return (T) db.get(chunks.getLong(index)).getValueReadOnlyUnsafe();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
@ -387,10 +387,26 @@ public class LightBigList<T> implements LightList<T>, Saveable {
@Override @Override
public EntryReference<T> getReference(int index) { 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 { try {
return db.get(chunks.getLong(index)).cast(); return db.get(chunks.getLong(index)).cast();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); if (throwError) e.printStackTrace();
return null; return null;
} }
} }
@ -398,8 +414,14 @@ public class LightBigList<T> implements LightList<T>, Saveable {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public T set(int setOffset, final T element) { 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; long nextChunkOffset = 0;
VariableWrapper<T> wrapper = new VariableWrapper<>(null); VariableWrapper<EntryReference<T>> wrapper = new VariableWrapper<>(null);
if (setOffset >= 0) { if (setOffset >= 0) {
// Iterate through all chunks // Iterate through all chunks
for (int i = 0; i < chunks.size(); i++) { for (int i = 0; i < chunks.size(); i++) {
@ -420,8 +442,7 @@ public class LightBigList<T> implements LightList<T>, Saveable {
try { try {
EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex); EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex);
chunkRef.editValue((chunk) -> { chunkRef.editValue((chunk) -> {
chunk.set(relativeOffset, element); wrapper.var = chunk.set(relativeOffset, element);
wrapper.var = element;
}); });
} catch (IOException ex) { } catch (IOException ex) {
throw (NullPointerException) new NullPointerException().initCause(ex); throw (NullPointerException) new NullPointerException().initCause(ex);
@ -463,7 +484,7 @@ public class LightBigList<T> implements LightList<T>, Saveable {
// Get chunk index // Get chunk index
final long chunkIndex = chunks.getLong(i); final long chunkIndex = chunks.getLong(i);
EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex); EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex);
final int foundIndex = chunkRef.getValueReadOnly().indexOfEntry(ref); final int foundIndex = chunkRef.getValueReadOnlyUnsafe().indexOfEntry(ref);
if (foundIndex >= 0) { if (foundIndex >= 0) {
return currentOffset + foundIndex; return currentOffset + foundIndex;
} }
@ -492,7 +513,7 @@ public class LightBigList<T> implements LightList<T>, Saveable {
// Get chunk index // Get chunk index
final long chunkIndex = chunks.getLong(i); final long chunkIndex = chunks.getLong(i);
EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex); EntryReference<LightArrayList<T>> chunkRef = db.get(chunkIndex);
final int foundIndex = chunkRef.getValueReadOnly().lastIndexOfEntry(ref); final int foundIndex = chunkRef.getValueReadOnlyUnsafe().lastIndexOfEntry(ref);
if (foundIndex >= 0) { if (foundIndex >= 0) {
return currentOffset + foundIndex; return currentOffset + foundIndex;
} }
@ -578,4 +599,9 @@ public class LightBigList<T> implements LightList<T>, Saveable {
this.cachedChunkRef.save(); this.cachedChunkRef.save();
} }
} }
@Override
public void saveAndFlush() {
save();
}
} }

View File

@ -3,6 +3,7 @@ package org.warp.jcwdb;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
public interface LightList<T> extends List<T> { 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> addEntry(T o);
EntryReference<T> set(int setOffset, final EntryReference<T> element);
boolean remove(EntryReference<T> ref); boolean remove(EntryReference<T> ref);
EntryReference<T> getReference(int index); EntryReference<T> getReference(int index);
EntryReference<T> getReferenceOrInitialize(int index, Supplier<T> initializer);
int indexOfEntry(EntryReference<T> ref); int indexOfEntry(EntryReference<T> ref);
int lastIndexOfEntry(EntryReference<T> ref); int lastIndexOfEntry(EntryReference<T> ref);

View File

@ -3,5 +3,6 @@ package org.warp.jcwdb;
import java.io.IOException; import java.io.IOException;
public interface Saveable { public interface Saveable {
public void save(); void save();
void saveAndFlush();
} }

View File

@ -63,7 +63,7 @@ public class App {
System.out.println("Retrieving items..."); System.out.println("Retrieving items...");
root.forEachReference((valueReference) -> { root.forEachReference((valueReference) -> {
Animal value = valueReference.getValueReadOnly(); Animal value = valueReference.getValueReadOnlyUnsafe();
if (Animal.hasFourLegs(value)) { if (Animal.hasFourLegs(value)) {
results.add(value); results.add(value);
} }