Storage now depends on StorageKey (instead of ByteArrayWrapper), in order
to make it clear that it must be a SHA256 hash, and not just bytes of arbitrary length.
This commit is contained in:
parent
2a7d8397e7
commit
6decb2b234
@ -27,7 +27,6 @@ import org.slf4j.Logger;
|
|||||||
|
|
||||||
import dorkbox.util.DelayTimer;
|
import dorkbox.util.DelayTimer;
|
||||||
import dorkbox.util.SerializationManager;
|
import dorkbox.util.SerializationManager;
|
||||||
import dorkbox.util.bytes.ByteArrayWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +37,7 @@ import dorkbox.util.bytes.ByteArrayWrapper;
|
|||||||
@SuppressWarnings({"Convert2Diamond", "Convert2Lambda"})
|
@SuppressWarnings({"Convert2Diamond", "Convert2Lambda"})
|
||||||
class DiskStorage implements Storage {
|
class DiskStorage implements Storage {
|
||||||
private final DelayTimer timer;
|
private final DelayTimer timer;
|
||||||
private final ByteArrayWrapper defaultKey;
|
private final StorageKey defaultKey;
|
||||||
private final StorageBase storage;
|
private final StorageBase storage;
|
||||||
|
|
||||||
private final AtomicInteger references = new AtomicInteger(1);
|
private final AtomicInteger references = new AtomicInteger(1);
|
||||||
@ -46,14 +45,14 @@ class DiskStorage implements Storage {
|
|||||||
private final AtomicBoolean isOpen = new AtomicBoolean(false);
|
private final AtomicBoolean isOpen = new AtomicBoolean(false);
|
||||||
private volatile long milliSeconds = 3000L;
|
private volatile long milliSeconds = 3000L;
|
||||||
|
|
||||||
private volatile Map<ByteArrayWrapper, Object> actionMap = new ConcurrentHashMap<ByteArrayWrapper, Object>();
|
private volatile Map<StorageKey, Object> actionMap = new ConcurrentHashMap<StorageKey, Object>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates or opens a new database file.
|
* Creates or opens a new database file.
|
||||||
*/
|
*/
|
||||||
DiskStorage(File storageFile, SerializationManager serializationManager, final boolean readOnly, final Logger logger) throws IOException {
|
DiskStorage(File storageFile, SerializationManager serializationManager, final boolean readOnly, final Logger logger) throws IOException {
|
||||||
this.storage = new StorageBase(storageFile, serializationManager, logger);
|
this.storage = new StorageBase(storageFile, serializationManager, logger);
|
||||||
this.defaultKey = ByteArrayWrapper.wrap("");
|
this.defaultKey = new StorageKey("");
|
||||||
|
|
||||||
if (readOnly) {
|
if (readOnly) {
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
@ -65,12 +64,12 @@ class DiskStorage implements Storage {
|
|||||||
void run() {
|
void run() {
|
||||||
ReentrantLock actionLock2 = DiskStorage.this.actionLock;
|
ReentrantLock actionLock2 = DiskStorage.this.actionLock;
|
||||||
|
|
||||||
Map<ByteArrayWrapper, Object> actions;
|
Map<StorageKey, Object> actions;
|
||||||
try {
|
try {
|
||||||
actionLock2.lock();
|
actionLock2.lock();
|
||||||
// do a fast swap on the actionMap.
|
// do a fast swap on the actionMap.
|
||||||
actions = DiskStorage.this.actionMap;
|
actions = DiskStorage.this.actionMap;
|
||||||
DiskStorage.this.actionMap = new ConcurrentHashMap<ByteArrayWrapper, Object>();
|
DiskStorage.this.actionMap = new ConcurrentHashMap<StorageKey, Object>();
|
||||||
} finally {
|
} finally {
|
||||||
actionLock2.unlock();
|
actionLock2.unlock();
|
||||||
}
|
}
|
||||||
@ -116,7 +115,7 @@ class DiskStorage implements Storage {
|
|||||||
throw new RuntimeException("Unable to act on closed storage");
|
throw new RuntimeException("Unable to act on closed storage");
|
||||||
}
|
}
|
||||||
|
|
||||||
final ByteArrayWrapper wrap = ByteArrayWrapper.wrap(key);
|
final StorageKey wrap = new StorageKey(key);
|
||||||
// check if our pending actions has it, or if our storage index has it
|
// check if our pending actions has it, or if our storage index has it
|
||||||
return this.actionMap.containsKey(wrap) || this.storage.contains(wrap);
|
return this.actionMap.containsKey(wrap) || this.storage.contains(wrap);
|
||||||
}
|
}
|
||||||
@ -140,7 +139,7 @@ class DiskStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
<T> T get(String key) throws IOException {
|
<T> T get(String key) throws IOException {
|
||||||
return get0(ByteArrayWrapper.wrap(key));
|
return get0(new StorageKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,7 +150,7 @@ class DiskStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
<T> T get(byte[] key) throws IOException {
|
<T> T get(byte[] key) throws IOException {
|
||||||
return get0(ByteArrayWrapper.wrap(key));
|
return get0(new StorageKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -161,7 +160,7 @@ class DiskStorage implements Storage {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
<T> T get(ByteArrayWrapper key) throws IOException {
|
<T> T get(StorageKey key) throws IOException {
|
||||||
return get0(key);
|
return get0(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +185,7 @@ class DiskStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T getAndPut(String key, T data) throws IOException {
|
<T> T getAndPut(String key, T data) throws IOException {
|
||||||
ByteArrayWrapper wrap = ByteArrayWrapper.wrap(key);
|
StorageKey wrap = new StorageKey(key);
|
||||||
|
|
||||||
return getAndPut(wrap, data);
|
return getAndPut(wrap, data);
|
||||||
}
|
}
|
||||||
@ -199,7 +198,7 @@ class DiskStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T getAndPut(byte[] key, T data) throws IOException {
|
<T> T getAndPut(byte[] key, T data) throws IOException {
|
||||||
return getAndPut(ByteArrayWrapper.wrap(key), data);
|
return getAndPut(new StorageKey(key), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,7 +209,7 @@ class DiskStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public
|
public
|
||||||
<T> T getAndPut(ByteArrayWrapper key, T data) throws IOException {
|
<T> T getAndPut(StorageKey key, T data) throws IOException {
|
||||||
Object source = get0(key);
|
Object source = get0(key);
|
||||||
|
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
@ -236,7 +235,7 @@ class DiskStorage implements Storage {
|
|||||||
* @throws IOException if there is a problem deserializing data from disk
|
* @throws IOException if there is a problem deserializing data from disk
|
||||||
*/
|
*/
|
||||||
private
|
private
|
||||||
<T> T get0(ByteArrayWrapper key) throws IOException {
|
<T> T get0(StorageKey key) throws IOException {
|
||||||
if (!this.isOpen.get()) {
|
if (!this.isOpen.get()) {
|
||||||
throw new RuntimeException("Unable to act on closed storage");
|
throw new RuntimeException("Unable to act on closed storage");
|
||||||
}
|
}
|
||||||
@ -269,7 +268,7 @@ class DiskStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
void put(String key, Object object) {
|
void put(String key, Object object) {
|
||||||
put(ByteArrayWrapper.wrap(key), object);
|
put(new StorageKey(key), object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -281,7 +280,7 @@ class DiskStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
void put(byte[] key, Object object) {
|
void put(byte[] key, Object object) {
|
||||||
put(ByteArrayWrapper.wrap(key), object);
|
put(new StorageKey(key), object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -292,7 +291,7 @@ class DiskStorage implements Storage {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
void put(ByteArrayWrapper key, Object object) {
|
void put(StorageKey key, Object object) {
|
||||||
if (!this.isOpen.get()) {
|
if (!this.isOpen.get()) {
|
||||||
throw new RuntimeException("Unable to act on closed storage");
|
throw new RuntimeException("Unable to act on closed storage");
|
||||||
}
|
}
|
||||||
@ -338,7 +337,7 @@ class DiskStorage implements Storage {
|
|||||||
throw new RuntimeException("Unable to act on closed storage");
|
throw new RuntimeException("Unable to act on closed storage");
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArrayWrapper wrap = ByteArrayWrapper.wrap(key);
|
StorageKey wrap = new StorageKey(key);
|
||||||
|
|
||||||
// timer action runs on THIS thread, not timer thread
|
// timer action runs on THIS thread, not timer thread
|
||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
@ -357,7 +356,7 @@ class DiskStorage implements Storage {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
boolean delete(ByteArrayWrapper key) {
|
boolean delete(StorageKey key) {
|
||||||
if (!this.isOpen.get()) {
|
if (!this.isOpen.get()) {
|
||||||
throw new RuntimeException("Unable to act on closed storage");
|
throw new RuntimeException("Unable to act on closed storage");
|
||||||
}
|
}
|
||||||
@ -471,7 +470,7 @@ class DiskStorage implements Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
void action(ByteArrayWrapper key, Object object) {
|
void action(StorageKey key, Object object) {
|
||||||
try {
|
try {
|
||||||
this.actionLock.lock();
|
this.actionLock.lock();
|
||||||
|
|
||||||
@ -537,7 +536,7 @@ class DiskStorage implements Storage {
|
|||||||
|
|
||||||
// timer action runs on THIS thread, not timer thread
|
// timer action runs on THIS thread, not timer thread
|
||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
action(ByteArrayWrapper.wrap(key), object);
|
action(new StorageKey(key), object);
|
||||||
this.timer.delay(0L);
|
this.timer.delay(0L);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -555,7 +554,7 @@ class DiskStorage implements Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (timer != null) {
|
if (timer != null) {
|
||||||
action(ByteArrayWrapper.wrap(key), object);
|
action(new StorageKey(key), object);
|
||||||
|
|
||||||
// timer action runs on THIS thread, not timer thread
|
// timer action runs on THIS thread, not timer thread
|
||||||
this.timer.delay(0L);
|
this.timer.delay(0L);
|
||||||
@ -570,7 +569,7 @@ class DiskStorage implements Storage {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void putAndSave(final ByteArrayWrapper key, final Object object) {
|
void putAndSave(final StorageKey key, final Object object) {
|
||||||
if (!this.isOpen.get()) {
|
if (!this.isOpen.get()) {
|
||||||
throw new RuntimeException("Unable to act on closed storage");
|
throw new RuntimeException("Unable to act on closed storage");
|
||||||
}
|
}
|
||||||
|
@ -19,20 +19,18 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import dorkbox.util.bytes.ByteArrayWrapper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Storage that is in memory only (and is not persisted to disk)
|
* Storage that is in memory only (and is not persisted to disk)
|
||||||
*/
|
*/
|
||||||
class MemoryStorage implements Storage {
|
class MemoryStorage implements Storage {
|
||||||
private final ConcurrentHashMap<ByteArrayWrapper, Object> storage;
|
private final ConcurrentHashMap<StorageKey, Object> storage;
|
||||||
private final ByteArrayWrapper defaultKey;
|
private final StorageKey defaultKey;
|
||||||
private int version;
|
private int version;
|
||||||
|
|
||||||
|
|
||||||
MemoryStorage() {
|
MemoryStorage() {
|
||||||
this.storage = new ConcurrentHashMap<ByteArrayWrapper, Object>();
|
this.storage = new ConcurrentHashMap<StorageKey, Object>();
|
||||||
this.defaultKey = ByteArrayWrapper.wrap("");
|
this.defaultKey = new StorageKey("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +49,7 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
boolean contains(final String key) {
|
boolean contains(final String key) {
|
||||||
return storage.containsKey(ByteArrayWrapper.wrap(key));
|
return storage.containsKey(new StorageKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +68,7 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T get(final String key) {
|
<T> T get(final String key) {
|
||||||
return get(ByteArrayWrapper.wrap(key));
|
return get(new StorageKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -79,7 +77,7 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T get(final byte[] key) {
|
<T> T get(final byte[] key) {
|
||||||
return get(ByteArrayWrapper.wrap(key));
|
return get(new StorageKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,7 +86,7 @@ class MemoryStorage implements Storage {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T get(final ByteArrayWrapper key) {
|
<T> T get(final StorageKey key) {
|
||||||
return (T) storage.get(key);
|
return (T) storage.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +111,7 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T getAndPut(String key, T data) throws IOException {
|
<T> T getAndPut(String key, T data) throws IOException {
|
||||||
ByteArrayWrapper wrap = ByteArrayWrapper.wrap(key);
|
StorageKey wrap = new StorageKey(key);
|
||||||
|
|
||||||
return getAndPut(wrap, data);
|
return getAndPut(wrap, data);
|
||||||
}
|
}
|
||||||
@ -126,13 +124,13 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T getAndPut(byte[] key, T data) throws IOException {
|
<T> T getAndPut(byte[] key, T data) throws IOException {
|
||||||
return getAndPut(ByteArrayWrapper.wrap(key), data);
|
return getAndPut(new StorageKey(key), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
<T> T getAndPut(final ByteArrayWrapper key, final T data) throws IOException {
|
<T> T getAndPut(final StorageKey key, final T data) throws IOException {
|
||||||
final Object o = storage.get(key);
|
final Object o = storage.get(key);
|
||||||
if (o == null) {
|
if (o == null) {
|
||||||
storage.put(key, data);
|
storage.put(key, data);
|
||||||
@ -150,7 +148,7 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void put(final String key, final Object data) {
|
void put(final String key, final Object data) {
|
||||||
put(ByteArrayWrapper.wrap(key), data);
|
put(new StorageKey(key), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,7 +160,7 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void put(final byte[] key, final Object data) {
|
void put(final byte[] key, final Object data) {
|
||||||
put(ByteArrayWrapper.wrap(key), data);
|
put(new StorageKey(key), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -173,7 +171,7 @@ class MemoryStorage implements Storage {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void put(final ByteArrayWrapper key, final Object object) {
|
void put(final StorageKey key, final Object object) {
|
||||||
storage.put(key, object);
|
storage.put(key, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +195,7 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
boolean delete(final String key) {
|
boolean delete(final String key) {
|
||||||
return delete(ByteArrayWrapper.wrap(key));
|
return delete(new StorageKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -207,7 +205,7 @@ class MemoryStorage implements Storage {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
boolean delete(final ByteArrayWrapper key) {
|
boolean delete(final StorageKey key) {
|
||||||
storage.remove(key);
|
storage.remove(key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -262,18 +260,21 @@ class MemoryStorage implements Storage {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void putAndSave(final String key, final Object object) {
|
void putAndSave(final String key, final Object object) {
|
||||||
// no-op
|
put(key, object);
|
||||||
|
// no-save!
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void putAndSave(final byte[] key, final Object object) {
|
void putAndSave(final byte[] key, final Object object) {
|
||||||
// no-op
|
put(key, object);
|
||||||
|
// no-save!
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void putAndSave(final ByteArrayWrapper key, final Object object) {
|
void putAndSave(final StorageKey key, final Object object) {
|
||||||
// no-op
|
put(key, object);
|
||||||
|
// no-save!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ import com.esotericsoftware.kryo.io.Input;
|
|||||||
import com.esotericsoftware.kryo.io.Output;
|
import com.esotericsoftware.kryo.io.Output;
|
||||||
|
|
||||||
import dorkbox.util.SerializationManager;
|
import dorkbox.util.SerializationManager;
|
||||||
import dorkbox.util.bytes.ByteArrayWrapper;
|
|
||||||
|
|
||||||
public
|
public
|
||||||
class Metadata {
|
class Metadata {
|
||||||
@ -44,7 +43,7 @@ class Metadata {
|
|||||||
/**
|
/**
|
||||||
* This is the key to the index
|
* This is the key to the index
|
||||||
*/
|
*/
|
||||||
final ByteArrayWrapper key;
|
final StorageKey key;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates this header's position in the file index.
|
* Indicates this header's position in the file index.
|
||||||
@ -86,25 +85,26 @@ class Metadata {
|
|||||||
* Returns a file pointer in the index pointing to the first byte in the RECORD pointer located at the given index
|
* Returns a file pointer in the index pointing to the first byte in the RECORD pointer located at the given index
|
||||||
* position.
|
* position.
|
||||||
*/
|
*/
|
||||||
static
|
private static
|
||||||
long getDataPointer(int position) {
|
long getDataPointer(int position) {
|
||||||
return Metadata.getMetaDataPointer(position) + KEY_SIZE;
|
return Metadata.getMetaDataPointer(position) + KEY_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private
|
private
|
||||||
Metadata(ByteArrayWrapper key) {
|
Metadata(StorageKey key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we don't know how much data there is until AFTER we write the data
|
* we don't know how much data there is until AFTER we write the data
|
||||||
*/
|
*/
|
||||||
Metadata(ByteArrayWrapper key, int recordIndex, long dataPointer) {
|
Metadata(StorageKey key, int recordIndex, long dataPointer) {
|
||||||
this(key, recordIndex, dataPointer, 0);
|
this(key, recordIndex, dataPointer, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Metadata(ByteArrayWrapper key, int recordIndex, long dataPointer, int dataCapacity) {
|
private
|
||||||
|
Metadata(StorageKey key, int recordIndex, long dataPointer, int dataCapacity) {
|
||||||
if (key.getBytes().length > KEY_SIZE) {
|
if (key.getBytes().length > KEY_SIZE) {
|
||||||
throw new IllegalArgumentException("Bad record key size: " + dataCapacity);
|
throw new IllegalArgumentException("Bad record key size: " + dataCapacity);
|
||||||
}
|
}
|
||||||
@ -119,6 +119,7 @@ class Metadata {
|
|||||||
this.dataCount = dataCapacity;
|
this.dataCount = dataCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
int getFreeSpace() {
|
int getFreeSpace() {
|
||||||
return this.dataCapacity - this.dataCount;
|
return this.dataCapacity - this.dataCount;
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ class Metadata {
|
|||||||
|
|
||||||
lock.release();
|
lock.release();
|
||||||
|
|
||||||
Metadata r = new Metadata(ByteArrayWrapper.wrap(buf));
|
Metadata r = new Metadata(new StorageKey(buf));
|
||||||
r.indexPosition = position;
|
r.indexPosition = position;
|
||||||
|
|
||||||
long recordHeaderPointer = Metadata.getDataPointer(position);
|
long recordHeaderPointer = Metadata.getDataPointer(position);
|
||||||
@ -247,6 +248,7 @@ class Metadata {
|
|||||||
/**
|
/**
|
||||||
* Reads the record data for the given record header.
|
* Reads the record data for the given record header.
|
||||||
*/
|
*/
|
||||||
|
private
|
||||||
byte[] readDataRaw(RandomAccessFile file) throws IOException {
|
byte[] readDataRaw(RandomAccessFile file) throws IOException {
|
||||||
|
|
||||||
byte[] buf = new byte[this.dataCount];
|
byte[] buf = new byte[this.dataCount];
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.util.storage;
|
package dorkbox.util.storage;
|
||||||
|
|
||||||
import dorkbox.util.bytes.ByteArrayWrapper;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -53,7 +51,7 @@ interface Storage {
|
|||||||
/**
|
/**
|
||||||
* Reads a object using the specific key, and casts it to the expected class
|
* Reads a object using the specific key, and casts it to the expected class
|
||||||
*/
|
*/
|
||||||
<T> T get(ByteArrayWrapper key) throws IOException;
|
<T> T get(StorageKey key) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses the DEFAULT key ("") to return saved data.
|
* Uses the DEFAULT key ("") to return saved data.
|
||||||
@ -86,7 +84,7 @@ interface Storage {
|
|||||||
* @param key The key used to check if data already exists.
|
* @param key The key used to check if data already exists.
|
||||||
* @param data This is the default value, and if there is no value with the key in the DB this default value will be saved.
|
* @param data This is the default value, and if there is no value with the key in the DB this default value will be saved.
|
||||||
*/
|
*/
|
||||||
<T> T getAndPut(ByteArrayWrapper key, T data) throws IOException;
|
<T> T getAndPut(StorageKey key, T data) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the given data to storage with the associated key.
|
* Saves the given data to storage with the associated key.
|
||||||
@ -110,7 +108,7 @@ interface Storage {
|
|||||||
* Also will update existing data. If the new contents do not fit in the original space, then the update is handled by
|
* Also will update existing data. If the new contents do not fit in the original space, then the update is handled by
|
||||||
* deleting the old data and adding the new.
|
* deleting the old data and adding the new.
|
||||||
*/
|
*/
|
||||||
void put(ByteArrayWrapper key, Object data);
|
void put(StorageKey key, Object data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given object to the storage using a default (blank) key, OR -- if it has been registered, using it's registered key
|
* Adds the given object to the storage using a default (blank) key, OR -- if it has been registered, using it's registered key
|
||||||
@ -132,7 +130,7 @@ interface Storage {
|
|||||||
*
|
*
|
||||||
* @return true if the delete was successful. False if there were problems deleting the data.
|
* @return true if the delete was successful. False if there were problems deleting the data.
|
||||||
*/
|
*/
|
||||||
boolean delete(ByteArrayWrapper key);
|
boolean delete(StorageKey key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the file that backs this storage
|
* @return the file that backs this storage
|
||||||
@ -197,5 +195,5 @@ interface Storage {
|
|||||||
* <p/>
|
* <p/>
|
||||||
* This will save the ALL of the pending save actions to the file
|
* This will save the ALL of the pending save actions to the file
|
||||||
*/
|
*/
|
||||||
void putAndSave(ByteArrayWrapper key, Object object);
|
void putAndSave(StorageKey key, Object object);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ import com.esotericsoftware.kryo.io.Output;
|
|||||||
|
|
||||||
import dorkbox.util.OS;
|
import dorkbox.util.OS;
|
||||||
import dorkbox.util.SerializationManager;
|
import dorkbox.util.SerializationManager;
|
||||||
import dorkbox.util.bytes.ByteArrayWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
// a note on file locking between c and java
|
// a note on file locking between c and java
|
||||||
@ -65,7 +64,7 @@ class StorageBase {
|
|||||||
|
|
||||||
|
|
||||||
// The in-memory index (for efficiency, all of the record info is cached in memory).
|
// The in-memory index (for efficiency, all of the record info is cached in memory).
|
||||||
private final Map<ByteArrayWrapper, Metadata> memoryIndex;
|
private final Map<StorageKey, Metadata> memoryIndex;
|
||||||
|
|
||||||
// determines how much the index will grow by
|
// determines how much the index will grow by
|
||||||
private final Float weight;
|
private final Float weight;
|
||||||
@ -174,7 +173,7 @@ class StorageBase {
|
|||||||
|
|
||||||
//noinspection AutoBoxing
|
//noinspection AutoBoxing
|
||||||
this.weight = 0.5F;
|
this.weight = 0.5F;
|
||||||
this.memoryIndex = new ConcurrentHashMap<ByteArrayWrapper, Metadata>(this.numberOfRecords);
|
this.memoryIndex = new ConcurrentHashMap<StorageKey, Metadata>(this.numberOfRecords);
|
||||||
|
|
||||||
if (!newStorage) {
|
if (!newStorage) {
|
||||||
Metadata meta;
|
Metadata meta;
|
||||||
@ -210,7 +209,7 @@ class StorageBase {
|
|||||||
* Checks if there is a record belonging to the given key.
|
* Checks if there is a record belonging to the given key.
|
||||||
*/
|
*/
|
||||||
final
|
final
|
||||||
boolean contains(ByteArrayWrapper key) {
|
boolean contains(StorageKey key) {
|
||||||
// protected by lock
|
// protected by lock
|
||||||
|
|
||||||
// check to see if it's in the pending ops
|
// check to see if it's in the pending ops
|
||||||
@ -221,7 +220,7 @@ class StorageBase {
|
|||||||
* @return an object for a specified key ONLY FROM THE REFERENCE CACHE
|
* @return an object for a specified key ONLY FROM THE REFERENCE CACHE
|
||||||
*/
|
*/
|
||||||
final
|
final
|
||||||
<T> T getCached(ByteArrayWrapper key) {
|
<T> T getCached(StorageKey key) {
|
||||||
// protected by lock
|
// protected by lock
|
||||||
|
|
||||||
Metadata meta = this.memoryIndex.get(key);
|
Metadata meta = this.memoryIndex.get(key);
|
||||||
@ -253,7 +252,7 @@ class StorageBase {
|
|||||||
* @return an object for a specified key form referenceCache FIRST, then from DISK
|
* @return an object for a specified key form referenceCache FIRST, then from DISK
|
||||||
*/
|
*/
|
||||||
final
|
final
|
||||||
<T> T get(ByteArrayWrapper key) throws IOException {
|
<T> T get(StorageKey key) throws IOException {
|
||||||
// NOT protected by lock
|
// NOT protected by lock
|
||||||
|
|
||||||
Metadata meta = this.memoryIndex.get(key);
|
Metadata meta = this.memoryIndex.get(key);
|
||||||
@ -314,7 +313,7 @@ class StorageBase {
|
|||||||
* @return true if the delete was successful. False if there were problems deleting the data.
|
* @return true if the delete was successful. False if there were problems deleting the data.
|
||||||
*/
|
*/
|
||||||
final
|
final
|
||||||
boolean delete(ByteArrayWrapper key) {
|
boolean delete(StorageKey key) {
|
||||||
// pending ops flushed (protected by lock)
|
// pending ops flushed (protected by lock)
|
||||||
// not protected by lock
|
// not protected by lock
|
||||||
Metadata delRec = this.memoryIndex.get(key);
|
Metadata delRec = this.memoryIndex.get(key);
|
||||||
@ -398,7 +397,7 @@ class StorageBase {
|
|||||||
* Will also save the object in a cache.
|
* Will also save the object in a cache.
|
||||||
*/
|
*/
|
||||||
private
|
private
|
||||||
void save0(ByteArrayWrapper key, Object object) {
|
void save0(StorageKey key, Object object) {
|
||||||
Metadata metaData = this.memoryIndex.get(key);
|
Metadata metaData = this.memoryIndex.get(key);
|
||||||
int currentRecordCount = this.numberOfRecords;
|
int currentRecordCount = this.numberOfRecords;
|
||||||
|
|
||||||
@ -519,15 +518,15 @@ class StorageBase {
|
|||||||
return outputStream;
|
return outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
void doActionThings(Map<ByteArrayWrapper, Object> actions) {
|
void doActionThings(Map<StorageKey, Object> actions) {
|
||||||
|
|
||||||
// actions is thrown away after this invocation. GC can pick it up.
|
// actions is thrown away after this invocation. GC can pick it up.
|
||||||
// we are only interested in the LAST action that happened for some data.
|
// we are only interested in the LAST action that happened for some data.
|
||||||
// items to be "autosaved" are automatically injected into "actions".
|
// items to be "autosaved" are automatically injected into "actions".
|
||||||
final Set<Entry<ByteArrayWrapper, Object>> entries = actions.entrySet();
|
final Set<Entry<StorageKey, Object>> entries = actions.entrySet();
|
||||||
for (Entry<ByteArrayWrapper, Object> entry : entries) {
|
for (Entry<StorageKey, Object> entry : entries) {
|
||||||
Object object = entry.getValue();
|
Object object = entry.getValue();
|
||||||
ByteArrayWrapper key = entry.getKey();
|
StorageKey key = entry.getKey();
|
||||||
|
|
||||||
// our action list is for explicitly saving objects (but not necessarily "registering" them to be auto-saved
|
// our action list is for explicitly saving objects (but not necessarily "registering" them to be auto-saved
|
||||||
save0(key, object);
|
save0(key, object);
|
||||||
@ -612,7 +611,7 @@ class StorageBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private
|
private
|
||||||
void deleteRecordIndex(ByteArrayWrapper key, Metadata deleteRecord) throws IOException {
|
void deleteRecordIndex(StorageKey key, Metadata deleteRecord) throws IOException {
|
||||||
int currentNumRecords = this.memoryIndex.size();
|
int currentNumRecords = this.memoryIndex.size();
|
||||||
|
|
||||||
if (deleteRecord.indexPosition != currentNumRecords - 1) {
|
if (deleteRecord.indexPosition != currentNumRecords - 1) {
|
||||||
|
20
src/dorkbox/util/storage/StorageKey.java
Normal file
20
src/dorkbox/util/storage/StorageKey.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package dorkbox.util.storage;
|
||||||
|
|
||||||
|
import dorkbox.util.HashUtil;
|
||||||
|
import dorkbox.util.bytes.ByteArrayWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a ByteArrayWrapper that is really a SHA256 hash of the bytes.
|
||||||
|
*/
|
||||||
|
public
|
||||||
|
class StorageKey extends ByteArrayWrapper {
|
||||||
|
public
|
||||||
|
StorageKey(String key) {
|
||||||
|
super(HashUtil.getSha256(key), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public
|
||||||
|
StorageKey(byte[] key) {
|
||||||
|
super(key, false);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user