Refactored code to consolidate functionality in Database* classes.
Renamed few methods and variables to align with local convention and also to match the description of functionality.

Change-Id: Ib17e73079534c76f76bcb01f14b6496e62275dbd
diff --git a/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java b/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java
index 1779256..fee8cfa 100644
--- a/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java
+++ b/core/api/src/main/java/org/onosproject/store/service/AsyncConsistentMap.java
@@ -18,7 +18,6 @@
 
 import java.util.Collection;
 import java.util.Map.Entry;
-import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.BiFunction;
@@ -166,17 +165,6 @@
     CompletableFuture<Versioned<V>> putAndGet(K key, V value);
 
     /**
-     * Associates the specified value with the specified key in this map (optional operation).
-     * If the map previously contained a mapping for the key, the old value is replaced by the
-     * specified value.
-     *
-     * @param key key with which the specified value is to be associated
-     * @param value value to be associated with the specified key
-     * @return optional updated value. Will be empty if update did not happen
-     */
-    CompletableFuture<Optional<Versioned<V>>> putIfAbsentAndGet(K key, V value);
-
-    /**
      * Removes the mapping for a key from this map if it is present (optional operation).
      *
      * @param key key whose value is to be removed from the map
@@ -279,17 +267,6 @@
     CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue);
 
     /**
-     * Replaces the entry for the specified key only if it is currently mapped to the
-     * specified version.
-     *
-     * @param key key key with which the specified value is associated
-     * @param oldVersion version expected to be associated with the specified key
-     * @param newValue value to be associated with the specified key
-     * @return optional updated value. Will be empty if update did not happen.
-     */
-    CompletableFuture<Optional<Versioned<V>>> replaceAndGet(K key, long oldVersion, V newValue);
-
-    /**
      * Registers the specified listener to be notified whenever the map is updated.
      *
      * @param listener listener to notify about map events
diff --git a/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java b/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java
index 59f72a9..127a567 100644
--- a/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java
+++ b/core/api/src/main/java/org/onosproject/store/service/ConsistentMap.java
@@ -18,7 +18,6 @@
 
 import java.util.Collection;
 import java.util.Map.Entry;
-import java.util.Optional;
 import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.Function;
@@ -168,17 +167,6 @@
     Versioned<V> putAndGet(K key, V value);
 
     /**
-     * Associates the specified value with the specified key in this map (optional operation).
-     * If the map previously contained a mapping for the key, the old value is replaced by the
-     * specified value.
-     *
-     * @param key key with which the specified value is to be associated
-     * @param value value to be associated with the specified key
-     * @return optional updated value. Will be empty if update did not happen
-     */
-    Optional<Versioned<V>> putIfAbsentAndGet(K key, V value);
-
-    /**
      * Removes the mapping for a key from this map if it is present (optional operation).
      *
      * @param key key whose value is to be removed from the map
@@ -280,17 +268,6 @@
     boolean replace(K key, long oldVersion, V newValue);
 
     /**
-     * Replaces the entry for the specified key only if it is currently mapped to the
-     * specified version.
-     *
-     * @param key key key with which the specified value is associated
-     * @param oldVersion version expected to be associated with the specified key
-     * @param newValue value to be associated with the specified key
-     * @return optional new value. Will be empty if replace did not happen
-     */
-    Optional<Versioned<V>> replaceAndGet(K key, long oldVersion, V newValue);
-
-    /**
      * Registers the specified listener to be notified whenever the map is updated.
      *
      * @param listener listener to notify about map events
diff --git a/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java b/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java
index fd4373e..8cac596 100644
--- a/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java
+++ b/core/api/src/main/java/org/onosproject/store/service/DatabaseUpdate.java
@@ -68,7 +68,7 @@
     }
 
     private Type type;
-    private String tableName;
+    private String mapName;
     private String key;
     private byte[] value;
     private byte[] currentValue;
@@ -83,11 +83,11 @@
     }
 
     /**
-     * Returns the tableName being updated.
-     * @return table name.
+     * Returns the name of map being updated.
+     * @return map name.
      */
-    public String tableName() {
-        return tableName;
+    public String mapName() {
+        return mapName;
     }
 
     /**
@@ -126,7 +126,7 @@
     public String toString() {
         return MoreObjects.toStringHelper(this)
             .add("type", type)
-            .add("tableName", tableName)
+            .add("mapName", mapName)
             .add("key", key)
             .add("value", value)
             .add("currentValue", currentValue)
@@ -161,8 +161,8 @@
             return this;
         }
 
-        public Builder withTableName(String tableName) {
-            update.tableName = checkNotNull(tableName, "tableName cannot be null");
+        public Builder withMapName(String mapName) {
+            update.mapName = checkNotNull(mapName, "mapName cannot be null");
             return this;
         }
 
@@ -189,7 +189,7 @@
 
         private void validateInputs() {
             checkNotNull(update.type, "type must be specified");
-            checkNotNull(update.tableName, "table name must be specified");
+            checkNotNull(update.mapName, "map name must be specified");
             checkNotNull(update.key, "key must be specified");
             switch (update.type) {
             case PUT:
diff --git a/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java b/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java
index 4dfb28d..b498c1c 100644
--- a/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java
+++ b/core/api/src/test/java/org/onosproject/store/service/DatabaseUpdateTest.java
@@ -33,7 +33,7 @@
             .withValue("2".getBytes())
             .withCurrentVersion(3)
             .withKey("4")
-            .withTableName("5")
+            .withMapName("5")
             .withType(DatabaseUpdate.Type.PUT)
             .build();
 
@@ -42,7 +42,7 @@
             .withValue("2".getBytes())
             .withCurrentVersion(3)
             .withKey("4")
-            .withTableName("5")
+            .withMapName("5")
             .withType(DatabaseUpdate.Type.REMOVE)
             .build();
 
@@ -51,7 +51,7 @@
             .withValue("2".getBytes())
             .withCurrentVersion(3)
             .withKey("4")
-            .withTableName("5")
+            .withMapName("5")
             .withType(DatabaseUpdate.Type.REMOVE_IF_VALUE_MATCH)
             .build();
 
@@ -60,7 +60,7 @@
             .withValue("2".getBytes())
             .withCurrentVersion(3)
             .withKey("4")
-            .withTableName("5")
+            .withMapName("5")
             .withType(DatabaseUpdate.Type.REMOVE_IF_VERSION_MATCH)
             .build();
 
@@ -69,7 +69,7 @@
             .withValue("2".getBytes())
             .withCurrentVersion(3)
             .withKey("4")
-            .withTableName("5")
+            .withMapName("5")
             .withType(DatabaseUpdate.Type.PUT_IF_VALUE_MATCH)
             .build();
 
@@ -78,7 +78,7 @@
             .withValue("2".getBytes())
             .withCurrentVersion(3)
             .withKey("4")
-            .withTableName("5")
+            .withMapName("5")
             .withType(DatabaseUpdate.Type.PUT_IF_VERSION_MATCH)
             .build();
 
@@ -91,7 +91,7 @@
         assertThat(stats1.value(), is("2".getBytes()));
         assertThat(stats1.currentVersion(), is(3L));
         assertThat(stats1.key(), is("4"));
-        assertThat(stats1.tableName(), is("5"));
+        assertThat(stats1.mapName(), is("5"));
         assertThat(stats1.type(), is(DatabaseUpdate.Type.PUT));
     }
 
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java
index 91cfa4b..a04a592 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Database.java
@@ -81,4 +81,4 @@
       .addStartupTask(() -> coordinator.open().thenApply(v -> null))
       .addShutdownTask(coordinator::close);
   }
-}
+}
\ No newline at end of file
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
index 619bc91..86f7103 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseManager.java
@@ -391,9 +391,9 @@
     }
 
     private List<MapInfo> getMapInfo(Database database) {
-        return complete(database.tableNames())
+        return complete(database.maps())
             .stream()
-            .map(name -> new MapInfo(name, complete(database.size(name))))
+            .map(name -> new MapInfo(name, complete(database.mapSize(name))))
             .filter(info -> info.size() > 0)
             .collect(Collectors.toList());
     }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabasePartitioner.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabasePartitioner.java
index a76a4e3..740f81a 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabasePartitioner.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabasePartitioner.java
@@ -24,9 +24,9 @@
 import com.google.common.hash.Hashing;
 
 /**
- * Partitioner for mapping table entries to individual database partitions.
+ * Partitioner for mapping map entries to individual database partitions.
  * <p>
- * By default a md5 hash of the hash key (key or table name) is used to pick a
+ * By default a md5 hash of the hash key (key or map name) is used to pick a
  * partition.
  */
 public abstract class DatabasePartitioner implements Partitioner<String> {
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java
index 518b526..68cfe9e 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseProxy.java
@@ -31,11 +31,11 @@
 public interface DatabaseProxy<K, V> {
 
     /**
-     * Returns a set of all tables names.
+     * Returns a set of all map names.
      *
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Set<String>> tableNames();
+    CompletableFuture<Set<String>> maps();
 
     /**
      * Returns a mapping from counter name to next value.
@@ -45,185 +45,93 @@
     CompletableFuture<Map<String, Long>> counters();
 
     /**
-     * Gets the table size.
      *
-     * @param tableName table name
+     * @param mapName map name
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Integer> size(String tableName);
+    CompletableFuture<Integer> mapSize(String mapName);
 
     /**
-     * Checks whether the table is empty.
+     * Checks whether the map is empty.
      *
-     * @param tableName table name
+     * @param mapName map name
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Boolean> isEmpty(String tableName);
+    CompletableFuture<Boolean> mapIsEmpty(String mapName);
 
     /**
-     * Checks whether the table contains a key.
+     * Checks whether the map contains a key.
      *
-     * @param tableName table name
-     * @param key       The key to check.
+     * @param mapName map name
+     * @param key key to check.
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Boolean> containsKey(String tableName, K key);
+    CompletableFuture<Boolean> mapContainsKey(String mapName, K key);
 
     /**
-     * Checks whether the table contains a value.
+     * Checks whether the map contains a value.
      *
-     * @param tableName table name
-     * @param value     The value to check.
+     * @param mapName map name
+     * @param value The value to check.
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Boolean> containsValue(String tableName, V value);
+    CompletableFuture<Boolean> mapContainsValue(String mapName, V value);
 
     /**
-     * Gets a value from the table.
+     * Gets a value from the map.
      *
-     * @param tableName table name
-     * @param key       The key to get.
+     * @param mapName map name
+     * @param key The key to get.
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Versioned<V>> get(String tableName, K key);
+    CompletableFuture<Versioned<V>> mapGet(String mapName, K key);
 
     /**
-     * Puts a value in the table.
+     * Updates the map.
      *
-     * @param tableName table name
-     * @param key       The key to set.
-     * @param value     The value to set.
+     * @param mapName map name
+     * @param key           The key to set
+     * @param valueMatch    match for checking existing value
+     * @param versionMatch  match for checking existing version
+     * @param value         new value
+     * @return A completable future to be completed with the result once complete
+     */
+    CompletableFuture<Result<UpdateResult<K, V>>> mapUpdate(
+            String mapName, K key, Match<V> valueMatch, Match<Long> versionMatch, V value);
+
+    /**
+     * Clears the map.
+     *
+     * @param mapName map name
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Result<Versioned<V>>> put(String tableName, K key, V value);
+    CompletableFuture<Result<Void>> mapClear(String mapName);
 
     /**
-     * Puts a value in the table.
+     * Gets a set of keys in the map.
      *
-     * @param tableName table name
-     * @param key       The key to set.
-     * @param value     The value to set.
+     * @param mapName map name
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Result<UpdateResult<Versioned<V>>>> putAndGet(String tableName, K key, V value);
+    CompletableFuture<Set<K>> mapKeySet(String mapName);
 
     /**
-     * Puts a value in the table.
+     * Gets a collection of values in the map.
      *
-     * @param tableName table name
-     * @param key       The key to set.
-     * @param value     The value to set.
+     * @param mapName map name
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Result<UpdateResult<Versioned<V>>>> putIfAbsentAndGet(String tableName, K key, V value);
+    CompletableFuture<Collection<Versioned<V>>> mapValues(String mapName);
 
     /**
-     * Removes a value from the table.
+     * Gets a set of entries in the map.
      *
-     * @param tableName table name
-     * @param key       The key to remove.
+     * @param mapName map name
      * @return A completable future to be completed with the result once complete.
      */
-    CompletableFuture<Result<Versioned<V>>> remove(String tableName, K key);
+    CompletableFuture<Set<Map.Entry<K, Versioned<V>>>> mapEntrySet(String mapName);
 
-    /**
-     * Clears the table.
-     *
-     * @param tableName table name
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Result<Void>> clear(String tableName);
-
-    /**
-     * Gets a set of keys in the table.
-     *
-     * @param tableName table name
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Set<K>> keySet(String tableName);
-
-    /**
-     * Gets a collection of values in the table.
-     *
-     * @param tableName table name
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Collection<Versioned<V>>> values(String tableName);
-
-    /**
-     * Gets a set of entries in the table.
-     *
-     * @param tableName table name
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Set<Map.Entry<K, Versioned<V>>>> entrySet(String tableName);
-
-    /**
-     * Puts a value in the table if the given key does not exist.
-     *
-     * @param tableName table name
-     * @param key       The key to set.
-     * @param value     The value to set if the given key does not exist.
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Result<Versioned<V>>> putIfAbsent(String tableName, K key, V value);
-
-    /**
-     * Removes a key and if the existing value for that key matches the specified value.
-     *
-     * @param tableName table name
-     * @param key       The key to remove.
-     * @param value     The value to remove.
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Result<Boolean>> remove(String tableName, K key, V value);
-
-    /**
-     * Removes a key and if the existing version for that key matches the specified version.
-     *
-     * @param tableName table name
-     * @param key       The key to remove.
-     * @param version   The expected version.
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Result<Boolean>> remove(String tableName, K key, long version);
-
-    /**
-     * Replaces the entry for the specified key only if currently mapped to the specified value.
-     *
-     * @param tableName table name
-     * @param key       The key to replace.
-     * @param oldValue  The value to replace.
-     * @param newValue  The value with which to replace the given key and value.
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Result<Boolean>> replace(String tableName, K key, V oldValue, V newValue);
-
-    /**
-     * Replaces the entry for the specified key only if currently mapped to the specified version.
-     *
-     * @param tableName  table name
-     * @param key        The key to update
-     * @param oldVersion existing version in the map for this replace to succeed.
-     * @param newValue   The value with which to replace the given key and version.
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Result<Boolean>> replace(String tableName, K key, long oldVersion, V newValue);
-
-    /**
-     * Replaces the entry for the specified key only if currently mapped to the specified version.
-     *
-     * @param tableName  table name
-     * @param key        The key to update
-     * @param oldVersion existing version in the map for this replace to succeed.
-     * @param newValue   The value with which to replace the given key and version.
-     * @return A completable future to be completed with the result once complete.
-     */
-    CompletableFuture<Result<UpdateResult<Versioned<V>>>> replaceAndGet(String tableName,
-            K key, long oldVersion,
-            V newValue);
-
-    /**
+     /**
      * Atomically add the given value to current value of the specified counter.
      *
      * @param counterName counter name
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseSerializer.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseSerializer.java
index db28826..2503cfa 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseSerializer.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseSerializer.java
@@ -79,6 +79,7 @@
             .register(Result.Status.class)
             .register(DefaultTransaction.class)
             .register(Transaction.State.class)
+            .register(Match.class)
             .register(NodeId.class)
             .build();
 
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java
index 0af7f42..e0582c9 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DatabaseState.java
@@ -45,67 +45,40 @@
   void init(StateContext<DatabaseState<K, V>> context);
 
   @Query
-  Set<String> tableNames();
+  Set<String> maps();
 
   @Query
   Map<String, Long> counters();
 
   @Query
-  int size(String tableName);
+  int size(String mapName);
 
   @Query
-  boolean isEmpty(String tableName);
+  boolean mapIsEmpty(String mapName);
 
   @Query
-  boolean containsKey(String tableName, K key);
+  boolean mapContainsKey(String mapName, K key);
 
   @Query
-  boolean containsValue(String tableName, V value);
+  boolean mapContainsValue(String mapName, V value);
 
   @Query
-  Versioned<V> get(String tableName, K key);
+  Versioned<V> mapGet(String mapName, K key);
 
   @Command
-  Result<Versioned<V>> put(String tableName, K key, V value);
+  Result<UpdateResult<K, V>> mapUpdate(String mapName, K key, Match<V> valueMatch, Match<Long> versionMatch, V value);
 
   @Command
-  Result<UpdateResult<Versioned<V>>> putAndGet(String tableName, K key, V value);
-
-  @Command
-  Result<UpdateResult<Versioned<V>>> putIfAbsentAndGet(String tableName, K key, V value);
-
-  @Command
-  Result<Versioned<V>> remove(String tableName, K key);
-
-  @Command
-  Result<Void> clear(String tableName);
+  Result<Void> mapClear(String mapName);
 
   @Query
-  Set<K> keySet(String tableName);
+  Set<K> mapKeySet(String mapName);
 
   @Query
-  Collection<Versioned<V>> values(String tableName);
+  Collection<Versioned<V>> mapValues(String mapName);
 
   @Query
-  Set<Entry<K, Versioned<V>>> entrySet(String tableName);
-
-  @Command
-  Result<Versioned<V>> putIfAbsent(String tableName, K key, V value);
-
-  @Command
-  Result<Boolean> remove(String tableName, K key, V value);
-
-  @Command
-  Result<Boolean> remove(String tableName, K key, long version);
-
-  @Command
-  Result<Boolean> replace(String tableName, K key, V oldValue, V newValue);
-
-  @Command
-  Result<Boolean> replace(String tableName, K key, long oldVersion, V newValue);
-
-  @Command
-  Result<UpdateResult<Versioned<V>>> replaceAndGet(String tableName, K key, long oldVersion, V newValue);
+  Set<Entry<K, Versioned<V>>> mapEntrySet(String mapName);
 
   @Command
   Long counterAddAndGet(String counterName, long delta);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java
index 298fe2f..cdd809c 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultAsyncConsistentMap.java
@@ -23,7 +23,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.atomic.AtomicReference;
@@ -34,7 +33,6 @@
 import java.util.stream.Collectors;
 import java.util.Set;
 
-import org.apache.commons.lang3.tuple.Pair;
 import org.onlab.util.HexString;
 import org.onlab.util.Tools;
 import org.onosproject.core.ApplicationId;
@@ -49,6 +47,7 @@
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
+import com.google.common.collect.Maps;
 
 /**
  * AsyncConsistentMap implementation that is backed by a Raft consensus
@@ -139,38 +138,39 @@
 
     @Override
     public CompletableFuture<Integer> size() {
-        return database.size(name);
+        return database.mapSize(name);
     }
 
     @Override
     public CompletableFuture<Boolean> isEmpty() {
-        return database.isEmpty(name);
+        return database.mapIsEmpty(name);
     }
 
     @Override
     public CompletableFuture<Boolean> containsKey(K key) {
         checkNotNull(key, ERROR_NULL_KEY);
-        return database.containsKey(name, keyCache.getUnchecked(key));
+        return database.mapContainsKey(name, keyCache.getUnchecked(key));
     }
 
     @Override
     public CompletableFuture<Boolean> containsValue(V value) {
         checkNotNull(value, ERROR_NULL_VALUE);
-        return database.containsValue(name, serializer.encode(value));
+        return database.mapContainsValue(name, serializer.encode(value));
     }
 
     @Override
     public CompletableFuture<Versioned<V>> get(K key) {
         checkNotNull(key, ERROR_NULL_KEY);
-        return database.get(name, keyCache.getUnchecked(key))
-            .thenApply(v -> v != null
-            ? new Versioned<>(serializer.decode(v.value()), v.version(), v.creationTime()) : null);
+        return database.mapGet(name, keyCache.getUnchecked(key))
+            .thenApply(v -> v != null ? v.map(serializer::decode) : null);
     }
 
     @Override
     public CompletableFuture<Versioned<V>> computeIfAbsent(K key,
             Function<? super K, ? extends V> mappingFunction) {
-        return computeIf(key, Objects::isNull, (k, v) -> mappingFunction.apply(k));
+        checkNotNull(key, ERROR_NULL_KEY);
+        checkNotNull(mappingFunction, "Mapping function cannot be null");
+        return updateAndGet(key, Match.ifNull(), Match.any(), mappingFunction.apply(key)).thenApply(v -> v.newValue());
     }
 
     @Override
@@ -192,7 +192,6 @@
         checkNotNull(key, ERROR_NULL_KEY);
         checkNotNull(condition, "predicate function cannot be null");
         checkNotNull(remappingFunction, "Remapping function cannot be null");
-        AtomicReference<MapEvent<K, V>> mapEvent = new AtomicReference<>();
         return get(key).thenCompose(r1 -> {
             V existingValue = r1 == null ? null : r1.value();
             // if the condition evaluates to false, return existing value.
@@ -207,116 +206,51 @@
             } catch (Exception e) {
                 return Tools.exceptionalFuture(e);
             }
-
-            // if the computed value is null, remove current value if one exists.
-            // throw an exception if concurrent modification is detected.
-            if (computedValue.get() == null) {
-                if (r1 != null) {
-                    return remove(key, r1.version()).thenApply(result -> {
-                        if (result) {
-                            mapEvent.set(new MapEvent<>(name, MapEvent.Type.REMOVE, key, r1));
-                            return null;
-                        } else {
-                            throw new ConsistentMapException.ConcurrentModification();
-                        }
-                    });
-                } else {
-                    return CompletableFuture.completedFuture(null);
-                }
-            } else {
-                // replace current value; throw an exception if concurrent modification is detected
-                if (r1 != null) {
-                    return replaceAndGet(key, r1.version(), computedValue.get())
-                            .thenApply(v -> {
-                                if (v.isPresent()) {
-                                    mapEvent.set(new MapEvent<>(name, MapEvent.Type.UPDATE, key, v.get()));
-                                    return v.get();
-                                } else {
-                                    throw new ConsistentMapException.ConcurrentModification();
-                                }
-                            });
-                } else {
-                    return putIfAbsentAndGet(key, computedValue.get()).thenApply(result -> {
-                        if (!result.isPresent()) {
-                            throw new ConsistentMapException.ConcurrentModification();
-                        } else {
-                            mapEvent.set(new MapEvent<>(name, MapEvent.Type.INSERT, key, result.get()));
-                            return result.get();
-                        }
-                    });
-                }
+            if (computedValue.get() == null && r1 == null) {
+                return CompletableFuture.completedFuture(null);
             }
-        }).whenComplete((result, error) -> notifyListeners(mapEvent.get()));
+            Match<V> valueMatcher = r1 == null ? Match.ifNull() : Match.any();
+            Match<Long> versionMatcher = r1 == null ? Match.any() : Match.ifValue(r1.version());
+            return updateAndGet(key, valueMatcher, versionMatcher, computedValue.get())
+                    .thenApply(v -> {
+                        if (v.updated()) {
+                            return v.newValue();
+                        } else {
+                            throw new ConsistentMapException.ConcurrentModification();
+                        }
+                    });
+        });
     }
 
     @Override
     public CompletableFuture<Versioned<V>> put(K key, V value) {
         checkNotNull(key, ERROR_NULL_KEY);
         checkNotNull(value, ERROR_NULL_VALUE);
-        checkIfUnmodifiable();
-        return database.put(name, keyCache.getUnchecked(key), serializer.encode(value))
-                       .thenApply(this::unwrapResult)
-                       .thenApply(v -> v != null
-                       ? new Versioned<>(serializer.decode(v.value()), v.version(), v.creationTime()) : null);
+        return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.oldValue());
     }
 
     @Override
     public CompletableFuture<Versioned<V>> putAndGet(K key, V value) {
         checkNotNull(key, ERROR_NULL_KEY);
         checkNotNull(value, ERROR_NULL_VALUE);
-        checkIfUnmodifiable();
-        return database.putAndGet(name, keyCache.getUnchecked(key), serializer.encode(value))
-                .thenApply(this::unwrapResult)
-                .thenApply(v -> {
-                    Versioned<byte[]> rawNewValue = v.newValue();
-                    return new Versioned<>(serializer.decode(rawNewValue.value()),
-                            rawNewValue.version(),
-                            rawNewValue.creationTime());
-                });
-    }
-
-    @Override
-    public CompletableFuture<Optional<Versioned<V>>> putIfAbsentAndGet(K key, V value) {
-        checkNotNull(key, ERROR_NULL_KEY);
-        checkNotNull(value, ERROR_NULL_VALUE);
-        checkIfUnmodifiable();
-        return database.putIfAbsentAndGet(name, keyCache.getUnchecked(key), serializer.encode(value))
-                .thenApply(this::unwrapResult)
-                .thenApply(v -> {
-                    if (v.updated()) {
-                        Versioned<byte[]> rawNewValue = v.newValue();
-                        return Optional.of(new Versioned<>(serializer.decode(rawNewValue.value()),
-                                                           rawNewValue.version(),
-                                                           rawNewValue.creationTime()));
-                    } else {
-                        return Optional.empty();
-                    }
-                });
+        return updateAndGet(key, Match.any(), Match.any(), value).thenApply(v -> v.newValue());
     }
 
     @Override
     public CompletableFuture<Versioned<V>> remove(K key) {
         checkNotNull(key, ERROR_NULL_KEY);
-        checkIfUnmodifiable();
-        return database.remove(name, keyCache.getUnchecked(key))
-                .thenApply(this::unwrapResult)
-                .thenApply(v -> v != null ? v.<V>map(serializer::decode) : null)
-                .whenComplete((r, e) -> {
-                    if (r != null) {
-                        notifyListeners(new MapEvent<>(name, MapEvent.Type.REMOVE, key, r));
-                    }
-                });
+        return updateAndGet(key, Match.any(), Match.any(), null).thenApply(v -> v.oldValue());
     }
 
     @Override
     public CompletableFuture<Void> clear() {
         checkIfUnmodifiable();
-        return database.clear(name).thenApply(this::unwrapResult);
+        return database.mapClear(name).thenApply(this::unwrapResult);
     }
 
     @Override
     public CompletableFuture<Set<K>> keySet() {
-        return database.keySet(name)
+        return database.mapKeySet(name)
                 .thenApply(s -> s
                 .stream()
                 .map(this::dK)
@@ -325,17 +259,17 @@
 
     @Override
     public CompletableFuture<Collection<Versioned<V>>> values() {
-        return database.values(name).thenApply(c -> c
+        return database.mapValues(name).thenApply(c -> c
             .stream()
-            .map(v -> new Versioned<V>(serializer.decode(v.value()), v.version(), v.creationTime()))
+            .map(v -> v.<V>map(serializer::decode))
             .collect(Collectors.toList()));
     }
 
     @Override
     public CompletableFuture<Set<Entry<K, Versioned<V>>>> entrySet() {
-        return database.entrySet(name).thenApply(s -> s
+        return database.mapEntrySet(name).thenApply(s -> s
                 .stream()
-                .map(this::fromRawEntry)
+                .map(this::mapRawEntry)
                 .collect(Collectors.toSet()));
     }
 
@@ -343,84 +277,52 @@
     public CompletableFuture<Versioned<V>> putIfAbsent(K key, V value) {
         checkNotNull(key, ERROR_NULL_KEY);
         checkNotNull(value, ERROR_NULL_VALUE);
-        checkIfUnmodifiable();
-        AtomicReference<MapEvent<K, V>> event = new AtomicReference<>();
-        return database.putIfAbsentAndGet(name, keyCache.getUnchecked(key), serializer.encode(value))
-                .thenApply(this::unwrapResult)
-                .whenComplete((r, e) -> {
-                    if (r != null && r.updated()) {
-                        event.set(new MapEvent<K, V>(name,
-                                                 MapEvent.Type.INSERT,
-                                                 key,
-                                                 r.newValue().<V>map(serializer::decode)));
-                    }
-                })
-                .thenApply(v -> v.updated() ? null : v.oldValue().<V>map(serializer::decode))
-                .whenComplete((r, e) -> notifyListeners(event.get()));
+        return computeIfAbsent(key, k -> value);
     }
 
     @Override
     public CompletableFuture<Boolean> remove(K key, V value) {
         checkNotNull(key, ERROR_NULL_KEY);
         checkNotNull(value, ERROR_NULL_VALUE);
-        checkIfUnmodifiable();
-        return database.remove(name, keyCache.getUnchecked(key), serializer.encode(value))
-                       .thenApply(this::unwrapResult);
+        return updateAndGet(key, Match.ifValue(value), Match.any(), null).thenApply(v -> v.updated());
     }
 
     @Override
     public CompletableFuture<Boolean> remove(K key, long version) {
         checkNotNull(key, ERROR_NULL_KEY);
-        checkIfUnmodifiable();
-        return database.remove(name, keyCache.getUnchecked(key), version)
-                       .thenApply(this::unwrapResult);
-
+        return updateAndGet(key, Match.any(), Match.ifValue(version), null).thenApply(v -> v.updated());
     }
 
     @Override
     public CompletableFuture<Boolean> replace(K key, V oldValue, V newValue) {
         checkNotNull(key, ERROR_NULL_KEY);
+        checkNotNull(oldValue, ERROR_NULL_VALUE);
         checkNotNull(newValue, ERROR_NULL_VALUE);
-        checkIfUnmodifiable();
-        byte[] existing = oldValue != null ? serializer.encode(oldValue) : null;
-        return database.replace(name, keyCache.getUnchecked(key), existing, serializer.encode(newValue))
-                       .thenApply(this::unwrapResult);
+        return updateAndGet(key, Match.ifValue(oldValue), Match.any(), newValue).thenApply(v -> v.updated());
     }
 
     @Override
     public CompletableFuture<Boolean> replace(K key, long oldVersion, V newValue) {
-        return replaceAndGet(key, oldVersion, newValue).thenApply(Optional::isPresent);
+        return updateAndGet(key, Match.any(), Match.ifValue(oldVersion), newValue).thenApply(v -> v.updated());
     }
 
-    @Override
-    public CompletableFuture<Optional<Versioned<V>>> replaceAndGet(K key, long oldVersion, V newValue) {
-        checkNotNull(key, ERROR_NULL_KEY);
-        checkNotNull(newValue, ERROR_NULL_VALUE);
+    private Map.Entry<K, Versioned<V>> mapRawEntry(Map.Entry<String, Versioned<byte[]>> e) {
+        return Maps.immutableEntry(dK(e.getKey()), e.getValue().<V>map(serializer::decode));
+    }
+
+    private CompletableFuture<UpdateResult<K, V>> updateAndGet(K key,
+            Match<V> oldValueMatch,
+            Match<Long> oldVersionMatch,
+            V value) {
         checkIfUnmodifiable();
-        return database.replaceAndGet(name,
-                                      keyCache.getUnchecked(key),
-                                      oldVersion,
-                                      serializer.encode(newValue))
-                       .thenApply(this::unwrapResult)
-                       .thenApply(v -> {
-                                   if (v.updated()) {
-                                       Versioned<byte[]> rawNewValue = v.newValue();
-                                       return Optional.of(new Versioned<>(serializer.decode(rawNewValue.value()),
-                                                                            rawNewValue.version(),
-                                                                            rawNewValue.creationTime()));
-                                   } else {
-                                       return Optional.empty();
-                                   }
-                       });
-    }
-
-    private Map.Entry<K, Versioned<V>> fromRawEntry(Map.Entry<String, Versioned<byte[]>> e) {
-        return Pair.of(
-                dK(e.getKey()),
-                new Versioned<>(
-                        serializer.decode(e.getValue().value()),
-                        e.getValue().version(),
-                        e.getValue().creationTime()));
+        return database.mapUpdate(name,
+                    keyCache.getUnchecked(key),
+                    oldValueMatch.map(serializer::encode),
+                    oldVersionMatch,
+                    value == null ? null : serializer.encode(value))
+                .thenApply(this::unwrapResult)
+                .thenApply(r -> r.<K, V>map(this::dK, serializer::decode))
+                .whenComplete((r, e) -> notifyListeners(r != null ? r.toMapEvent() : null));
     }
 
     private <T> T unwrapResult(Result<T> result) {
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultConsistentMap.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultConsistentMap.java
index 7995d8f..d6a657c 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultConsistentMap.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultConsistentMap.java
@@ -18,7 +18,6 @@
 
 import java.util.Collection;
 import java.util.Map.Entry;
-import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -115,11 +114,6 @@
     }
 
     @Override
-    public Optional<Versioned<V>> putIfAbsentAndGet(K key, V value) {
-        return complete(asyncMap.putIfAbsentAndGet(key, value));
-    }
-
-    @Override
     public Versioned<V> remove(K key) {
         return complete(asyncMap.remove(key));
     }
@@ -169,11 +163,6 @@
         return complete(asyncMap.replace(key, oldVersion, newValue));
     }
 
-    @Override
-    public Optional<Versioned<V>> replaceAndGet(K key, long oldVersion, V newValue) {
-        return complete(asyncMap.replaceAndGet(key, oldVersion, newValue));
-    }
-
     private static <T> T complete(CompletableFuture<T> future) {
         try {
             return future.get(OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java
index f8e4191..9e48051 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabase.java
@@ -64,8 +64,8 @@
     }
 
     @Override
-    public CompletableFuture<Set<String>> tableNames() {
-        return checkOpen(() -> proxy.tableNames());
+    public CompletableFuture<Set<String>> maps() {
+        return checkOpen(() -> proxy.maps());
     }
 
     @Override
@@ -74,105 +74,54 @@
     }
 
     @Override
-    public CompletableFuture<Integer> size(String tableName) {
-        return checkOpen(() -> proxy.size(tableName));
+    public CompletableFuture<Integer> mapSize(String mapName) {
+        return checkOpen(() -> proxy.mapSize(mapName));
     }
 
     @Override
-    public CompletableFuture<Boolean> isEmpty(String tableName) {
-        return checkOpen(() -> proxy.isEmpty(tableName));
+    public CompletableFuture<Boolean> mapIsEmpty(String mapName) {
+        return checkOpen(() -> proxy.mapIsEmpty(mapName));
     }
 
     @Override
-    public CompletableFuture<Boolean> containsKey(String tableName, String key) {
-        return checkOpen(() -> proxy.containsKey(tableName, key));
+    public CompletableFuture<Boolean> mapContainsKey(String mapName, String key) {
+        return checkOpen(() -> proxy.mapContainsKey(mapName, key));
     }
 
     @Override
-    public CompletableFuture<Boolean> containsValue(String tableName, byte[] value) {
-        return checkOpen(() -> proxy.containsValue(tableName, value));
+    public CompletableFuture<Boolean> mapContainsValue(String mapName, byte[] value) {
+        return checkOpen(() -> proxy.mapContainsValue(mapName, value));
     }
 
     @Override
-    public CompletableFuture<Versioned<byte[]>> get(String tableName, String key) {
-        return checkOpen(() -> proxy.get(tableName, key));
+    public CompletableFuture<Versioned<byte[]>> mapGet(String mapName, String key) {
+        return checkOpen(() -> proxy.mapGet(mapName, key));
     }
 
     @Override
-    public CompletableFuture<Result<Versioned<byte[]>>> put(String tableName, String key, byte[] value) {
-        return checkOpen(() -> proxy.put(tableName, key, value));
+    public CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(
+            String mapName, String key, Match<byte[]> valueMatch, Match<Long> versionMatch, byte[] value) {
+        return checkOpen(() -> proxy.mapUpdate(mapName, key, valueMatch, versionMatch, value));
     }
 
     @Override
-    public CompletableFuture<Result<UpdateResult<Versioned<byte[]>>>> putAndGet(String tableName,
-            String key,
-            byte[] value) {
-        return checkOpen(() -> proxy.putAndGet(tableName, key, value));
+    public CompletableFuture<Result<Void>> mapClear(String mapName) {
+        return checkOpen(() -> proxy.mapClear(mapName));
     }
 
     @Override
-    public CompletableFuture<Result<UpdateResult<Versioned<byte[]>>>> putIfAbsentAndGet(String tableName,
-            String key,
-            byte[] value) {
-        return checkOpen(() -> proxy.putIfAbsentAndGet(tableName, key, value));
+    public CompletableFuture<Set<String>> mapKeySet(String mapName) {
+        return checkOpen(() -> proxy.mapKeySet(mapName));
     }
 
     @Override
-    public CompletableFuture<Result<Versioned<byte[]>>> remove(String tableName, String key) {
-        return checkOpen(() -> proxy.remove(tableName, key));
+    public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) {
+        return checkOpen(() -> proxy.mapValues(mapName));
     }
 
     @Override
-    public CompletableFuture<Result<Void>> clear(String tableName) {
-        return checkOpen(() -> proxy.clear(tableName));
-    }
-
-    @Override
-    public CompletableFuture<Set<String>> keySet(String tableName) {
-        return checkOpen(() -> proxy.keySet(tableName));
-    }
-
-    @Override
-    public CompletableFuture<Collection<Versioned<byte[]>>> values(String tableName) {
-        return checkOpen(() -> proxy.values(tableName));
-    }
-
-    @Override
-    public CompletableFuture<Set<Map.Entry<String, Versioned<byte[]>>>> entrySet(String tableName) {
-        return checkOpen(() -> proxy.entrySet(tableName));
-    }
-
-    @Override
-    public CompletableFuture<Result<Versioned<byte[]>>> putIfAbsent(String tableName, String key, byte[] value) {
-        return checkOpen(() -> proxy.putIfAbsent(tableName, key, value));
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> remove(String tableName, String key, byte[] value) {
-        return checkOpen(() -> proxy.remove(tableName, key, value));
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> remove(String tableName, String key, long version) {
-        return checkOpen(() -> proxy.remove(tableName, key, version));
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> replace(String tableName, String key, byte[] oldValue, byte[] newValue) {
-        return checkOpen(() -> proxy.replace(tableName, key, oldValue, newValue));
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> replace(String tableName, String key, long oldVersion, byte[] newValue) {
-        return checkOpen(() -> proxy.replace(tableName, key, oldVersion, newValue));
-    }
-
-    @Override
-    public CompletableFuture<Result<UpdateResult<Versioned<byte[]>>>> replaceAndGet(String tableName,
-            String key,
-            long oldVersion,
-            byte[] newValue) {
-        return checkOpen(() -> proxy.replaceAndGet(tableName, key, oldVersion, newValue));
+    public CompletableFuture<Set<Map.Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) {
+        return checkOpen(() -> proxy.mapEntrySet(mapName));
     }
 
     @Override
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java
index f1bba25..2a37e53 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultDatabaseState.java
@@ -48,7 +48,7 @@
 public class DefaultDatabaseState implements DatabaseState<String, byte[]> {
     private Long nextVersion;
     private Map<String, AtomicLong> counters;
-    private Map<String, Map<String, Versioned<byte[]>>> tables;
+    private Map<String, Map<String, Versioned<byte[]>>> maps;
     private Map<String, Queue<byte[]>> queues;
     private Map<String, Set<NodeId>> queueUpdateNotificationTargets;
 
@@ -72,10 +72,10 @@
             counters = Maps.newConcurrentMap();
             context.put("counters", counters);
         }
-        tables = context.get("tables");
-        if (tables == null) {
-            tables = Maps.newConcurrentMap();
-            context.put("tables", tables);
+        maps = context.get("maps");
+        if (maps == null) {
+            maps = Maps.newConcurrentMap();
+            context.put("maps", maps);
         }
         locks = context.get("locks");
         if (locks == null) {
@@ -100,8 +100,8 @@
     }
 
     @Override
-    public Set<String> tableNames() {
-        return new HashSet<>(tables.keySet());
+    public Set<String> maps() {
+        return ImmutableSet.copyOf(maps.keySet());
     }
 
     @Override
@@ -112,96 +112,78 @@
     }
 
     @Override
-    public int size(String tableName) {
-      return getTableMap(tableName).size();
+    public int size(String mapName) {
+      return getMap(mapName).size();
     }
 
     @Override
-    public boolean isEmpty(String tableName) {
-        return getTableMap(tableName).isEmpty();
+    public boolean mapIsEmpty(String mapName) {
+        return getMap(mapName).isEmpty();
     }
 
     @Override
-    public boolean containsKey(String tableName, String key) {
-        return getTableMap(tableName).containsKey(key);
+    public boolean mapContainsKey(String mapName, String key) {
+        return getMap(mapName).containsKey(key);
     }
 
     @Override
-    public boolean containsValue(String tableName, byte[] value) {
-        return getTableMap(tableName).values().stream().anyMatch(v -> Arrays.equals(v.value(), value));
+    public boolean mapContainsValue(String mapName, byte[] value) {
+        return getMap(mapName).values().stream().anyMatch(v -> Arrays.equals(v.value(), value));
     }
 
     @Override
-    public Versioned<byte[]> get(String tableName, String key) {
-        return getTableMap(tableName).get(key);
+    public Versioned<byte[]> mapGet(String mapName, String key) {
+        return getMap(mapName).get(key);
     }
 
-    @Override
-    public Result<Versioned<byte[]>> put(String tableName, String key, byte[] value) {
-        return isLockedForUpdates(tableName, key)
-                ? Result.locked()
-                : Result.ok(getTableMap(tableName).put(key, new Versioned<>(value, ++nextVersion)));
-    }
 
     @Override
-    public Result<UpdateResult<Versioned<byte[]>>> putAndGet(String tableName,
+    public Result<UpdateResult<String, byte[]>> mapUpdate(
+            String mapName,
             String key,
+            Match<byte[]> valueMatch,
+            Match<Long> versionMatch,
             byte[] value) {
-        if (isLockedForUpdates(tableName, key)) {
+        if (isLockedForUpdates(mapName, key)) {
             return Result.locked();
+        }
+        Versioned<byte[]> currentValue = getMap(mapName).get(key);
+        if (!valueMatch.matches(currentValue == null ? null : currentValue.value()) ||
+                !versionMatch.matches(currentValue == null ? null : currentValue.version())) {
+            return Result.ok(new UpdateResult<>(false, mapName, key, currentValue, currentValue));
         } else {
+            if (value == null && currentValue != null) {
+                getMap(mapName).remove(key);
+                return Result.ok(new UpdateResult<>(true, mapName, key, currentValue, null));
+            }
             Versioned<byte[]> newValue = new Versioned<>(value, ++nextVersion);
-            Versioned<byte[]> oldValue = getTableMap(tableName).put(key, newValue);
-            return Result.ok(new UpdateResult<>(true, oldValue, newValue));
+            getMap(mapName).put(key, newValue);
+            return Result.ok(new UpdateResult<>(true, mapName, key, currentValue, newValue));
         }
     }
 
     @Override
-    public Result<UpdateResult<Versioned<byte[]>>> putIfAbsentAndGet(String tableName,
-            String key,
-            byte[] value) {
-        if (isLockedForUpdates(tableName, key)) {
+    public Result<Void> mapClear(String mapName) {
+        if (areTransactionsInProgress(mapName)) {
             return Result.locked();
         }
-        Versioned<byte[]> currentValue = getTableMap(tableName).get(key);
-        if (currentValue != null) {
-            return Result.ok(new UpdateResult<>(false, currentValue, currentValue));
-        } else {
-            Versioned<byte[]> newValue = new Versioned<>(value, ++nextVersion);
-            getTableMap(tableName).put(key, newValue);
-            return Result.ok(new UpdateResult<>(true, null, newValue));
-        }
-    }
-
-    @Override
-    public Result<Versioned<byte[]>> remove(String tableName, String key) {
-        return isLockedForUpdates(tableName, key)
-                ? Result.locked()
-                : Result.ok(getTableMap(tableName).remove(key));
-    }
-
-    @Override
-    public Result<Void> clear(String tableName) {
-        if (areTransactionsInProgress(tableName)) {
-            return Result.locked();
-        }
-        getTableMap(tableName).clear();
+        getMap(mapName).clear();
         return Result.ok(null);
     }
 
     @Override
-    public Set<String> keySet(String tableName) {
-        return ImmutableSet.copyOf(getTableMap(tableName).keySet());
+    public Set<String> mapKeySet(String mapName) {
+        return ImmutableSet.copyOf(getMap(mapName).keySet());
     }
 
     @Override
-    public Collection<Versioned<byte[]>> values(String tableName) {
-        return ImmutableList.copyOf(getTableMap(tableName).values());
+    public Collection<Versioned<byte[]>> mapValues(String mapName) {
+        return ImmutableList.copyOf(getMap(mapName).values());
     }
 
     @Override
-    public Set<Entry<String, Versioned<byte[]>>> entrySet(String tableName) {
-        return ImmutableSet.copyOf(getTableMap(tableName)
+    public Set<Entry<String, Versioned<byte[]>>> mapEntrySet(String mapName) {
+        return ImmutableSet.copyOf(getMap(mapName)
                 .entrySet()
                 .stream()
                 .map(entry -> Pair.of(entry.getKey(), entry.getValue()))
@@ -209,85 +191,6 @@
     }
 
     @Override
-    public Result<Versioned<byte[]>> putIfAbsent(String tableName, String key, byte[] value) {
-        if (isLockedForUpdates(tableName, key)) {
-            return Result.locked();
-        }
-        Versioned<byte[]> existingValue = get(tableName, key);
-        Versioned<byte[]> currentValue = existingValue != null ? existingValue : put(tableName, key, value).value();
-        return Result.ok(currentValue);
-    }
-
-    @Override
-    public Result<Boolean> remove(String tableName, String key, byte[] value) {
-        if (isLockedForUpdates(tableName, key)) {
-            return Result.locked();
-        }
-        Versioned<byte[]> existing = get(tableName, key);
-        if (existing != null && Arrays.equals(existing.value(), value)) {
-            getTableMap(tableName).remove(key);
-            return Result.ok(true);
-        }
-        return Result.ok(false);
-    }
-
-    @Override
-    public Result<Boolean> remove(String tableName, String key, long version) {
-        if (isLockedForUpdates(tableName, key)) {
-            return Result.locked();
-        }
-        Versioned<byte[]> existing = get(tableName, key);
-        if (existing != null && existing.version() == version) {
-            remove(tableName, key);
-            return Result.ok(true);
-        }
-        return Result.ok(false);
-    }
-
-    @Override
-    public Result<Boolean> replace(String tableName, String key, byte[] oldValue, byte[] newValue) {
-        if (isLockedForUpdates(tableName, key)) {
-            return Result.locked();
-        }
-        Versioned<byte[]> existing = get(tableName, key);
-        if (existing != null && Arrays.equals(existing.value(), oldValue)) {
-            put(tableName, key, newValue);
-            return Result.ok(true);
-        }
-        return Result.ok(false);
-    }
-
-    @Override
-    public Result<Boolean> replace(String tableName, String key, long oldVersion, byte[] newValue) {
-        if (isLockedForUpdates(tableName, key)) {
-            return Result.locked();
-        }
-        Versioned<byte[]> existing = get(tableName, key);
-        if (existing != null && existing.version() == oldVersion) {
-            put(tableName, key, newValue);
-            return Result.ok(true);
-        }
-        return Result.ok(false);
-    }
-
-    @Override
-    public Result<UpdateResult<Versioned<byte[]>>> replaceAndGet(
-            String tableName, String key, long oldVersion, byte[] newValue) {
-        if (isLockedForUpdates(tableName, key)) {
-            return Result.locked();
-        }
-        boolean updated = false;
-        Versioned<byte[]> previous = get(tableName, key);
-        Versioned<byte[]> current = previous;
-        if (previous != null && previous.version() == oldVersion) {
-            current = new Versioned<>(newValue, ++nextVersion);
-            getTableMap(tableName).put(key, current);
-            updated = true;
-        }
-        return Result.ok(new UpdateResult<>(updated, previous, current));
-    }
-
-    @Override
     public Long counterAddAndGet(String counterName, long delta) {
         return getCounter(counterName).addAndGet(delta);
     }
@@ -343,7 +246,7 @@
     @Override
     public boolean prepare(Transaction transaction) {
         if (transaction.updates().stream().anyMatch(update ->
-                    isLockedByAnotherTransaction(update.tableName(),
+                    isLockedByAnotherTransaction(update.mapName(),
                                                  update.key(),
                                                  transaction.id()))) {
             return false;
@@ -368,12 +271,12 @@
         return true;
     }
 
-    private Map<String, Versioned<byte[]>> getTableMap(String tableName) {
-        return tables.computeIfAbsent(tableName, name -> Maps.newConcurrentMap());
+    private Map<String, Versioned<byte[]>> getMap(String mapName) {
+        return maps.computeIfAbsent(mapName, name -> Maps.newConcurrentMap());
     }
 
-    private Map<String, Update> getLockMap(String tableName) {
-        return locks.computeIfAbsent(tableName, name -> Maps.newConcurrentMap());
+    private Map<String, Update> getLockMap(String mapName) {
+        return locks.computeIfAbsent(mapName, name -> Maps.newConcurrentMap());
     }
 
     private AtomicLong getCounter(String counterName) {
@@ -389,7 +292,7 @@
     }
 
     private boolean isUpdatePossible(DatabaseUpdate update) {
-        Versioned<byte[]> existingEntry = get(update.tableName(), update.key());
+        Versioned<byte[]> existingEntry = mapGet(update.mapName(), update.key());
         switch (update.type()) {
         case PUT:
         case REMOVE:
@@ -410,7 +313,7 @@
     }
 
     private void doProvisionalUpdate(DatabaseUpdate update, long transactionId) {
-        Map<String, Update> lockMap = getLockMap(update.tableName());
+        Map<String, Update> lockMap = getLockMap(update.mapName());
         switch (update.type()) {
         case PUT:
         case PUT_IF_ABSENT:
@@ -429,12 +332,12 @@
     }
 
     private void commitProvisionalUpdate(DatabaseUpdate update, long transactionId) {
-        String tableName = update.tableName();
+        String mapName = update.mapName();
         String key = update.key();
         Type type = update.type();
-        Update provisionalUpdate = getLockMap(tableName).get(key);
+        Update provisionalUpdate = getLockMap(mapName).get(key);
         if (Objects.equal(transactionId, provisionalUpdate.transactionId()))  {
-            getLockMap(tableName).remove(key);
+            getLockMap(mapName).remove(key);
         } else {
             return;
         }
@@ -444,12 +347,12 @@
         case PUT_IF_ABSENT:
         case PUT_IF_VERSION_MATCH:
         case PUT_IF_VALUE_MATCH:
-            put(tableName, key, provisionalUpdate.value());
+            mapUpdate(mapName, key, Match.any(), Match.any(), provisionalUpdate.value());
             break;
         case REMOVE:
         case REMOVE_IF_VERSION_MATCH:
         case REMOVE_IF_VALUE_MATCH:
-            remove(tableName, key);
+            mapUpdate(mapName, key, Match.any(), Match.any(), null);
             break;
         default:
             break;
@@ -457,28 +360,28 @@
     }
 
     private void undoProvisionalUpdate(DatabaseUpdate update, long transactionId) {
-        String tableName = update.tableName();
+        String mapName = update.mapName();
         String key = update.key();
-        Update provisionalUpdate = getLockMap(tableName).get(key);
+        Update provisionalUpdate = getLockMap(mapName).get(key);
         if (provisionalUpdate == null) {
             return;
         }
         if (Objects.equal(transactionId, provisionalUpdate.transactionId()))  {
-            getLockMap(tableName).remove(key);
+            getLockMap(mapName).remove(key);
         }
     }
 
-    private boolean isLockedByAnotherTransaction(String tableName, String key, long transactionId) {
-        Update update = getLockMap(tableName).get(key);
+    private boolean isLockedByAnotherTransaction(String mapName, String key, long transactionId) {
+        Update update = getLockMap(mapName).get(key);
         return update != null && !Objects.equal(transactionId, update.transactionId());
     }
 
-    private boolean isLockedForUpdates(String tableName, String key) {
-        return getLockMap(tableName).containsKey(key);
+    private boolean isLockedForUpdates(String mapName, String key) {
+        return getLockMap(mapName).containsKey(key);
     }
 
-    private boolean areTransactionsInProgress(String tableName) {
-        return !getLockMap(tableName).isEmpty();
+    private boolean areTransactionsInProgress(String mapName) {
+        return !getLockMap(mapName).isEmpty();
     }
 
     private class Update {
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionalMap.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionalMap.java
index 91151b0..ade7033 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionalMap.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/DefaultTransactionalMap.java
@@ -164,7 +164,7 @@
             Versioned<V> original = readCache.get(key);
             if (original != null) {
                 updates.add(DatabaseUpdate.newBuilder()
-                        .withTableName(name)
+                        .withMapName(name)
                         .withType(DatabaseUpdate.Type.REMOVE_IF_VERSION_MATCH)
                         .withKey(keyCache.getUnchecked(key))
                         .withCurrentVersion(original.version())
@@ -175,14 +175,14 @@
             Versioned<V> original = readCache.get(key);
             if (original == null) {
                 updates.add(DatabaseUpdate.newBuilder()
-                        .withTableName(name)
+                        .withMapName(name)
                         .withType(DatabaseUpdate.Type.PUT_IF_ABSENT)
                         .withKey(keyCache.getUnchecked(key))
                         .withValue(serializer.encode(value))
                         .build());
             } else {
                 updates.add(DatabaseUpdate.newBuilder()
-                        .withTableName(name)
+                        .withMapName(name)
                         .withType(DatabaseUpdate.Type.PUT_IF_VERSION_MATCH)
                         .withKey(keyCache.getUnchecked(key))
                         .withCurrentVersion(original.version())
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Match.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Match.java
new file mode 100644
index 0000000..093e02c
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Match.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.store.consistent.impl;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Utility class for checking matching values.
+ *
+ * @param <T> type of value
+ */
+public final class Match<T> {
+
+    private final boolean matchAny;
+    private final T value;
+
+    /**
+     * Returns a Match that matches any value.
+     * @param <T> match type
+     * @return new instance
+     */
+    public static <T> Match<T> any() {
+        return new Match<>();
+    }
+
+    /**
+     * Returns a Match that matches null values.
+     * @param <T> match type
+     * @return new instance
+     */
+    public static <T> Match<T> ifNull() {
+        return ifValue(null);
+    }
+
+    /**
+     * Returns a Match that matches only specified value.
+     * @param value value to match
+     * @param <T> match type
+     * @return new instance
+     */
+    public static <T> Match<T> ifValue(T value) {
+        return new Match<>(value);
+    }
+
+    private Match() {
+        matchAny = true;
+        value = null;
+    }
+
+    private Match(T value) {
+        matchAny = false;
+        this.value = value;
+    }
+
+    /**
+     * Maps this instance to a Match of another type.
+     * @param mapper transformation function
+     * @param <V> new match type
+     * @return new instance
+     */
+    public <V> Match<V> map(Function<T, V> mapper) {
+        if (matchAny) {
+            return any();
+        } else if (value == null) {
+            return ifNull();
+        } else {
+            return ifValue(mapper.apply(value));
+        }
+    }
+
+    /**
+     * Checks if this instance matches specified value.
+     * @param other other value
+     * @return true if matches; false otherwise
+     */
+    public boolean matches(T other) {
+        if (matchAny) {
+            return true;
+        } else if (other == null) {
+            return value == null;
+        } else {
+            if (value instanceof byte[]) {
+                return Arrays.equals((byte[]) value, (byte[]) other);
+            }
+            return Objects.equals(value, other);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("matchAny", matchAny)
+                .add("value", value)
+                .toString();
+    }
+}
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java
index bc287f0..b0fa4fe 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/PartitionedDatabase.java
@@ -82,14 +82,14 @@
     }
 
     @Override
-    public CompletableFuture<Set<String>> tableNames() {
+    public CompletableFuture<Set<String>> maps() {
         checkState(isOpen.get(), DB_NOT_OPEN);
-        Set<String> tableNames = Sets.newConcurrentHashSet();
+        Set<String> mapNames = Sets.newConcurrentHashSet();
         return CompletableFuture.allOf(partitions
                 .stream()
-                .map(db -> db.tableNames().thenApply(tableNames::addAll))
+                .map(db -> db.maps().thenApply(mapNames::addAll))
                 .toArray(CompletableFuture[]::new))
-            .thenApply(v -> tableNames);
+            .thenApply(v -> mapNames);
     }
 
     @Override
@@ -108,158 +108,100 @@
     }
 
     @Override
-    public CompletableFuture<Integer> size(String tableName) {
+    public CompletableFuture<Integer> mapSize(String mapName) {
         checkState(isOpen.get(), DB_NOT_OPEN);
         AtomicInteger totalSize = new AtomicInteger(0);
         return CompletableFuture.allOf(partitions
                     .stream()
-                    .map(p -> p.size(tableName).thenApply(totalSize::addAndGet))
+                    .map(p -> p.mapSize(mapName).thenApply(totalSize::addAndGet))
                     .toArray(CompletableFuture[]::new))
                 .thenApply(v -> totalSize.get());
     }
 
     @Override
-    public CompletableFuture<Boolean> isEmpty(String tableName) {
+    public CompletableFuture<Boolean> mapIsEmpty(String mapName) {
         checkState(isOpen.get(), DB_NOT_OPEN);
-        return size(tableName).thenApply(size -> size == 0);
+        return mapSize(mapName).thenApply(size -> size == 0);
     }
 
     @Override
-    public CompletableFuture<Boolean> containsKey(String tableName, String key) {
+    public CompletableFuture<Boolean> mapContainsKey(String mapName, String key) {
         checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).containsKey(tableName, key);
+        return partitioner.getPartition(mapName, key).mapContainsKey(mapName, key);
     }
 
     @Override
-    public CompletableFuture<Boolean> containsValue(String tableName, byte[] value) {
+    public CompletableFuture<Boolean> mapContainsValue(String mapName, byte[] value) {
         checkState(isOpen.get(), DB_NOT_OPEN);
         AtomicBoolean containsValue = new AtomicBoolean(false);
         return CompletableFuture.allOf(partitions
                     .stream()
-                    .map(p -> p.containsValue(tableName, value).thenApply(v -> containsValue.compareAndSet(false, v)))
+                    .map(p -> p.mapContainsValue(mapName, value)
+                               .thenApply(v -> containsValue.compareAndSet(false, v)))
                     .toArray(CompletableFuture[]::new))
                 .thenApply(v -> containsValue.get());
     }
 
     @Override
-    public CompletableFuture<Versioned<byte[]>> get(String tableName, String key) {
+    public CompletableFuture<Versioned<byte[]>> mapGet(String mapName, String key) {
         checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).get(tableName, key);
+        return partitioner.getPartition(mapName, key).mapGet(mapName, key);
     }
 
     @Override
-    public CompletableFuture<Result<Versioned<byte[]>>> put(String tableName, String key, byte[] value) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).put(tableName, key, value);
+    public CompletableFuture<Result<UpdateResult<String, byte[]>>> mapUpdate(
+            String mapName, String key, Match<byte[]> valueMatch,
+            Match<Long> versionMatch, byte[] value) {
+        return partitioner.getPartition(mapName, key).mapUpdate(mapName, key, valueMatch, versionMatch, value);
+
     }
 
     @Override
-    public CompletableFuture<Result<UpdateResult<Versioned<byte[]>>>> putAndGet(String tableName,
-            String key,
-            byte[] value) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).putAndGet(tableName, key, value);
-    }
-
-    @Override
-    public CompletableFuture<Result<UpdateResult<Versioned<byte[]>>>> putIfAbsentAndGet(String tableName,
-            String key,
-            byte[] value) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).putIfAbsentAndGet(tableName, key, value);
-    }
-
-    @Override
-    public CompletableFuture<Result<Versioned<byte[]>>> remove(String tableName, String key) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).remove(tableName, key);
-    }
-
-    @Override
-    public CompletableFuture<Result<Void>> clear(String tableName) {
+    public CompletableFuture<Result<Void>> mapClear(String mapName) {
         AtomicBoolean isLocked = new AtomicBoolean(false);
         checkState(isOpen.get(), DB_NOT_OPEN);
         return CompletableFuture.allOf(partitions
                     .stream()
-                    .map(p -> p.clear(tableName)
+                    .map(p -> p.mapClear(mapName)
                             .thenApply(v -> isLocked.compareAndSet(false, Result.Status.LOCKED == v.status())))
                     .toArray(CompletableFuture[]::new))
                 .thenApply(v -> isLocked.get() ? Result.locked() : Result.ok(null));
     }
 
     @Override
-    public CompletableFuture<Set<String>> keySet(String tableName) {
+    public CompletableFuture<Set<String>> mapKeySet(String mapName) {
         checkState(isOpen.get(), DB_NOT_OPEN);
         Set<String> keySet = Sets.newConcurrentHashSet();
         return CompletableFuture.allOf(partitions
                     .stream()
-                    .map(p -> p.keySet(tableName).thenApply(keySet::addAll))
+                    .map(p -> p.mapKeySet(mapName).thenApply(keySet::addAll))
                     .toArray(CompletableFuture[]::new))
                 .thenApply(v -> keySet);
     }
 
     @Override
-    public CompletableFuture<Collection<Versioned<byte[]>>> values(String tableName) {
+    public CompletableFuture<Collection<Versioned<byte[]>>> mapValues(String mapName) {
         checkState(isOpen.get(), DB_NOT_OPEN);
         List<Versioned<byte[]>> values = new CopyOnWriteArrayList<>();
         return CompletableFuture.allOf(partitions
                     .stream()
-                    .map(p -> p.values(tableName).thenApply(values::addAll))
+                    .map(p -> p.mapValues(mapName).thenApply(values::addAll))
                     .toArray(CompletableFuture[]::new))
                 .thenApply(v -> values);
     }
 
     @Override
-    public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> entrySet(String tableName) {
+    public CompletableFuture<Set<Entry<String, Versioned<byte[]>>>> mapEntrySet(String mapName) {
         checkState(isOpen.get(), DB_NOT_OPEN);
         Set<Entry<String, Versioned<byte[]>>> entrySet = Sets.newConcurrentHashSet();
         return CompletableFuture.allOf(partitions
                     .stream()
-                    .map(p -> p.entrySet(tableName).thenApply(entrySet::addAll))
+                    .map(p -> p.mapEntrySet(mapName).thenApply(entrySet::addAll))
                     .toArray(CompletableFuture[]::new))
                 .thenApply(v -> entrySet);
     }
 
     @Override
-    public CompletableFuture<Result<Versioned<byte[]>>> putIfAbsent(String tableName, String key, byte[] value) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).putIfAbsent(tableName, key, value);
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> remove(String tableName, String key, byte[] value) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).remove(tableName, key, value);
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> remove(String tableName, String key, long version) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).remove(tableName, key, version);
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> replace(
-            String tableName, String key, byte[] oldValue, byte[] newValue) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).replace(tableName, key, oldValue, newValue);
-    }
-
-    @Override
-    public CompletableFuture<Result<Boolean>> replace(
-            String tableName, String key, long oldVersion, byte[] newValue) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).replace(tableName, key, oldVersion, newValue);
-    }
-
-    @Override
-    public CompletableFuture<Result<UpdateResult<Versioned<byte[]>>>> replaceAndGet(
-            String tableName, String key, long oldVersion, byte[] newValue) {
-        checkState(isOpen.get(), DB_NOT_OPEN);
-        return partitioner.getPartition(tableName, key).replaceAndGet(tableName, key, oldVersion, newValue);
-    }
-
-    @Override
     public CompletableFuture<Long> counterGet(String counterName) {
         checkState(isOpen.get(), DB_NOT_OPEN);
         return partitioner.getPartition(counterName, counterName).counterGet(counterName);
@@ -408,7 +350,7 @@
             Transaction transaction) {
         Map<Database, List<DatabaseUpdate>> perPartitionUpdates = Maps.newHashMap();
         for (DatabaseUpdate update : transaction.updates()) {
-            Database partition = partitioner.getPartition(update.tableName(), update.key());
+            Database partition = partitioner.getPartition(update.mapName(), update.key());
             List<DatabaseUpdate> partitionUpdates =
                     perPartitionUpdates.computeIfAbsent(partition, k -> Lists.newLinkedList());
             partitionUpdates.add(update);
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Partitioner.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Partitioner.java
index 37eb1f3..de630b9 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Partitioner.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/Partitioner.java
@@ -25,9 +25,9 @@
 
     /**
      * Returns the database partition.
-     * @param tableName table name
+     * @param mapName map name
      * @param key key
      * @return Database partition
      */
-    Database getPartition(String tableName, K key);
+    Database getPartition(String mapName, K key);
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleKeyHashPartitioner.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleKeyHashPartitioner.java
index 4475bc9..4086428 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleKeyHashPartitioner.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleKeyHashPartitioner.java
@@ -32,7 +32,7 @@
     }
 
     @Override
-    public Database getPartition(String tableName, String key) {
+    public Database getPartition(String mapName, String key) {
         return partitions.get(hash(key) % partitions.size());
     }
 }
\ No newline at end of file
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleTableHashPartitioner.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleTableHashPartitioner.java
index e8daeff..8dc26e0 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleTableHashPartitioner.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/SimpleTableHashPartitioner.java
@@ -19,11 +19,11 @@
 import java.util.List;
 
 /**
- * A simple Partitioner that uses the table name hash to
+ * A simple Partitioner that uses the map name hash to
  * pick a partition.
  * <p>
- * This class uses a md5 hash based hashing scheme for hashing the table name to
- * a partition. This partitioner maps all keys for a table to the same database
+ * This class uses a md5 hash based hashing scheme for hashing the map name to
+ * a partition. This partitioner maps all keys for a map to the same database
  * partition.
  */
 public class SimpleTableHashPartitioner extends DatabasePartitioner {
@@ -33,7 +33,7 @@
     }
 
     @Override
-    public Database getPartition(String tableName, String key) {
-        return partitions.get(hash(tableName) % partitions.size());
+    public Database getPartition(String mapName, String key) {
+        return partitions.get(hash(mapName) % partitions.size());
     }
 }
diff --git a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/UpdateResult.java b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/UpdateResult.java
index 4f3c663..50b78dd 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/UpdateResult.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/consistent/impl/UpdateResult.java
@@ -15,6 +15,11 @@
  */
 package org.onosproject.store.consistent.impl;
 
+import java.util.function.Function;
+
+import org.onosproject.store.service.MapEvent;
+import org.onosproject.store.service.Versioned;
+
 /**
  * Result of a update operation.
  * <p>
@@ -23,14 +28,18 @@
  * point to the same unmodified value.
  * @param <V> result type
  */
-public class UpdateResult<V> {
+public class UpdateResult<K, V> {
 
     private final boolean updated;
-    private final V oldValue;
-    private final V newValue;
+    private final String mapName;
+    private final K key;
+    private final Versioned<V> oldValue;
+    private final Versioned<V> newValue;
 
-    public UpdateResult(boolean updated, V oldValue, V newValue) {
+    public UpdateResult(boolean updated, String mapName, K key, Versioned<V> oldValue, Versioned<V> newValue) {
         this.updated = updated;
+        this.mapName = mapName;
+        this.key = key;
         this.oldValue = oldValue;
         this.newValue = newValue;
     }
@@ -39,11 +48,38 @@
         return updated;
     }
 
-    public V oldValue() {
+    public String mapName() {
+        return mapName;
+    }
+
+    public K key() {
+        return key;
+    }
+
+    public Versioned<V> oldValue() {
         return oldValue;
     }
 
-    public V newValue() {
+    public Versioned<V> newValue() {
         return newValue;
     }
+
+    public <K1, V1> UpdateResult<K1, V1> map(Function<K, K1> keyTransform, Function<V, V1> valueMapper) {
+        return new UpdateResult<>(updated,
+                mapName,
+                keyTransform.apply(key),
+                oldValue == null ? null : oldValue.map(valueMapper),
+                newValue == null ? null : newValue.map(valueMapper));
+    }
+
+    public MapEvent<K, V> toMapEvent() {
+        if (!updated) {
+            return null;
+        } else {
+            MapEvent.Type eventType = oldValue == null ?
+                    MapEvent.Type.INSERT : newValue == null ? MapEvent.Type.REMOVE : MapEvent.Type.UPDATE;
+            Versioned<V> eventValue = eventType == MapEvent.Type.REMOVE ? oldValue : newValue;
+            return new MapEvent<>(mapName(), eventType, key(), eventValue);
+        }
+    }
 }
\ No newline at end of file