Simplified storage API. Throws RuntimeException if trying to write to a
read-only storage.
This commit is contained in:
parent
ec84231b1b
commit
85a745dc3a
@ -36,6 +36,7 @@ import dorkbox.util.SerializationManager;
|
||||
*/
|
||||
@SuppressWarnings({"Convert2Diamond", "Convert2Lambda"})
|
||||
class DiskStorage implements Storage {
|
||||
// null if we are a read-only storage
|
||||
private final DelayTimer timer;
|
||||
private final StorageBase storage;
|
||||
|
||||
@ -60,16 +61,16 @@ class DiskStorage implements Storage {
|
||||
@Override
|
||||
public
|
||||
void run() {
|
||||
ReentrantLock actionLock2 = DiskStorage.this.actionLock;
|
||||
ReentrantLock actionLock = DiskStorage.this.actionLock;
|
||||
|
||||
Map<StorageKey, Object> actions;
|
||||
try {
|
||||
actionLock2.lock();
|
||||
actionLock.lock();
|
||||
// do a fast swap on the actionMap.
|
||||
actions = DiskStorage.this.actionMap;
|
||||
DiskStorage.this.actionMap = new ConcurrentHashMap<StorageKey, Object>();
|
||||
} finally {
|
||||
actionLock2.unlock();
|
||||
actionLock.unlock();
|
||||
}
|
||||
|
||||
DiskStorage.this.storage.doActionThings(actions);
|
||||
@ -108,32 +109,13 @@ class DiskStorage implements Storage {
|
||||
*/
|
||||
@Override
|
||||
public final
|
||||
boolean contains(String key) {
|
||||
boolean contains(StorageKey key) {
|
||||
if (!this.isOpen.get()) {
|
||||
throw new RuntimeException("Unable to act on closed storage");
|
||||
}
|
||||
|
||||
final StorageKey wrap = new StorageKey(key);
|
||||
// check if our pending actions has it, or if our storage index has it
|
||||
return this.actionMap.containsKey(wrap) || this.storage.contains(wrap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a object using the specific key, and casts it to the expected class
|
||||
*/
|
||||
@Override
|
||||
public final
|
||||
<T> T get(String key) {
|
||||
return get0(new StorageKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a object using the specific key, and casts it to the expected class
|
||||
*/
|
||||
@Override
|
||||
public final
|
||||
<T> T get(byte[] key) {
|
||||
return get0(new StorageKey(key));
|
||||
return this.actionMap.containsKey(key) || this.storage.contains(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,31 +128,7 @@ class DiskStorage implements Storage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved data for the specified key. Also saves the data.
|
||||
*
|
||||
* @param data If there is no object in the DB with the specified key, this value will be the default (and will be saved to the db)
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
<T> T get(String key, T data) {
|
||||
StorageKey wrap = new StorageKey(key);
|
||||
|
||||
return get(wrap, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved data for the specified key. Also saves the data.
|
||||
*
|
||||
* @param data If there is no object in the DB with the specified key, this value will be the default (and will be saved to the db)
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
<T> T get(byte[] key, T data) {
|
||||
return get(new StorageKey(key), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved data (or null) for the specified key. Also saves the data.
|
||||
* Returns the saved data (or null) for the specified key. Also saves the data as default data.
|
||||
*
|
||||
* @param data If there is no object in the DB with the specified key, this value will be the default (and will be saved to the db)
|
||||
*
|
||||
@ -184,7 +142,7 @@ class DiskStorage implements Storage {
|
||||
|
||||
if (source == null) {
|
||||
// returned was null, so we should save the default value
|
||||
putAndSave(key, data);
|
||||
put(key, data);
|
||||
return data;
|
||||
}
|
||||
else {
|
||||
@ -236,30 +194,6 @@ class DiskStorage implements Storage {
|
||||
return this.storage.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public final
|
||||
void put(String key, Object object) {
|
||||
put(new StorageKey(key), object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public final
|
||||
void put(byte[] key, Object object) {
|
||||
put(new StorageKey(key), object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
@ -274,34 +208,24 @@ class DiskStorage implements Storage {
|
||||
}
|
||||
|
||||
if (timer != null) {
|
||||
action(key, object);
|
||||
try {
|
||||
this.actionLock.lock();
|
||||
|
||||
if (object != null) {
|
||||
// push action to map
|
||||
this.actionMap.put(key, object);
|
||||
}
|
||||
else {
|
||||
this.actionMap.remove(key);
|
||||
}
|
||||
} finally {
|
||||
this.actionLock.unlock();
|
||||
}
|
||||
|
||||
// timer action runs on TIMER thread, not this thread
|
||||
this.timer.delay(this.milliSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an object from storage.
|
||||
*
|
||||
* @return true if the delete was successful. False if there were problems deleting the data.
|
||||
*/
|
||||
@Override
|
||||
public final
|
||||
boolean delete(String key) {
|
||||
if (!this.isOpen.get()) {
|
||||
throw new RuntimeException("Unable to act on closed storage");
|
||||
}
|
||||
|
||||
StorageKey wrap = new StorageKey(key);
|
||||
|
||||
// timer action runs on THIS thread, not timer thread
|
||||
if (timer != null) {
|
||||
this.timer.delay(0L);
|
||||
return this.storage.delete(wrap);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
} else {
|
||||
throw new RuntimeException("Unable to put on a read-only storage");
|
||||
}
|
||||
}
|
||||
|
||||
@ -323,13 +247,14 @@ class DiskStorage implements Storage {
|
||||
return this.storage.delete(key);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
throw new RuntimeException("Unable to delete on a read-only storage");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes and removes this storage from the storage system. This is the same as calling {@link StorageSystem#close(Storage)}
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void close() {
|
||||
StorageSystem.close(this);
|
||||
@ -433,24 +358,6 @@ class DiskStorage implements Storage {
|
||||
this.storage.setVersion(version);
|
||||
}
|
||||
|
||||
private
|
||||
void action(StorageKey key, Object object) {
|
||||
try {
|
||||
this.actionLock.lock();
|
||||
|
||||
if (object != null) {
|
||||
// push action to map
|
||||
this.actionMap.put(key, object);
|
||||
} else {
|
||||
this.actionMap.remove(key);
|
||||
}
|
||||
|
||||
|
||||
} finally {
|
||||
this.actionLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void increaseReference() {
|
||||
this.references.incrementAndGet();
|
||||
}
|
||||
@ -483,66 +390,8 @@ class DiskStorage implements Storage {
|
||||
// timer action runs on THIS thread, not timer thread
|
||||
if (timer != null) {
|
||||
this.timer.delay(0L);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage, then saves the storage to disk, immediately.
|
||||
* <p/>
|
||||
* This will save ALL of the pending save actions to the file
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void putAndSave(final String key, final Object object) {
|
||||
if (!this.isOpen.get()) {
|
||||
throw new RuntimeException("Unable to act on closed storage");
|
||||
}
|
||||
|
||||
// timer action runs on THIS thread, not timer thread
|
||||
if (timer != null) {
|
||||
action(new StorageKey(key), object);
|
||||
this.timer.delay(0L);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage, then save the storage to disk, immediately.
|
||||
* <p/>
|
||||
* This will save ALL of the pending save actions to the file
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void putAndSave(final byte[] key, final Object object) {
|
||||
if (!this.isOpen.get()) {
|
||||
throw new RuntimeException("Unable to act on closed storage");
|
||||
}
|
||||
|
||||
if (timer != null) {
|
||||
action(new StorageKey(key), object);
|
||||
|
||||
// timer action runs on THIS thread, not timer thread
|
||||
this.timer.delay(0L);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage, then save the storage to disk, immediately.
|
||||
* <p/>
|
||||
* This will save ALL of the pending save actions to the file
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void putAndSave(final StorageKey key, final Object object) {
|
||||
if (!this.isOpen.get()) {
|
||||
throw new RuntimeException("Unable to act on closed storage");
|
||||
}
|
||||
|
||||
if (timer != null) {
|
||||
action(key, object);
|
||||
|
||||
// timer action runs on THIS thread, not timer thread
|
||||
this.timer.delay(0L);
|
||||
} else {
|
||||
throw new RuntimeException("Unable to save on a read-only storage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,26 +45,8 @@ class MemoryStorage implements Storage {
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
boolean contains(final String key) {
|
||||
return storage.containsKey(new StorageKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a object using the specific key, and casts it to the expected class
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
<T> T get(final String key) {
|
||||
return get(new StorageKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a object using the specific key, and casts it to the expected class
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
<T> T get(final byte[] key) {
|
||||
return get(new StorageKey(key));
|
||||
boolean contains(final StorageKey key) {
|
||||
return storage.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,30 +59,6 @@ class MemoryStorage implements Storage {
|
||||
return (T) storage.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved data for the specified key.
|
||||
*
|
||||
* @param data If there is no object in the DB with the specified key, this value will be the default (and will be saved to the db)
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
<T> T get(String key, T data) {
|
||||
StorageKey wrap = new StorageKey(key);
|
||||
|
||||
return get(wrap, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saved data for the specified key.
|
||||
*
|
||||
* @param data If there is no object in the DB with the specified key, this value will be the default (and will be saved to the db)
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
<T> T get(byte[] key, T data) {
|
||||
return get(new StorageKey(key), data);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public
|
||||
@ -113,30 +71,6 @@ class MemoryStorage implements Storage {
|
||||
return (T) o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void put(final String key, final Object data) {
|
||||
put(new StorageKey(key), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void put(final byte[] key, final Object data) {
|
||||
put(new StorageKey(key), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
@ -149,17 +83,6 @@ class MemoryStorage implements Storage {
|
||||
storage.put(key, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an object from storage.
|
||||
*
|
||||
* @return true if the delete was successful. False if there were problems deleting the data.
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
boolean delete(final String key) {
|
||||
return delete(new StorageKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an object from storage.
|
||||
*
|
||||
@ -247,43 +170,6 @@ class MemoryStorage implements Storage {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage.
|
||||
* <p/>
|
||||
* There is no file that backs this storage, so writes are immediate and saves do nothing
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void putAndSave(final String key, final Object object) {
|
||||
put(key, object);
|
||||
// no-save!
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Adds a key/value pair to the storage.
|
||||
* <p/>
|
||||
* There is no file that backs this storage, so writes are immediate and saves do nothing
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void putAndSave(final byte[] key, final Object object) {
|
||||
put(key, object);
|
||||
// no save because we are in memory!
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage.
|
||||
* <p/>
|
||||
* There is no file that backs this storage, so writes are immediate and saves do nothing
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
void putAndSave(final StorageKey key, final Object object) {
|
||||
put(key, object);
|
||||
// no save because we are in memory!
|
||||
}
|
||||
|
||||
/**
|
||||
* In-memory storage systems do not have a backing file, so there is nothing to close
|
||||
*/
|
||||
|
@ -31,39 +31,13 @@ interface Storage {
|
||||
/**
|
||||
* Checks if there is a object corresponding to the given key.
|
||||
*/
|
||||
boolean contains(String key);
|
||||
|
||||
/**
|
||||
* Reads a object using the specific key, and casts it to the expected class.
|
||||
*/
|
||||
<T> T get(String key);
|
||||
|
||||
/**
|
||||
* Reads a object using the specific key, and casts it to the expected class
|
||||
*/
|
||||
<T> T get(byte[] key);
|
||||
boolean contains(StorageKey key);
|
||||
|
||||
/**
|
||||
* Reads a object using the specific key, and casts it to the expected class
|
||||
*/
|
||||
<T> T get(StorageKey key);
|
||||
|
||||
/**
|
||||
* Returns the saved data for the specified key.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
<T> T get(String key, T data);
|
||||
|
||||
/**
|
||||
* Returns the saved data for the specified key.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
<T> T get(byte[] key, T data);
|
||||
|
||||
/**
|
||||
* Returns the saved data for the specified key.
|
||||
*
|
||||
@ -72,22 +46,6 @@ interface Storage {
|
||||
*/
|
||||
<T> T get(StorageKey key, T data);
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
void put(String key, Object data);
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
* 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.
|
||||
*/
|
||||
void put(byte[] key, Object data);
|
||||
|
||||
/**
|
||||
* Saves the given data to storage with the associated key.
|
||||
* <p/>
|
||||
@ -96,13 +54,6 @@ interface Storage {
|
||||
*/
|
||||
void put(StorageKey key, Object data);
|
||||
|
||||
/**
|
||||
* Deletes an object from storage.
|
||||
*
|
||||
* @return true if the delete was successful. False if there were problems deleting the data.
|
||||
*/
|
||||
boolean delete(String key);
|
||||
|
||||
/**
|
||||
* Deletes an object from storage.
|
||||
*
|
||||
@ -154,27 +105,6 @@ interface Storage {
|
||||
*/
|
||||
void save();
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage, then saves the storage immediately.
|
||||
* <p/>
|
||||
* This will save ALL of the pending save actions to the file
|
||||
*/
|
||||
void putAndSave(String key, Object object);
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage, then saves the storage immediately.
|
||||
* <p/>
|
||||
* This will save ALL of the pending save actions to the file
|
||||
*/
|
||||
void putAndSave(byte[] key, Object object);
|
||||
|
||||
/**
|
||||
* Adds a key/value pair to the storage, then saves the storage immediately.
|
||||
* <p/>
|
||||
* This will save ALL of the pending save actions to the file
|
||||
*/
|
||||
void putAndSave(StorageKey key, Object object);
|
||||
|
||||
/**
|
||||
* Closes this storage system
|
||||
*/
|
||||
|
@ -286,7 +286,7 @@ class StorageTest {
|
||||
|
||||
// now test loading data
|
||||
Data data = new Data();
|
||||
String createKey = createKey(63);
|
||||
StorageKey createKey = createKey(63);
|
||||
makeData(data);
|
||||
|
||||
storage.put(createKey, data);
|
||||
@ -453,7 +453,7 @@ class StorageTest {
|
||||
for (int i = 0; i < total; i++) {
|
||||
Data data = new Data();
|
||||
makeData(data);
|
||||
String createKey = createKey(i);
|
||||
StorageKey createKey = createKey(i);
|
||||
|
||||
storage.put(createKey, data);
|
||||
}
|
||||
@ -466,7 +466,7 @@ class StorageTest {
|
||||
.file(TEST_DB)
|
||||
.build();
|
||||
for (int i = 0; i < total; i++) {
|
||||
String createKey = createKey(i);
|
||||
StorageKey createKey = createKey(i);
|
||||
|
||||
Data data2;
|
||||
data2 = storage.get(createKey, new Data());
|
||||
@ -489,7 +489,7 @@ class StorageTest {
|
||||
public static
|
||||
String add(Storage storage, int number) throws IOException {
|
||||
String record1Data = createData(number);
|
||||
String record1Key = createKey(number);
|
||||
StorageKey record1Key = createKey(number);
|
||||
|
||||
log("adding record " + number + "...");
|
||||
storage.put(record1Key, record1Data);
|
||||
@ -498,7 +498,7 @@ class StorageTest {
|
||||
|
||||
public static
|
||||
String readRecord(Storage storage, int number) throws ClassNotFoundException, IOException {
|
||||
String record1Key = createKey(number);
|
||||
StorageKey record1Key = createKey(number);
|
||||
|
||||
log("reading record " + number + "...");
|
||||
|
||||
@ -509,7 +509,7 @@ class StorageTest {
|
||||
|
||||
public static
|
||||
void deleteRecord(Storage storage, int nNumber) throws ClassNotFoundException, IOException {
|
||||
String record1Key = createKey(nNumber);
|
||||
StorageKey record1Key = createKey(nNumber);
|
||||
|
||||
log("deleting record " + nNumber + "...");
|
||||
storage.delete(record1Key);
|
||||
@ -517,7 +517,7 @@ class StorageTest {
|
||||
|
||||
private static
|
||||
String updateRecord(Storage storage, int number, String newData) throws IOException {
|
||||
String record1Key = createKey(number);
|
||||
StorageKey record1Key = createKey(number);
|
||||
|
||||
log("updating record " + number + "...");
|
||||
storage.put(record1Key, newData);
|
||||
@ -526,8 +526,8 @@ class StorageTest {
|
||||
}
|
||||
|
||||
private static
|
||||
String createKey(int number) {
|
||||
return "foo" + number;
|
||||
StorageKey createKey(int number) {
|
||||
return new StorageKey("foo" + number);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user