Remove non-transactional mutation from KeyValueStore (#500)

Put and remove are currently available on the KeyValueStorage interface
as non-transactional calls.  These are used nowhere other than test
code, all our production write calls are to the transactional interface.

* Remove the non-transactional mutation APIs from the interface
* Update the tests to use transactional writes
* Update getStartTransaction to just be startTransaction since it is
  not a property but a method.
Danno Ferrin 6 years ago committed by GitHub
parent 4ef2082408
commit d6f85abc11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/storage/keyvalue/KeyValueStoragePrefixedKeyBlockchainStorage.java
  2. 2
      ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorage.java
  3. 2
      ethereum/trie/src/main/java/tech/pegasys/pantheon/ethereum/trie/KeyValueMerkleStorage.java
  4. 24
      services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/InMemoryKeyValueStorage.java
  5. 15
      services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/KeyValueStorage.java
  6. 22
      services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java
  7. 88
      services/kvstore/src/test/java/tech/pegasys/pantheon/services/kvstore/AbstractKeyValueStorageTest.java

@ -105,7 +105,7 @@ public class KeyValueStoragePrefixedKeyBlockchainStorage implements BlockchainSt
@Override @Override
public Updater updater() { public Updater updater() {
return new Updater(storage.getStartTransaction()); return new Updater(storage.startTransaction());
} }
private List<TransactionReceipt> rlpDecodeTransactionReceipts(final BytesValue bytes) { private List<TransactionReceipt> rlpDecodeTransactionReceipts(final BytesValue bytes) {

@ -45,7 +45,7 @@ public class KeyValueStorageWorldStateStorage implements WorldStateStorage {
@Override @Override
public Updater updater() { public Updater updater() {
return new Updater(keyValueStorage.getStartTransaction()); return new Updater(keyValueStorage.startTransaction());
} }
public static class Updater implements WorldStateStorage.Updater { public static class Updater implements WorldStateStorage.Updater {

@ -49,7 +49,7 @@ public class KeyValueMerkleStorage implements MerkleStorage {
// Nothing to do // Nothing to do
return; return;
} }
final KeyValueStorage.Transaction kvTx = keyValueStorage.getStartTransaction(); final KeyValueStorage.Transaction kvTx = keyValueStorage.startTransaction();
for (final Map.Entry<Bytes32, BytesValue> entry : pendingUpdates.entrySet()) { for (final Map.Entry<Bytes32, BytesValue> entry : pendingUpdates.entrySet()) {
kvTx.put(entry.getKey(), entry.getValue()); kvTx.put(entry.getKey(), entry.getValue());
} }

@ -42,29 +42,7 @@ public class InMemoryKeyValueStorage implements KeyValueStorage {
} }
@Override @Override
public void put(final BytesValue key, final BytesValue value) { public Transaction startTransaction() {
final Lock lock = rwLock.writeLock();
lock.lock();
try {
hashValueStore.put(key, value);
} finally {
lock.unlock();
}
}
@Override
public void remove(final BytesValue key) throws StorageException {
final Lock lock = rwLock.writeLock();
lock.lock();
try {
hashValueStore.remove(key);
} finally {
lock.unlock();
}
}
@Override
public Transaction getStartTransaction() {
return new InMemoryTransaction(); return new InMemoryTransaction();
} }

@ -30,25 +30,12 @@ public interface KeyValueStorage extends Closeable {
*/ */
Optional<BytesValue> get(BytesValue key) throws StorageException; Optional<BytesValue> get(BytesValue key) throws StorageException;
/**
* @param key Index into persistent data repository.
* @param value The value persisted at the key index.
*/
void put(BytesValue key, BytesValue value) throws StorageException;
/**
* Remove the data corresponding to the given key.
*
* @param key Index into persistent data repository.
*/
void remove(BytesValue key) throws StorageException;
/** /**
* Begins a transaction. Returns a transaction object that can be updated and committed. * Begins a transaction. Returns a transaction object that can be updated and committed.
* *
* @return An object representing the transaction. * @return An object representing the transaction.
*/ */
Transaction getStartTransaction() throws StorageException; Transaction startTransaction() throws StorageException;
/** /**
* Stream all stored key-value pairs. * Stream all stored key-value pairs.

@ -73,27 +73,7 @@ public class RocksDbKeyValueStorage implements KeyValueStorage, Closeable {
} }
@Override @Override
public void put(final BytesValue key, final BytesValue value) throws StorageException { public Transaction startTransaction() throws StorageException {
throwIfClosed();
try {
db.put(key.extractArray(), value.extractArray());
} catch (final RocksDBException e) {
throw new StorageException(e);
}
}
@Override
public void remove(final BytesValue key) throws StorageException {
throwIfClosed();
try {
db.delete(key.extractArray());
} catch (final RocksDBException e) {
throw new StorageException(e);
}
}
@Override
public Transaction getStartTransaction() throws StorageException {
throwIfClosed(); throwIfClosed();
final WriteOptions options = new WriteOptions(); final WriteOptions options = new WriteOptions();
return new RocksDbTransaction(db.beginTransaction(options), options); return new RocksDbTransaction(db.beginTransaction(options), options);

@ -42,7 +42,9 @@ public abstract class AbstractKeyValueStorageTest {
final KeyValueStorage store1 = createStore(); final KeyValueStorage store1 = createStore();
final KeyValueStorage store2 = createStore(); final KeyValueStorage store2 = createStore();
store1.put(BytesValue.fromHexString("0001"), BytesValue.fromHexString("0FFF")); Transaction tx = store1.startTransaction();
tx.put(BytesValue.fromHexString("0001"), BytesValue.fromHexString("0FFF"));
tx.commit();
final Optional<BytesValue> result = store2.get(BytesValue.fromHexString("0001")); final Optional<BytesValue> result = store2.get(BytesValue.fromHexString("0001"));
assertEquals(Optional.empty(), result); assertEquals(Optional.empty(), result);
} }
@ -51,11 +53,15 @@ public abstract class AbstractKeyValueStorageTest {
public void put() throws Exception { public void put() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
store.put(BytesValue.fromHexString("0F"), BytesValue.fromHexString("0ABC")); Transaction tx = store.startTransaction();
tx.put(BytesValue.fromHexString("0F"), BytesValue.fromHexString("0ABC"));
tx.commit();
assertEquals( assertEquals(
Optional.of(BytesValue.fromHexString("0ABC")), store.get(BytesValue.fromHexString("0F"))); Optional.of(BytesValue.fromHexString("0ABC")), store.get(BytesValue.fromHexString("0F")));
store.put(BytesValue.fromHexString("0F"), BytesValue.fromHexString("0DEF")); tx = store.startTransaction();
tx.put(BytesValue.fromHexString("0F"), BytesValue.fromHexString("0DEF"));
tx.commit();
assertEquals( assertEquals(
Optional.of(BytesValue.fromHexString("0DEF")), store.get(BytesValue.fromHexString("0F"))); Optional.of(BytesValue.fromHexString("0DEF")), store.get(BytesValue.fromHexString("0F")));
} }
@ -63,15 +69,31 @@ public abstract class AbstractKeyValueStorageTest {
@Test @Test
public void removeExisting() throws Exception { public void removeExisting() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
store.put(BytesValue.fromHexString("0F"), BytesValue.fromHexString("0ABC")); Transaction tx = store.startTransaction();
store.remove(BytesValue.fromHexString("0F")); tx.put(BytesValue.fromHexString("0F"), BytesValue.fromHexString("0ABC"));
tx.commit();
tx = store.startTransaction();
tx.remove(BytesValue.fromHexString("0F"));
tx.commit();
assertEquals(Optional.empty(), store.get(BytesValue.fromHexString("0F")));
}
@Test
public void removeExistingSameTransaction() throws Exception {
final KeyValueStorage store = createStore();
Transaction tx = store.startTransaction();
tx.put(BytesValue.fromHexString("0F"), BytesValue.fromHexString("0ABC"));
tx.remove(BytesValue.fromHexString("0F"));
tx.commit();
assertEquals(Optional.empty(), store.get(BytesValue.fromHexString("0F"))); assertEquals(Optional.empty(), store.get(BytesValue.fromHexString("0F")));
} }
@Test @Test
public void removeNonExistent() throws Exception { public void removeNonExistent() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
store.remove(BytesValue.fromHexString("0F")); Transaction tx = store.startTransaction();
tx.remove(BytesValue.fromHexString("0F"));
tx.commit();
assertEquals(Optional.empty(), store.get(BytesValue.fromHexString("0F"))); assertEquals(Optional.empty(), store.get(BytesValue.fromHexString("0F")));
} }
@ -83,9 +105,11 @@ public abstract class AbstractKeyValueStorageTest {
Arrays.asList( Arrays.asList(
Entry.create(BytesValue.fromHexString("01"), BytesValue.fromHexString("0ABC")), Entry.create(BytesValue.fromHexString("01"), BytesValue.fromHexString("0ABC")),
Entry.create(BytesValue.fromHexString("02"), BytesValue.fromHexString("0DEF"))); Entry.create(BytesValue.fromHexString("02"), BytesValue.fromHexString("0DEF")));
Transaction tx = store.startTransaction();
for (final Entry testEntry : testEntries) { for (final Entry testEntry : testEntries) {
store.put(testEntry.getKey(), testEntry.getValue()); tx.put(testEntry.getKey(), testEntry.getValue());
} }
tx.commit();
final List<Entry> actualEntries = store.entries().collect(Collectors.toList()); final List<Entry> actualEntries = store.entries().collect(Collectors.toList());
testEntries.sort(Comparator.comparing(Entry::getKey)); testEntries.sort(Comparator.comparing(Entry::getKey));
@ -106,7 +130,9 @@ public abstract class AbstractKeyValueStorageTest {
() -> { () -> {
try { try {
for (int i = 0; i < keyCount; i++) { for (int i = 0; i < keyCount; i++) {
store.put(BytesValues.toMinimalBytes(i), value); Transaction tx = store.startTransaction();
tx.put(BytesValues.toMinimalBytes(i), value);
tx.commit();
} }
} finally { } finally {
finishedLatch.countDown(); finishedLatch.countDown();
@ -134,12 +160,14 @@ public abstract class AbstractKeyValueStorageTest {
public void transactionCommit() throws Exception { public void transactionCommit() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
// Add some values // Add some values
store.put(BytesValue.of(1), BytesValue.of(1)); Transaction tx = store.startTransaction();
store.put(BytesValue.of(2), BytesValue.of(2)); tx.put(BytesValue.of(1), BytesValue.of(1));
store.put(BytesValue.of(3), BytesValue.of(3)); tx.put(BytesValue.of(2), BytesValue.of(2));
tx.put(BytesValue.of(3), BytesValue.of(3));
tx.commit();
// Start transaction that adds, modifies, and removes some values // Start transaction that adds, modifies, and removes some values
final Transaction tx = store.getStartTransaction(); tx = store.startTransaction();
tx.put(BytesValue.of(2), BytesValue.of(3)); tx.put(BytesValue.of(2), BytesValue.of(3));
tx.put(BytesValue.of(2), BytesValue.of(4)); tx.put(BytesValue.of(2), BytesValue.of(4));
tx.remove(BytesValue.of(3)); tx.remove(BytesValue.of(3));
@ -164,12 +192,14 @@ public abstract class AbstractKeyValueStorageTest {
public void transactionRollback() throws Exception { public void transactionRollback() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
// Add some values // Add some values
store.put(BytesValue.of(1), BytesValue.of(1)); Transaction tx = store.startTransaction();
store.put(BytesValue.of(2), BytesValue.of(2)); tx.put(BytesValue.of(1), BytesValue.of(1));
store.put(BytesValue.of(3), BytesValue.of(3)); tx.put(BytesValue.of(2), BytesValue.of(2));
tx.put(BytesValue.of(3), BytesValue.of(3));
tx.commit();
// Start transaction that adds, modifies, and removes some values // Start transaction that adds, modifies, and removes some values
final Transaction tx = store.getStartTransaction(); tx = store.startTransaction();
tx.put(BytesValue.of(2), BytesValue.of(3)); tx.put(BytesValue.of(2), BytesValue.of(3));
tx.put(BytesValue.of(2), BytesValue.of(4)); tx.put(BytesValue.of(2), BytesValue.of(4));
tx.remove(BytesValue.of(3)); tx.remove(BytesValue.of(3));
@ -193,21 +223,21 @@ public abstract class AbstractKeyValueStorageTest {
@Test @Test
public void transactionCommitEmpty() throws Exception { public void transactionCommitEmpty() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.commit(); tx.commit();
} }
@Test @Test
public void transactionRollbackEmpty() throws Exception { public void transactionRollbackEmpty() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.rollback(); tx.rollback();
} }
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionPutAfterCommit() throws Exception { public void transactionPutAfterCommit() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.commit(); tx.commit();
tx.put(BytesValue.of(1), BytesValue.of(1)); tx.put(BytesValue.of(1), BytesValue.of(1));
} }
@ -215,7 +245,7 @@ public abstract class AbstractKeyValueStorageTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionRemoveAfterCommit() throws Exception { public void transactionRemoveAfterCommit() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.commit(); tx.commit();
tx.remove(BytesValue.of(1)); tx.remove(BytesValue.of(1));
} }
@ -223,7 +253,7 @@ public abstract class AbstractKeyValueStorageTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionPutAfterRollback() throws Exception { public void transactionPutAfterRollback() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.rollback(); tx.rollback();
tx.put(BytesValue.of(1), BytesValue.of(1)); tx.put(BytesValue.of(1), BytesValue.of(1));
} }
@ -231,7 +261,7 @@ public abstract class AbstractKeyValueStorageTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionRemoveAfterRollback() throws Exception { public void transactionRemoveAfterRollback() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.rollback(); tx.rollback();
tx.remove(BytesValue.of(1)); tx.remove(BytesValue.of(1));
} }
@ -239,7 +269,7 @@ public abstract class AbstractKeyValueStorageTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionCommitAfterRollback() throws Exception { public void transactionCommitAfterRollback() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.rollback(); tx.rollback();
tx.commit(); tx.commit();
} }
@ -247,7 +277,7 @@ public abstract class AbstractKeyValueStorageTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionCommitTwice() throws Exception { public void transactionCommitTwice() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.commit(); tx.commit();
tx.commit(); tx.commit();
} }
@ -255,7 +285,7 @@ public abstract class AbstractKeyValueStorageTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionRollbackAfterCommit() throws Exception { public void transactionRollbackAfterCommit() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.commit(); tx.commit();
tx.rollback(); tx.rollback();
} }
@ -263,7 +293,7 @@ public abstract class AbstractKeyValueStorageTest {
@Test(expected = IllegalStateException.class) @Test(expected = IllegalStateException.class)
public void transactionRollbackTwice() throws Exception { public void transactionRollbackTwice() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
tx.rollback(); tx.rollback();
tx.rollback(); tx.rollback();
} }
@ -272,8 +302,8 @@ public abstract class AbstractKeyValueStorageTest {
public void twoTransactions() throws Exception { public void twoTransactions() throws Exception {
final KeyValueStorage store = createStore(); final KeyValueStorage store = createStore();
final Transaction tx1 = store.getStartTransaction(); final Transaction tx1 = store.startTransaction();
final Transaction tx2 = store.getStartTransaction(); final Transaction tx2 = store.startTransaction();
tx1.put(BytesValue.of(1), BytesValue.of(1)); tx1.put(BytesValue.of(1), BytesValue.of(1));
tx2.put(BytesValue.of(2), BytesValue.of(2)); tx2.put(BytesValue.of(2), BytesValue.of(2));
@ -295,7 +325,7 @@ public abstract class AbstractKeyValueStorageTest {
(value) -> (value) ->
new Thread( new Thread(
() -> { () -> {
final Transaction tx = store.getStartTransaction(); final Transaction tx = store.startTransaction();
for (int i = 0; i < keyCount; i++) { for (int i = 0; i < keyCount; i++) {
tx.put(BytesValues.toMinimalBytes(i), value); tx.put(BytesValues.toMinimalBytes(i), value);
} }

Loading…
Cancel
Save