Reworked DatabaseService API.
Initial implementation of LockManager.
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/BatchReadRequest.java b/core/api/src/main/java/org/onlab/onos/store/service/BatchReadRequest.java
new file mode 100644
index 0000000..1cf422c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/service/BatchReadRequest.java
@@ -0,0 +1,70 @@
+package org.onlab.onos.store.service;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Collection of read requests to be submitted as one batch.
+ */
+public class BatchReadRequest {
+
+ private final List<ReadRequest> readRequests;
+
+ /**
+ * Creates a new BatchReadRequest object from the specified list of read requests.
+ * @param readRequests read requests.
+ * @return BatchReadRequest object.
+ */
+ public static BatchReadRequest create(List<ReadRequest> readRequests) {
+ return new BatchReadRequest(readRequests);
+ }
+
+ private BatchReadRequest(List<ReadRequest> readRequests) {
+ this.readRequests = Collections.unmodifiableList(readRequests);
+ }
+
+ /**
+ * Returns the number of requests in this batch.
+ * @return size of request batch.
+ */
+ public int batchSize() {
+ return readRequests.size();
+ }
+
+ /**
+ * Returns the requests in this batch as a list.
+ * @return list of read requests
+ */
+ public List<ReadRequest> getAsList() {
+ return readRequests;
+ }
+
+ /**
+ * Builder for BatchReadRequest.
+ */
+ public static class Builder {
+
+ private final List<ReadRequest> readRequests = Lists.newLinkedList();
+
+ /**
+ * Append a get request.
+ * @param tableName table name
+ * @param key key to fetch.
+ * @return this Builder
+ */
+ public Builder get(String tableName, String key) {
+ readRequests.add(new ReadRequest(tableName, key));
+ return this;
+ }
+
+ /**
+ * Builds a BatchReadRequest
+ * @return BatchReadRequest
+ */
+ public BatchReadRequest build() {
+ return new BatchReadRequest(readRequests);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/BatchReadResult.java b/core/api/src/main/java/org/onlab/onos/store/service/BatchReadResult.java
new file mode 100644
index 0000000..7281eff
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/service/BatchReadResult.java
@@ -0,0 +1,21 @@
+package org.onlab.onos.store.service;
+
+import java.util.Collections;
+import java.util.List;
+
+public class BatchReadResult {
+
+ private final List<ReadResult> readResults;
+
+ public BatchReadResult(List<ReadResult> readResults) {
+ this.readResults = Collections.unmodifiableList(readResults);
+ }
+
+ public List<ReadResult> getAsList() {
+ return readResults;
+ }
+
+ public int batchSize() {
+ return readResults.size();
+ }
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/BatchWriteRequest.java b/core/api/src/main/java/org/onlab/onos/store/service/BatchWriteRequest.java
new file mode 100644
index 0000000..9ce14a1
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/service/BatchWriteRequest.java
@@ -0,0 +1,90 @@
+package org.onlab.onos.store.service;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+/**
+ * Collection of write requests to be submitted as one batch.
+ */
+public class BatchWriteRequest {
+
+ private final List<WriteRequest> writeRequests;
+
+ /**
+ * Creates a new BatchWriteRequest object from the specified list of write requests.
+ * @param writeRequests write requests.
+ * @return BatchWriteRequest object.
+ */
+ public static BatchWriteRequest create(List<WriteRequest> writeRequests) {
+ return new BatchWriteRequest(writeRequests);
+ }
+
+ private BatchWriteRequest(List<WriteRequest> writeRequests) {
+ this.writeRequests = Collections.unmodifiableList(writeRequests);
+ }
+
+ /**
+ * Returns the requests in this batch as a list.
+ * @return list of write requests
+ */
+ public List<WriteRequest> getAsList() {
+ return writeRequests;
+ }
+
+ /**
+ * Returns the number of requests in this batch.
+ * @return size of request batch.
+ */
+ public int batchSize() {
+ return writeRequests.size();
+ }
+
+ /**
+ * Builder for BatchWriteRequest.
+ */
+ public static class Builder {
+
+ private final List<WriteRequest> writeRequests = Lists.newLinkedList();
+
+ public Builder put(String tableName, String key, byte[] value) {
+ writeRequests.add(WriteRequest.put(tableName, key, value));
+ return this;
+ }
+
+ public Builder putIfAbsent(String tableName, String key, byte[] value) {
+ writeRequests.add(WriteRequest.putIfAbsent(tableName, key, value));
+ return this;
+ }
+
+ public Builder putIfValueMatches(String tableName, String key, byte[] oldValue, byte[] newValue) {
+ writeRequests.add(WriteRequest.putIfValueMatches(tableName, key, oldValue, newValue));
+ return this;
+ }
+
+ public Builder putIfVersionMatches(String tableName, String key, byte[] value, long version) {
+ writeRequests.add(WriteRequest.putIfVersionMatches(tableName, key, value, version));
+ return this;
+ }
+
+ public Builder remove(String tableName, String key) {
+ writeRequests.add(WriteRequest.remove(tableName, key));
+ return this;
+ }
+
+ public Builder removeIfVersionMatches(String tableName, String key, long version) {
+ writeRequests.add(WriteRequest.removeIfVersionMatches(tableName, key, version));
+ return this;
+ }
+
+ public Builder removeIfValueMatches(String tableName, String key, byte[] value) {
+ writeRequests.add(WriteRequest.removeIfValueMatches(tableName, key, value));
+ return this;
+ }
+
+ public BatchWriteRequest build() {
+ return new BatchWriteRequest(writeRequests);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/BatchWriteResult.java b/core/api/src/main/java/org/onlab/onos/store/service/BatchWriteResult.java
new file mode 100644
index 0000000..22c653c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/service/BatchWriteResult.java
@@ -0,0 +1,30 @@
+package org.onlab.onos.store.service;
+
+import java.util.Collections;
+import java.util.List;
+
+public class BatchWriteResult {
+
+ private final List<WriteResult> writeResults;
+
+ public BatchWriteResult(List<WriteResult> writeResults) {
+ this.writeResults = Collections.unmodifiableList(writeResults);
+ }
+
+ public boolean isSuccessful() {
+ for (WriteResult result : writeResults) {
+ if (result.status() != WriteStatus.OK) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public List<WriteResult> getAsList() {
+ return this.writeResults;
+ }
+
+ public int batchSize() {
+ return writeResults.size();
+ }
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/DatabaseService.java b/core/api/src/main/java/org/onlab/onos/store/service/DatabaseService.java
index cf0ef0a..57d81f2 100644
--- a/core/api/src/main/java/org/onlab/onos/store/service/DatabaseService.java
+++ b/core/api/src/main/java/org/onlab/onos/store/service/DatabaseService.java
@@ -1,7 +1,5 @@
package org.onlab.onos.store.service;
-import java.util.List;
-
/**
* Service interface for a strongly consistent and durable
* key value data store.
@@ -9,46 +7,93 @@
public interface DatabaseService {
/**
- * Performs a read on the database.
- * @param request read request.
- * @return ReadResult
- * @throws DatabaseException if there is a failure in executing read.
+ * Reads the specified key.
+ * @param tableName name of the table associated with this operation.
+ * @return key key to read.
+ * @returns value (and version) associated with this key. This calls returns null if the key does not exist.
*/
- ReadResult read(ReadRequest request);
-
+ VersionedValue get(String tableName, String key);
+
/**
- * Performs a batch read operation on the database.
- * The main advantage of batch read operation is parallelization.
- * @param batch batch of read requests to execute.
- * @return batch read result.
+ * Associate the key with a value.
+ * @param tableName table name in which this key/value resides.
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ * @return the previous value associated with the specified key, or null if there was no mapping for the key.
*/
- List<OptionalResult<ReadResult, DatabaseException>> batchRead(List<ReadRequest> batch);
-
- // FIXME Give me a better name
+ VersionedValue put(String tableName, String key, byte[] value);
+
/**
- * Performs a write operation on the database.
- * @param request write request
- * @return write result.
- * @throws DatabaseException if there is failure in execution write.
+ * If the specified key is not already associated with a value, associate it with the given value.
+ * @param tableName table name in which this key/value resides.
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ * @return true if put was successful, false if there is already a value associated with this key
*/
- OptionalResult<WriteResult, DatabaseException> writeNothrow(WriteRequest request);
-
+ boolean putIfAbsent(String tableName, String key, byte[] value);
+
/**
- * Performs a write operation on the database.
- * @param request write request
- * @return write result.
- * @throws OptimisticLockException FIXME define conditional failure
- * @throws PreconditionFailedException FIXME define conditional failure
- * @throws DatabaseException if there is failure in execution write.
+ * Sets the key to the specified value if the version in the database (for that key)
+ * matches the specified version.
+ * @param tableName name of table associated with this operation.
+ * @param key key
+ * @param value value
+ * @param version version that should present in the database for the put to be successful.
+ * @return true if put was successful, false if there version in database is different from what is specified.
*/
- WriteResult write(WriteRequest request)/* throws OptimisticLockException, PreconditionFailedException*/;
-
+ boolean putIfVersionMatches(String tableName, String key, byte[] value, long version);
+
/**
- * Performs a batch write operation on the database.
- * Batch write provides transactional semantics. Either all operations
- * succeed or none of them do.
- * @param batch batch of write requests to execute as a transaction.
- * @return result of executing the batch write operation.
+ * Replaces the entry for a key only if currently mapped to a given value.
+ * @param tableName name of table associated with this operation.
+ * @param key with which the specified value is associated
+ * @param oldValue value expected to be associated with the specified key
+ * @param newValue value to be associated with the specified key
+ * @return true if put was successful, false if there version in database is different from what is specified.
*/
- List<OptionalResult<WriteResult, DatabaseException>> batchWrite(List<WriteRequest> batch);
-}
+ boolean putIfValueMatches(String tableName, String key, byte[] oldValue, byte[] newValue);
+
+ /**
+ * Removes the key (and associated value).
+ * @param tableName name of table associated with this operation.
+ * @param key key to remove
+ * @return value previously associated with the key. This call returns null if the key does not exist.
+ */
+ VersionedValue remove(String tableName, String key);
+
+ /**
+ * Removes the key (and associated value) if the version in the database matches specified version.
+ * @param tableName name of table associated with this operation.
+ * @param key key to remove
+ * @param version version that should present in the database for the remove to be successful.
+ * @return true if remove was successful, false if there version in database is different from what is specified.
+ */
+ boolean removeIfVersionMatches(String tableName, String key, long version);
+
+ /**
+ * Removes the key (and associated value) if the value in the database matches specified value.
+ * @param tableName name of table associated with this operation.
+ * @param key key to remove
+ * @param value value that should present in the database for the remove to be successful.
+ * @return true if remove was successful, false if there value in database is different from what is specified.
+ */
+ boolean removeIfValueMatches(String tableName, String key, byte[] value);
+
+ /**
+ * Performs a batch read operation and returns the results.
+ * @param batchRequest batch request.
+ * @return result of the batch operation.
+ */
+ BatchReadResult batchRead(BatchReadRequest batchRequest);
+
+ /**
+ * Performs a batch write operation and returns the results.
+ * This method provides transactional semantics. Either all writes succeed or none do.
+ * Even a single write failure would cause the entire batch to be aborted.
+ * In the case of unsuccessful operation, the batch result can be inspected to determine
+ * which operation(s) caused the batch to fail.
+ * @param batchRequest batch request.
+ * @return result of the batch operation.
+ */
+ BatchWriteResult batchWrite(BatchWriteRequest batchRequest);
+}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/Lock.java b/core/api/src/main/java/org/onlab/onos/store/service/Lock.java
index 6d68133..510df82 100644
--- a/core/api/src/main/java/org/onlab/onos/store/service/Lock.java
+++ b/core/api/src/main/java/org/onlab/onos/store/service/Lock.java
@@ -9,6 +9,12 @@
*/
public interface Lock {
+ /**
+ * Returns the path this lock will be used to guard from concurrent access.
+ * @return path.
+ */
+ String path();
+
/**
* Acquires the lock.
* If the lock is not available then the caller thread becomes
@@ -26,7 +32,7 @@
* already been released by invoking unlock(). Must be in the range
* (0, LockManager.MAX_LEASE_MILLIS]
*/
- void lock(long leaseDurationMillis);
+ void lock(int leaseDurationMillis);
/**
* Acquires the lock only if it is free at the time of invocation.
@@ -36,7 +42,7 @@
* (0, LockManager.MAX_LEASE_MILLIS]
* @return true if the lock was acquired and false otherwise
*/
- boolean tryLock(long leaseDurationMillis);
+ boolean tryLock(int leaseDurationMillis);
/**
* Acquires the lock if it is free within the given waiting
@@ -49,7 +55,7 @@
* @return true if the lock was acquired and false if the waiting time
* elapsed before the lock was acquired
*/
- boolean tryLock(long waitTimeMillis, long leaseDurationMillis);
+ boolean tryLock(long waitTimeMillis, int leaseDurationMillis);
/**
* Returns true if this Lock instance currently holds the lock.
@@ -72,5 +78,5 @@
* @return true if successfully extended expiration, false if attempt to
* extend expiration fails or if the path is currently not locked by this instance.
*/
- boolean extendExpiration(long leaseDurationMillis);
+ boolean extendExpiration(int leaseDurationMillis);
}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/ReadRequest.java b/core/api/src/main/java/org/onlab/onos/store/service/ReadRequest.java
index 9f7af4a..f30529e 100644
--- a/core/api/src/main/java/org/onlab/onos/store/service/ReadRequest.java
+++ b/core/api/src/main/java/org/onlab/onos/store/service/ReadRequest.java
@@ -75,5 +75,4 @@
return Objects.equals(this.key, other.key) &&
Objects.equals(this.tableName, other.tableName);
}
-
}
\ No newline at end of file
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/ReadResult.java b/core/api/src/main/java/org/onlab/onos/store/service/ReadResult.java
index 49e9665..3f253f2 100644
--- a/core/api/src/main/java/org/onlab/onos/store/service/ReadResult.java
+++ b/core/api/src/main/java/org/onlab/onos/store/service/ReadResult.java
@@ -11,12 +11,21 @@
private final String tableName;
private final String key;
private final VersionedValue value;
+ private final ReadStatus status;
- public ReadResult(String tableName, String key, VersionedValue value) {
+ public ReadResult(ReadStatus status, String tableName, String key, VersionedValue value) {
+ this.status = status;
this.tableName = tableName;
this.key = key;
this.value = value;
}
+
+ /**
+ * Returns the status of the read operation.
+ */
+ public ReadStatus status() {
+ return status;
+ }
/**
* Returns database table name.
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/ReadStatus.java b/core/api/src/main/java/org/onlab/onos/store/service/ReadStatus.java
new file mode 100644
index 0000000..2039a1c
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/service/ReadStatus.java
@@ -0,0 +1,6 @@
+package org.onlab.onos.store.service;
+
+public enum ReadStatus {
+ OK,
+ NO_SUCH_TABLE
+}
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/WriteRequest.java b/core/api/src/main/java/org/onlab/onos/store/service/WriteRequest.java
index fb736e5..6607cfe 100644
--- a/core/api/src/main/java/org/onlab/onos/store/service/WriteRequest.java
+++ b/core/api/src/main/java/org/onlab/onos/store/service/WriteRequest.java
@@ -112,7 +112,7 @@
* @param previousVersion previous version expected
* @return WriteRequest
*/
- public static WriteRequest remove(String tableName, String key,
+ public static WriteRequest removeIfVersionMatches(String tableName, String key,
long previousVersion) {
return new WriteRequest(REMOVE_IF_VALUE, tableName, key,
null, previousVersion, null);
@@ -127,7 +127,7 @@
* @param oldValue previous value expected, must not be null
* @return WriteRequest
*/
- public static WriteRequest remove(String tableName, String key,
+ public static WriteRequest removeIfValueMatches(String tableName, String key,
byte[] oldValue) {
return new WriteRequest(Type.REMOVE_IF_VALUE, tableName, key,
null, ANY_VERSION, checkNotNull(oldValue));
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/WriteResult.java b/core/api/src/main/java/org/onlab/onos/store/service/WriteResult.java
index aec3046..3cc11b0 100644
--- a/core/api/src/main/java/org/onlab/onos/store/service/WriteResult.java
+++ b/core/api/src/main/java/org/onlab/onos/store/service/WriteResult.java
@@ -7,34 +7,27 @@
* Database write result.
*/
public class WriteResult {
-
- private final String tableName;
- private final String key;
+
+ private final WriteStatus status;
private final VersionedValue previousValue;
-
- public WriteResult(String tableName, String key, VersionedValue previousValue) {
- this.tableName = tableName;
- this.key = key;
+
+ public WriteResult(WriteStatus status, VersionedValue previousValue) {
+ this.status = status;
this.previousValue = previousValue;
}
- public String tableName() {
- return tableName;
- }
-
- public String key() {
- return key;
- }
-
public VersionedValue previousValue() {
return previousValue;
}
+
+ public WriteStatus status() {
+ return status;
+ }
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
- .add("tableName", tableName)
- .add("key", key)
+ .add("status", status)
.add("previousValue", previousValue)
.toString();
}
diff --git a/core/api/src/main/java/org/onlab/onos/store/service/WriteStatus.java b/core/api/src/main/java/org/onlab/onos/store/service/WriteStatus.java
new file mode 100644
index 0000000..ebb4f6d
--- /dev/null
+++ b/core/api/src/main/java/org/onlab/onos/store/service/WriteStatus.java
@@ -0,0 +1,8 @@
+package org.onlab.onos.store.service;
+
+public enum WriteStatus {
+ OK,
+ ABORTED,
+ PRECONDITION_VIOLATION,
+ NO_SUCH_TABLE,
+}