value reference private

This commit is contained in:
Cavallium 2018-12-11 23:00:51 +01:00
parent 468e58994c
commit adfdb571d8
12 changed files with 333 additions and 161 deletions

View File

@ -1,6 +1,7 @@
package org.warp.jcwdb;
import java.io.IOException;
import java.util.function.Consumer;
public class CacheIndexManager implements IndexManager {
@ -19,6 +20,12 @@ public class CacheIndexManager implements IndexManager {
return 0;
}
@Override
public long getHash(long index) {
// TODO: implement
return 0;
}
@Override
public <T> long add(DBDataOutput<T> writer) {
// TODO: implement
@ -26,8 +33,9 @@ public class CacheIndexManager implements IndexManager {
}
@Override
public <T> void set(long index, DBDataOutput<T> writer) {
public <T> IndexDetails set(long index, DBDataOutput<T> writer) {
// TODO: implement
return null;
}
@Override

View File

@ -62,15 +62,15 @@ public class Cleaner {
while(!stopRequest) {
try {
System.out.println("[CLEANER] Waiting " + sleepInterval + "ms.");
Thread.sleep(sleepInterval);
sleepFor(sleepInterval);
final double removedItems = clean();
double suggestedExecutionTimeByItemsCalculations = sleepInterval;
double suggestedExecutionTimeByItemsCalculations = (sleepInterval + MAXIMUM_SLEEP_INTERVAL) / 2;
System.out.println("[CLEANER] REMOVED_ITEMS: " + removedItems);
if (removedItems > 0) {
final double removedItemsRatio = removedItems / NORMAL_REMOVED_ITEMS;
System.out.println("[CLEANER] REMOVED_ITEMS_RATIO: " + removedItemsRatio);
if (removedItemsRatio < 1d / REMOVED_ITEMS_RATIO || removedItemsRatio > REMOVED_ITEMS_RATIO) {
if (removedItemsRatio < 1d / REMOVED_ITEMS_RATIO && removedItemsRatio >= REMOVED_ITEMS_RATIO) {
suggestedExecutionTimeByItemsCalculations = sleepInterval / removedItemsRatio;
}
}
@ -95,6 +95,21 @@ public class Cleaner {
}
}
}
private void sleepFor(int sleepInterval) throws InterruptedException {
int lastI = (int) Math.ceil(((double) sleepInterval) / 1000d);
for (int i = 0; i < lastI; i++) {
if (stopRequest) {
return;
}
if (i == lastI) {
Thread.sleep(sleepInterval % 1000);
} else {
Thread.sleep(lastI);
}
Thread.sleep(sleepInterval);
}
}
}
}

View File

@ -4,42 +4,37 @@ import java.util.ArrayList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
public class DBLightListParser extends DBTypeParserImpl<LightList> {
public class DBLightListParser<T> extends DBTypeParserImpl<LightList<T>> {
private final JCWDatabase db;
public DBLightListParser(JCWDatabase db) {
this.db = db;
}
public DBReader<LightList> getReader() {
public DBReader<LightList<T>> getReader() {
return (i, size) -> {
LongArrayList internalList = new LongArrayList();
LongArrayList hashes = new LongArrayList();
long max = size / (Long.BYTES * 2);
long max = size / Long.BYTES;
for (int item = 0; item < max; item++){
long itm = i.readLong();
long hash = i.readLong();
internalList.add(itm);
hashes.add(hash);
}
return new LightList(db, internalList, hashes);
return new LightList<T>(db, internalList);
};
}
public DBDataOutput<LightList> getWriter(final LightList value) {
public DBDataOutput<LightList<T>> getWriter(final LightList<T> value) {
final int elementsCount = value.size();
return DBDataOutput.create((o) -> {
LongArrayList list = value.internalList;
LongArrayList hashes = value.hashes;
for (int i = 0; i < elementsCount; i++) {
o.writeLong(list.getLong(i));
o.writeLong(hashes.getLong(i));
}
}, DBStandardTypes.LIGHT_LIST, elementsCount * Long.BYTES * 2, calculateHash(value));
}, DBStandardTypes.LIGHT_LIST, elementsCount * Long.BYTES, calculateHash(value));
}
@Override
public long calculateHash(LightList value) {
return value.hashCodeLong();
public long calculateHash(LightList<T> value) {
return value.internalList.hashCode();
}
}

View File

@ -1,31 +1,44 @@
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;
/**
* You must have only a maximum of 1 reference for each index
* @param <T>
*/
public class EntryReference<T> implements Castable {
public class EntryReference<T> implements Castable, Saveable {
private final JCWDatabase.EntryReferenceTools db;
private final long entryIndex;
private final DBTypeParser<T> parser;
private T value;
private long cachedHash;
private volatile boolean isHashCached;
private volatile boolean loaded;
private volatile boolean closed;
private final Object hashCacheLock = new Object();
private final Object accessLock = new Object();
private final Object closeLock = new Object();
public EntryReference(JCWDatabase.EntryReferenceTools db, long entryId, DBTypeParser<T> parser) throws IOException {
public EntryReference(JCWDatabase.EntryReferenceTools db, long entryId, long hash, DBTypeParser<T> parser) {
this.loaded = false;
this.isHashCached = false;
this.db = db;
this.entryIndex = entryId;
this.parser = parser;
this.value = db.read(entryId, parser.getReader());
this.value = null;
}
public EntryReference(JCWDatabase.EntryReferenceTools db, long entryId, DBTypeParser<T> parser, T value) {
public EntryReference(JCWDatabase.EntryReferenceTools db, long entryId, long hash, DBTypeParser<T> parser, T value) {
this.loaded = true;
this.isHashCached = true;
this.db = db;
this.entryIndex = entryId;
this.parser = parser;
this.cachedHash = hash;
this.value = value;
}
@ -38,44 +51,116 @@ public class EntryReference<T> implements Castable {
}
public long calculateHash() {
return parser.calculateHash(value);
synchronized(accessLock) {
load();
synchronized(hashCacheLock) {
if (isHashCached) {
return cachedHash;
}
}
return parser.calculateHash(this.value);
}
}
/**
* Note that this method won't be called when closing without saving
* @throws IOException
*/
public void save() throws IOException {
if (!closed) {
db.write(entryIndex, parser.getWriter(value));
public void save() {
synchronized(accessLock) {
if (loaded && !closed) {
try {
IndexDetails returnedDetails = db.write(entryIndex, parser.getWriter(value));
synchronized(hashCacheLock) {
this.cachedHash = returnedDetails.getHash();
this.isHashCached = true;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void editValue(Function<T, T> editFunction) throws IOException {
this.value = editFunction.apply(this.value);
this.save();
/**
* Reccomended way to edit the value
* @param editFunction
* @throws IOException
*/
public void editValue(BiFunction<T, Saveable, T> editFunction) throws IOException {
synchronized(accessLock) {
load();
this.value = editFunction.apply(this.value, this);
this.save();
}
}
/**
* Use editValue instead
* Reccomended way to edit the value
* @param editFunction
* @throws IOException
*/
public void editValue(BiConsumer<T, Saveable> editFunction) throws IOException {
synchronized(accessLock) {
load();
editFunction.accept(this.value, this);
this.save();
}
}
/**
* Substitute the old value with a new one
* @param val
* @throws IOException
*/
public void setValue(T val) throws IOException {
synchronized(accessLock) {
this.loaded = true;
this.value = val;
synchronized(hashCacheLock) {
this.isHashCached = false;
}
this.save();
}
}
/**
* Use editValue instead. READ ONLY!!
* @return
*/
@Deprecated()
public T getValue() {
return this.value;
return getValueReadOnly();
}
/**
* DO NOT ATTEMPT TO MODIFY THE VALUE RETURNED
* @return
*/
public T getValueUnsafe() {
return this.value;
public T getValueReadOnly() {
synchronized(accessLock) {
load();
return this.value;
}
}
private void load() {
synchronized(accessLock) {
if (!loaded) {
try {
this.value = db.read(entryIndex, parser.getReader());
this.loaded = true;
} catch (IOException e) {
throw (NullPointerException) new NullPointerException(e.getLocalizedMessage()).initCause(e);
}
}
}
}
@SuppressWarnings("unchecked")
@Override
public <T> T cast() {
return (T) this;
public <U> U cast() {
return (U) this;
}
protected void close() throws IOException {
@ -105,4 +190,8 @@ public class EntryReference<T> implements Castable {
closed = true;
}
}
public Object getAccessLock() {
return accessLock;
}
}

View File

@ -11,6 +11,7 @@ import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.function.Consumer;
public class FileIndexManager implements IndexManager {
private final SeekableByteChannel dataFileChannel, metadataFileChannel;
@ -69,16 +70,21 @@ public class FileIndexManager implements IndexManager {
}
@Override
public <T> void set(long index, DBDataOutput<T> data) throws IOException {
public long getHash(long index) throws IOException {
return getIndexMetadata(index).getHash();
}
@Override
public <T> IndexDetails set(long index, DBDataOutput<T> data) throws IOException {
checkClosed();
final int dataSize = data.getSize();
final IndexDetails indexDetails = getIndexMetadataUnsafe(index);
if (indexDetails == null || indexDetails.getSize() < dataSize) {
// Allocate new space
allocateAndWrite(index, data);
return allocateAndWrite(index, data);
} else {
// Check if size changed
if (indexDetails.getSize() > dataSize) {
if (dataSize < indexDetails.getSize()) {
// Mark free the unused bytes
fileAllocator.markFree(indexDetails.getOffset() + dataSize, dataSize);
}
@ -86,6 +92,8 @@ public class FileIndexManager implements IndexManager {
editIndex(index, indexDetails, indexDetails.getOffset(), dataSize, indexDetails.getType(), data.calculateHash());
// Write data
writeExact(indexDetails, data);
// Before returning, return IndexDetails
return indexDetails;
}
}
@ -122,13 +130,14 @@ public class FileIndexManager implements IndexManager {
o.flush();
}
private void allocateAndWrite(final long index, DBDataOutput<?> w) throws IOException {
private IndexDetails allocateAndWrite(final long index, DBDataOutput<?> w) throws IOException {
final int size = w.getSize();
final int type = w.getType();
final long hash = w.calculateHash();
final long offset = fileAllocator.allocate(size);
IndexDetails details = editIndex(index, offset, size, type, hash);
writeExact(details, w);
return details;
}
@Override
@ -156,16 +165,17 @@ public class FileIndexManager implements IndexManager {
SeekableByteChannel metadata = metadataFileChannel.position(index * IndexDetails.TOTAL_BYTES);
eraseIndexDetails(metadata);
}
if (dirtyLoadedIndices.contains(index)) {
synchronized (indicesMapsAccessLock) {
boolean isDirty = false;
IndexDetails indexDetails = null;
synchronized (indicesMapsAccessLock) {
if (dirtyLoadedIndices.contains(index)) {
indexDetails = loadedIndices.get(index);
dirtyLoadedIndices.remove(index);
}
}
if (isDirty) {
// Update indices metadata
SeekableByteChannel metadata = metadataFileChannel.position(index * IndexDetails.TOTAL_BYTES);
IndexDetails indexDetails;
synchronized (indicesMapsAccessLock) {
indexDetails = loadedIndices.get(index);
}
writeIndexDetails(metadata, indexDetails);
}
synchronized (indicesMapsAccessLock) {
@ -196,7 +206,7 @@ public class FileIndexManager implements IndexManager {
*/
private IndexDetails editIndex(long index, IndexDetails oldData, long offset, int size, int type, long hash) {
if (oldData.getOffset() != offset || oldData.getSize() != size || oldData.getType() != type || oldData.getHash() != hash) {
editIndex(index, offset, size, type, hash);
return editIndex(index, offset, size, type, hash);
} else {
return oldData;
}

View File

@ -1,12 +1,14 @@
package org.warp.jcwdb;
import java.io.IOException;
import java.util.function.Consumer;
public interface IndexManager extends Cleanable {
<T> T get(long index, DBReader<T> reader) throws IOException;
int getType(long index) throws IOException;
long getHash(long index) throws IOException;
<T> long add(DBDataOutput<T> writer) throws IOException;
<T> void set(long index, DBDataOutput<T> writer) throws IOException;
<T> IndexDetails set(long index, DBDataOutput<T> writer) throws IOException;
void delete(long index) throws IOException;
boolean has(long index);
void close() throws IOException;

View File

@ -5,6 +5,7 @@ import java.lang.ref.WeakReference;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.function.Consumer;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
@ -51,7 +52,7 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
if (exists(0)) {
return get(0);
} else {
LightList<T> newRoot = new LightList<T>(this, new LongArrayList(), new LongArrayList());
LightList<T> newRoot = new LightList<T>(this, new LongArrayList());
return set(0, newRoot);
}
}
@ -63,11 +64,13 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
EntryReference<T> ref;
if (refRef == null || (ref = (EntryReference<T>) refRef.get()) == null) {
int type;
long hash;
synchronized (indicesAccessLock) {
type = this.indices.getType(index);
hash = this.indices.getHash(index);
}
DBTypeParser<T> typeParser = this.typesManager.get(type);
ref = new EntryReference<>(entryReferenceTools, index, typeParser);
ref = new EntryReference<>(entryReferenceTools, index, hash, typeParser);
refRef = new WeakReference<>(ref);
this.references.put(index, refRef);
}
@ -81,10 +84,12 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
EntryReference<T> ref;
DBTypeParser<T> typeParser = this.typesManager.get((Class<T>) value.getClass());
long index;
long hash;
synchronized (indicesAccessLock) {
index = indices.add(typeParser.getWriter(value));
hash = indices.getHash(index);
}
ref = new EntryReference<>(entryReferenceTools, index, typeParser, value);
ref = new EntryReference<>(entryReferenceTools, index, hash, typeParser, value);
this.references.put(index, new WeakReference<>(ref));
return ref;
}
@ -105,14 +110,17 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
EntryReference<T> ref;
if (exists(index)) {
ref = get(index);
ref.value = value;
ref.setValue(value);
return ref;
} else {
@SuppressWarnings("unchecked")
DBTypeParser<T> typeParser = this.typesManager.get((Class<T>) value.getClass());
long hash;
synchronized (indicesAccessLock) {
indices.set(index, typeParser.getWriter(value));
IndexDetails returnedDetails = indices.set(index, typeParser.getWriter(value));
hash = returnedDetails.getHash();
}
ref = new EntryReference<>(entryReferenceTools, index, typeParser);
ref = new EntryReference<>(entryReferenceTools, index, hash, typeParser);
this.references.put(index, new WeakReference<EntryReference<?>>(ref));
return ref;
}
@ -194,6 +202,15 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
while (iterator.hasNext()) {
Entry<WeakReference<EntryReference<?>>> entry = iterator.next();
if (count > MAX_LOADED_REFERENCES * 3l / 2l) {
WeakReference<EntryReference<?>> weakRef = entry.getValue();
EntryReference<?> ref = weakRef.get();
if (ref != null) {
try {
ref.close();
} catch (IOException e) {
e.printStackTrace();
}
}
iterator.remove();
removedReferences++;
} else {
@ -214,8 +231,8 @@ public class JCWDatabase implements AutoCloseable, Cleanable {
return indices.get(index, reader);
}
public <T> void write(long index, DBDataOutput<T> writer) throws IOException {
indices.set(index, writer);
public <T> IndexDetails write(long index, DBDataOutput<T> writer) throws IOException {
return indices.set(index, writer);
}
}

View File

@ -10,12 +10,10 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList;
public class LightList<T> implements List<T> {
public final LongArrayList internalList;
public final LongArrayList hashes;
private final transient JCWDatabase db;
public LightList(JCWDatabase db, LongArrayList internalList, LongArrayList hashes) {
public LightList(JCWDatabase db, LongArrayList internalList) {
this.internalList = internalList;
this.hashes = hashes;
this.db = db;
}
@ -36,7 +34,7 @@ public class LightList<T> implements List<T> {
EntryReference<T> ref = null;
try {
ref = db.get(element);
if (o.equals(ref.value)) {
if (o.equals(ref.getValueReadOnly())) {
return true;
}
} catch (IOException e) {
@ -47,19 +45,37 @@ public class LightList<T> implements List<T> {
return false;
}
/**
* Use iteratorReferences()
*/
@Deprecated
@SuppressWarnings("unchecked")
@Override
public Iterator<T> iterator() {
final ArrayList<T> elements = new ArrayList<>();
for (Long element : internalList) {
try {
elements.add((T) db.get(element).value);
elements.add((T) db.get(element).getValueReadOnly());
} catch (IOException e) {
e.printStackTrace();
}
}
return elements.iterator();
}
@SuppressWarnings("unchecked")
public Iterator<EntryReference<T>> iteratorReferences() {
final ArrayList<EntryReference<T>> elements = new ArrayList<>();
for (Long element : internalList) {
try {
elements.add(db.get(element));
} catch (IOException e) {
e.printStackTrace();
}
}
return elements.iterator();
}
@SuppressWarnings("unchecked")
@Override
@ -67,7 +83,7 @@ public class LightList<T> implements List<T> {
final T[] elements = (T[]) new Objects[internalList.size()];
for (int i = 0; i < elements.length; i++) {
try {
elements[i] = (T) db.get(internalList.getLong(i)).value;
elements[i] = (T) db.get(internalList.getLong(i)).getValueReadOnly();
} catch (IOException e) {
e.printStackTrace();
}
@ -81,7 +97,7 @@ public class LightList<T> implements List<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)).value;
elements[i] = (T1) db.get(internalList.getLong(i)).getValueReadOnly();
} catch (IOException e) {
e.printStackTrace();
}
@ -98,11 +114,10 @@ public class LightList<T> implements List<T> {
public EntryReference<T> addEntry(T o) {
EntryReference<T> ref = addToDatabase(o);
if (internalList.add(ref.getIndex())) {
hashes.add(ref.getParser().calculateHash(ref.value));
return ref;
} else {
return null;
}
return ref;
}
@Override
@ -110,7 +125,6 @@ public class LightList<T> implements List<T> {
int removeIndex = indexOf(o);
if (removeIndex >= 0) {
internalList.removeLong(removeIndex);
hashes.removeLong(removeIndex);
return true;
}
return false;
@ -120,7 +134,6 @@ public class LightList<T> implements List<T> {
int removeIndex = indexOfEntry(ref);
if (removeIndex >= 0) {
internalList.removeLong(removeIndex);
hashes.removeLong(removeIndex);
return true;
}
return false;
@ -193,14 +206,30 @@ public class LightList<T> implements List<T> {
@Override
public void clear() {
internalList.clear();
hashes.clear();
}
/**
* Use getReference or getReadOnlyValue
*/
@Deprecated
@Override
public T get(int index) {
return getReadOnlyValue(index);
}
@SuppressWarnings("unchecked")
@Override
public T get(int index) {
public T getReadOnlyValue(int index) {
try {
return (T) db.get(internalList.getLong(index)).value;
return (T) db.get(internalList.getLong(index)).getValueReadOnly();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public EntryReference<T> getReference(int index) {
try {
return db.get(internalList.getLong(index)).cast();
} catch (IOException e) {
e.printStackTrace();
return null;
@ -212,10 +241,9 @@ public class LightList<T> implements List<T> {
public T set(int index, T element) {
EntryReference<T> ref = addToDatabase(element);
long oldIndex = internalList.set(index, ref.getIndex());
hashes.set(index, ref.calculateHash());
try {
ref.close();
return ((EntryReference<T>) (db.get(oldIndex))).value;
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnly();
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
@ -225,26 +253,26 @@ public class LightList<T> implements List<T> {
public void add(int index, T element) {
EntryReference<T> ref = addToDatabase(element);
internalList.add(index, ref.getIndex());
hashes.add(index, ref.getParser().calculateHash(ref.value));
}
@SuppressWarnings("unchecked")
@Override
public T remove(int index) {
long oldIndex = internalList.removeLong(index);
hashes.removeLong(index);
try {
return ((EntryReference<T>) (db.get(oldIndex))).value;
return ((EntryReference<T>) (db.get(oldIndex))).getValueReadOnly();
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
}
@Override
public int indexOf(Object o) {
EntryReference<?> ref = addToDatabase(o);
long objToRemoveHash = ref.calculateHash();
LongArrayList hashes = new LongArrayList();
for (int i = 0; i < hashes.size(); i++) {
long hash = hashes.getLong(i);
if (objToRemoveHash == hash) {
@ -261,18 +289,15 @@ public class LightList<T> implements List<T> {
}
public int indexOfEntry(EntryReference<T> ref) {
long objToRemoveHash = ref.calculateHash();
for (int i = 0; i < hashes.size(); i++) {
long hash = hashes.getLong(i);
if (objToRemoveHash == hash) {
try {
if (ref.equals(db.get(internalList.getLong(i)))) {
return i;
}
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
for (int i = 0; i < internalList.size(); i++) {
long index = internalList.getLong(i);
try {
EntryReference<?> ref2 = db.get(index);
if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) {
return i;
}
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
}
return -1;
@ -285,16 +310,17 @@ public class LightList<T> implements List<T> {
int lastValue = -1;
for (int i = 0; i < hashes.size(); i++) {
long hash = hashes.getLong(i);
if (objToRemoveHash == hash) {
try {
if (ref.equals(db.get(internalList.getLong(i)))) {
for (int i = 0; i < internalList.size(); i++) {
long index2 = internalList.getLong(i);
try {
EntryReference<?> ref2 = db.get(index2);
if (objToRemoveHash == ref2.calculateHash()) {
if (ref.getValueReadOnly().equals(ref2.getValueReadOnly())) {
lastValue = i;
}
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
}
return lastValue;
@ -336,19 +362,10 @@ public class LightList<T> implements List<T> {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((hashes == null) ? 0 : hashes.hashCode());
result = prime * result + ((internalList == null) ? 0 : internalList.hashCode());
return result;
}
public long hashCodeLong() {
final int prime = 31;
int result1 = prime + ((hashes == null) ? 0 : hashes.hashCode());
int result2 = prime + ((internalList == null) ? 0 : internalList.hashCode());
long result = (((long) result1) << 32) | (result2 & 0xffffffffL);
return result;
}
@SuppressWarnings("unchecked")
@Override
public boolean removeIf(Predicate<? super T> filter) {
@ -357,13 +374,12 @@ public class LightList<T> implements List<T> {
for (int i = 0; i < internalList.size(); ) {
T obj;
try {
obj = ((EntryReference<T>) (db.get(internalList.getLong(i)).cast())).value;
obj = ((EntryReference<T>) (db.get(internalList.getLong(i)).cast())).getValueReadOnly();
} catch (IOException e) {
throw (NullPointerException) new NullPointerException().initCause(e);
}
if (filter.test(obj)) {
internalList.removeLong(i);
hashes.removeLong(i);
removed = true;
} else {
i++;

View File

@ -5,6 +5,7 @@ import it.unimi.dsi.fastutil.longs.Long2LongMap;
import java.io.IOException;
import java.nio.file.Path;
import java.util.function.Consumer;
public class MixedIndexDatabase implements IndexManager {
private final Long2LongMap mostAccessedIndices;
@ -36,17 +37,26 @@ public class MixedIndexDatabase implements IndexManager {
}
}
@Override
public long getHash(long index) throws IOException {
if (cacheIndices.has(index)) {
return cacheIndices.getHash(index);
} else {
return fileIndices.getHash(index);
}
}
@Override
public <T> long add(DBDataOutput<T> writer) throws IOException {
return fileIndices.add(writer);
}
@Override
public <T> void set(long index, DBDataOutput<T> writer) throws IOException {
public <T> IndexDetails set(long index, DBDataOutput<T> writer) throws IOException {
if (cacheIndices.has(index)) {
cacheIndices.set(index, writer);
return cacheIndices.set(index, writer);
} else {
fileIndices.set(index, writer);
return fileIndices.set(index, writer);
}
}

View File

@ -0,0 +1,7 @@
package org.warp.jcwdb;
import java.io.IOException;
public interface Saveable {
public void save();
}

View File

@ -12,6 +12,7 @@ import java.nio.file.Paths;
import java.util.function.Predicate;
public class App {
static long time3;
public static void main(String[] args) {
try {
if (args.length > 2 && Boolean.parseBoolean(args[2])) {
@ -26,55 +27,57 @@ public class App {
System.out.println("Time elapsed: " + (time01 - time0));
System.out.println("Loading root...");
EntryReference<LightList<Animal>> rootRef = db.getRoot(Animal.class);
LightList<Animal> root = rootRef.getValue();
long time1 = System.currentTimeMillis();
System.out.println("Time elapsed: " + (time1 - time01));
System.out.println("Root size: " + root.size());
System.out.println("Root:");
// for (int i = 0; i < root.size(); i++) {
// System.out.println(" - " + root.get(i));
// }
long prectime = System.currentTimeMillis();
for (int i = 0; i < 2000000/* 2000000 */; i++) {
Animal animal = new StrangeAnimal(i % 40);
root.add(animal);
if (i > 0 && i % 200000 == 0) {
long precprectime = prectime;
prectime = System.currentTimeMillis();
System.out.println("Element " + i + " (" + (prectime - precprectime) + "ms)");
rootRef.editValue((root, saver) -> {
long time1 = System.currentTimeMillis();
System.out.println("Time elapsed: " + (time1 - time01));
System.out.println("Root size: " + root.size());
System.out.println("Root:");
// for (int i = 0; i < root.size(); i++) {
// System.out.println(" - " + root.get(i));
// }
long prectime = System.currentTimeMillis();
for (int i = 0; i < 20000/* 2000000 */; i++) {
Animal animal = new StrangeAnimal(i % 40);
root.add(animal);
if (i > 0 && i % 200000 == 0) {
long precprectime = prectime;
prectime = System.currentTimeMillis();
System.out.println("Element " + i + " (" + (prectime - precprectime) + "ms)");
}
}
}
long time2 = System.currentTimeMillis();
System.out.println("Root size: " + root.size());
System.out.println("Time elapsed: " + (time2 - time1));
System.out.println("Used memory: "
+ ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
long time2_0 = System.currentTimeMillis();
System.out.println("Filtering strings...");
//root.removeIf(Animal::hasFourLegs);
long time2_1 = System.currentTimeMillis();
System.out.println("Time elapsed: " + (time2_1 - time2_0));
ObjectList<Animal> results = new ObjectArrayList<>();
root.forEach((value) -> {
if (Animal.hasFourLegs(value)) {
results.add(value);
}
//System.out.println("val:" + value);
long time2 = System.currentTimeMillis();
saver.save();
System.out.println("Root size: " + root.size());
System.out.println("Time elapsed: " + (time2 - time1));
System.out.println("Used memory: "
+ ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
long time2_0 = System.currentTimeMillis();
System.out.println("Filtering strings...");
//root.removeIf(Animal::hasFourLegs);
long time2_1 = System.currentTimeMillis();
System.out.println("Time elapsed: " + (time2_1 - time2_0));
ObjectList<Animal> results = new ObjectArrayList<>();
root.forEach((value) -> {
if (Animal.hasFourLegs(value)) {
results.add(value);
}
//System.out.println("val:" + value);
});
long time2_2 = System.currentTimeMillis();
System.out.println("Time elapsed: " + (time2_2 - time2_1));
System.out.println("Used memory: "
+ ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
System.out.println("Used memory: " + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
System.out.println("Cleaning database (to reduce the amount of used memory and detect memory leaks)...");
long removedItems = db.clean();
time3 = System.currentTimeMillis();
System.out.println("Removed items: " + removedItems);
System.out.println("Used memory: " + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
System.out.println("Time elapsed: " + (time3 - time2_2));
System.out.println("Saving database...");
System.out.println("Root size: " + root.size());
});
long time2_2 = System.currentTimeMillis();
System.out.println("Time elapsed: " + (time2_2 - time2_1));
System.out.println("Used memory: "
+ ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
System.out.println("Used memory: " + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
System.out.println("Cleaning database (to reduce the amount of used memory and detect memory leaks)...");
long removedItems = db.clean();
long time3 = System.currentTimeMillis();
System.out.println("Removed items: " + removedItems);
System.out.println("Used memory: " + ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024) + "MB");
System.out.println("Time elapsed: " + (time3 - time2_2));
System.out.println("Saving database...");
System.out.println("Root size: " + root.size());
db.close();
long time4 = System.currentTimeMillis();
System.out.println("Time elapsed: " + (time4 - time3));

View File

@ -41,14 +41,14 @@ public class AppTest
JCWDatabase db = new JCWDatabase(path, idx);
EntryReference<LightList<CustomClass>> ref = db.getRoot();
LightList<CustomClass> root = ref.value;
root.add(customClass);
ref.editValue((root, saver) -> {
root.add(customClass);
});
db.close();
JCWDatabase db2 = new JCWDatabase(path, idx);
EntryReference<LightList<CustomClass>> ref2 = db2.getRoot();
LightList<CustomClass> root2 = ref2.value;
CustomClass customClass2 = root2.get(0);
CustomClass customClass2 = ref2.getValueReadOnly().getReadOnlyValue(0);
assertTrue(customClass.equals(customClass2));
assertTrue(customClass.string.equals(customClass2.string));
db2.close();
@ -99,7 +99,7 @@ public class AppTest
Path path = Files.createTempFile("", ".db"), idx = Files.createTempFile("", ".idx");
JCWDatabase db = new JCWDatabase(path, idx);
EntryReference<LightList<String>> ref = db.getRoot();
LightList<String> list1 = ref.value;
LightList<String> list1 = ref.getValueReadOnly();
ArrayList<String> list2 = new ArrayList<String>();
String s = "a";
for (int i = 0; i < 10; i++) {