You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by re...@apache.org on 2017/10/29 09:04:54 UTC

svn commit: r1813674 - in /jackrabbit/oak/trunk/oak-store-document/src: main/java/org/apache/jackrabbit/oak/plugins/document/ main/java/org/apache/jackrabbit/oak/plugins/document/memory/ main/java/org/apache/jackrabbit/oak/plugins/document/mongo/ main/...

Author: reschke
Date: Sun Oct 29 09:04:54 2017
New Revision: 1813674

URL: http://svn.apache.org/viewvc?rev=1813674&view=rev
Log:
OAK-6813: DocumentStore conditional remove: reduce set of supported conditions to what the Version GC needs

Modified:
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreJDBC.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java
    jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/ReadOnlyDocumentStoreWrapperTest.java

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentStore.java Sun Oct 29 09:04:54 2017
@@ -178,9 +178,10 @@ public interface DocumentStore {
             throws DocumentStoreException;
 
     /**
-     * Batch remove documents with given keys and corresponding conditions. Keys
-     * for documents that do not exist are simply ignored. A document is only
-     * removed if the corresponding conditions are met.
+     * Batch remove documents with given keys and corresponding equal conditions
+     * on {@link NodeDocument#MODIFIED_IN_SECS} values. Keys for documents that
+     * do not exist are simply ignored. A document is only removed if the
+     * corresponding condition is met.
      * <p>
      * In case of a {@code DocumentStoreException}, the documents with the given
      * keys may or may not have been removed from the store. It may also be
@@ -190,16 +191,18 @@ public interface DocumentStore {
      * properly reflected in the document cache. That is, an implementation
      * could simply evict documents with the given keys from the cache.
      *
-     * @param <T> the document type
-     * @param collection the collection.
-     * @param toRemove the keys of the documents to remove with the
-     *                 corresponding conditions.
+     * @param <T>
+     *            the document type
+     * @param collection
+     *            the collection.
+     * @param toRemove
+     *            the keys of the documents to remove with the corresponding
+     *            timestamps.
      * @return the number of removed documents.
-     * @throws DocumentStoreException if the operation failed. E.g. because of
-     *          an I/O error.
+     * @throws DocumentStoreException
+     *             if the operation failed. E.g. because of an I/O error.
      */
-    <T extends Document> int remove(Collection<T> collection,
-                                    Map<String, Map<UpdateOp.Key, UpdateOp.Condition>> toRemove)
+    <T extends Document> int remove(Collection<T> collection, Map<String, Long> toRemove)
             throws DocumentStoreException;
 
 

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java Sun Oct 29 09:04:54 2017
@@ -44,8 +44,6 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
 import org.apache.jackrabbit.oak.commons.sort.StringSort;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.util.TimeInterval;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.spi.gc.DelegatingGCMonitor;
@@ -61,7 +59,6 @@ import static com.google.common.base.Sta
 import static com.google.common.collect.Iterables.all;
 import static com.google.common.collect.Iterators.partition;
 import static com.google.common.util.concurrent.Atomics.newReference;
-import static java.util.Collections.singletonMap;
 import static java.util.concurrent.TimeUnit.MICROSECONDS;
 import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
 import static org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS;
@@ -69,7 +66,6 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SplitDocType.COMMIT_ROOT_ONLY;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SplitDocType.DEFAULT_LEAF;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SplitDocType.DEFAULT_NO_BRANCH;
-import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition.newEqualsCondition;
 import static org.slf4j.helpers.MessageFormatter.arrayFormat;
 
 public class VersionGarbageCollector {
@@ -78,7 +74,6 @@ public class VersionGarbageCollector {
     private static final int DELETE_BATCH_SIZE = 450;
     private static final int UPDATE_BATCH_SIZE = 450;
     private static final int PROGRESS_BATCH_SIZE = 10000;
-    private static final Key KEY_MODIFIED = new Key(MODIFIED_IN_SECS, null);
     private static final String STATUS_IDLE = "IDLE";
     private static final String STATUS_INITIALIZING = "INITIALIZING";
     private static final Logger log = LoggerFactory.getLogger(VersionGarbageCollector.class);
@@ -853,7 +848,7 @@ public class VersionGarbageCollector {
             int lastLoggedCount = 0;
             int recreatedCount = 0;
             while (idListItr.hasNext() && !cancel.get()) {
-                Map<String, Map<Key, Condition>> deletionBatch = Maps.newLinkedHashMap();
+                Map<String, Long> deletionBatch = Maps.newLinkedHashMap();
                 for (String s : idListItr.next()) {
                     Map.Entry<String, Long> parsed;
                     try {
@@ -862,7 +857,7 @@ public class VersionGarbageCollector {
                         monitor.warn("Invalid _modified suffix for {}", s);
                         continue;
                     }
-                    deletionBatch.put(parsed.getKey(), singletonMap(KEY_MODIFIED, newEqualsCondition(parsed.getValue())));
+                    deletionBatch.put(parsed.getKey(), parsed.getValue());
                 }
 
                 if (log.isTraceEnabled()) {

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/memory/MemoryDocumentStore.java Sun Oct 29 09:04:54 2017
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.plugins.document.memory;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentNavigableMap;
@@ -41,6 +42,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.UpdateUtils;
 
 import com.google.common.base.Splitter;
@@ -49,6 +51,8 @@ import com.mongodb.WriteConcern;
 import org.apache.jackrabbit.oak.plugins.document.cache.CacheInvalidationStats;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 
+import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS;
+import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition.newEqualsCondition;
 import static org.apache.jackrabbit.oak.plugins.document.UpdateUtils.assertUnconditional;
 import static org.apache.jackrabbit.oak.plugins.document.UpdateUtils.checkConditions;
 
@@ -94,6 +98,8 @@ public class MemoryDocumentStore impleme
 
     private final boolean maintainModCount;
 
+    private static final Key KEY_MODIFIED = new Key(MODIFIED_IN_SECS, null);
+
     public MemoryDocumentStore() {
         this(false);
     }
@@ -192,16 +198,16 @@ public class MemoryDocumentStore impleme
     }
 
     @Override
-    public <T extends Document> int remove(Collection<T> collection,
-                                           Map<String, Map<UpdateOp.Key, Condition>> toRemove) {
+    public <T extends Document> int remove(Collection<T> collection, Map<String, Long> toRemove) {
         int num = 0;
         ConcurrentSkipListMap<String, T> map = getMap(collection);
-        for (Map.Entry<String, Map<UpdateOp.Key, Condition>> entry : toRemove.entrySet()) {
+        for (Map.Entry<String, Long> entry : toRemove.entrySet()) {
             Lock lock = rwLock.writeLock();
             lock.lock();
             try {
                 T doc = map.get(entry.getKey());
-                if (doc != null && checkConditions(doc, entry.getValue())) {
+                Condition c = newEqualsCondition(entry.getValue());
+                if (doc != null && checkConditions(doc, Collections.singletonMap(KEY_MODIFIED, c))) {
                     if (map.remove(entry.getKey()) != null) {
                         num++;
                     }

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java Sun Oct 29 09:04:54 2017
@@ -112,6 +112,7 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SD_MAX_REV_TIME_IN_SECS;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SD_TYPE;
+import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition.newEqualsCondition;
 import static org.apache.jackrabbit.oak.plugins.document.mongo.MongoUtils.createIndex;
 import static org.apache.jackrabbit.oak.plugins.document.mongo.MongoUtils.createPartialIndex;
 import static org.apache.jackrabbit.oak.plugins.document.mongo.MongoUtils.hasIndex;
@@ -229,6 +230,8 @@ public class MongoDocumentStore implemen
 
     private boolean hasModifiedIdCompoundIndex = true;
 
+    private static final Key KEY_MODIFIED = new Key(MODIFIED_IN_SECS, null);
+
     public MongoDocumentStore(DB db, DocumentMK.Builder builder) {
         MongoStatus mongoStatus = builder.getMongoStatus();
         if (mongoStatus == null) {
@@ -721,8 +724,7 @@ public class MongoDocumentStore implemen
     }
 
     @Override
-    public <T extends Document> int remove(Collection<T> collection,
-                                           Map<String, Map<Key, Condition>> toRemove) {
+    public <T extends Document> int remove(Collection<T> collection, Map<String, Long> toRemove) {
         log("remove", toRemove);
         int num = 0;
         DBCollection dbCollection = getDBCollection(collection);
@@ -730,11 +732,12 @@ public class MongoDocumentStore implemen
         try {
             List<String> batchIds = Lists.newArrayList();
             List<DBObject> batch = Lists.newArrayList();
-            Iterator<Entry<String, Map<Key, Condition>>> it = toRemove.entrySet().iterator();
+            Iterator<Entry<String, Long>> it = toRemove.entrySet().iterator();
             while (it.hasNext()) {
-                Entry<String, Map<Key, Condition>> entry = it.next();
+                Entry<String, Long> entry = it.next();
+                Condition c = newEqualsCondition(entry.getValue());
                 QueryBuilder query = createQueryForUpdate(
-                        entry.getKey(), entry.getValue());
+                        entry.getKey(),  Collections.singletonMap(KEY_MODIFIED, c));
                 batchIds.add(entry.getKey());
                 batch.add(query.get());
                 if (!it.hasNext() || batch.size() == IN_CLAUSE_BATCH_SIZE) {

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java Sun Oct 29 09:04:54 2017
@@ -72,9 +72,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
 import org.apache.jackrabbit.oak.plugins.document.DocumentStoreStatsCollector;
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp;import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation;
 import org.apache.jackrabbit.oak.plugins.document.UpdateUtils;
 import org.apache.jackrabbit.oak.plugins.document.cache.CacheChangesTracker;
@@ -308,7 +306,7 @@ public class RDBDocumentStore implements
     }
 
     @Override
-    public <T extends Document> int remove(Collection<T> collection, Map<String, Map<Key, Condition>> toRemove) {
+    public <T extends Document> int remove(Collection<T> collection, Map<String, Long> toRemove) {
         try {
             return delete(collection, toRemove);
         } finally {
@@ -1774,14 +1772,13 @@ public class RDBDocumentStore implements
         return numDeleted;
     }
 
-    private <T extends Document> int delete(Collection<T> collection,
-                                            Map<String, Map<Key, Condition>> toRemove) {
+    private <T extends Document> int delete(Collection<T> collection, Map<String, Long> toRemove) {
         int numDeleted = 0;
         RDBTableMetaData tmd = getTable(collection);
-        Map<String, Map<Key, Condition>> subMap = Maps.newHashMap();
-        Iterator<Entry<String, Map<Key, Condition>>> it = toRemove.entrySet().iterator();
+        Map<String, Long> subMap = Maps.newHashMap();
+        Iterator<Entry<String, Long>> it = toRemove.entrySet().iterator();
         while (it.hasNext()) {
-            Entry<String, Map<Key, Condition>> entry = it.next();
+            Entry<String, Long> entry = it.next();
             subMap.put(entry.getKey(), entry.getValue());
             if (subMap.size() == 64 || !it.hasNext()) {
                 Connection connection = null;

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreJDBC.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreJDBC.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreJDBC.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStoreJDBC.java Sun Oct 29 09:04:54 2017
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
 
 import static com.google.common.collect.Iterables.transform;
 import static com.google.common.collect.Sets.newHashSet;
-import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS;
 import static org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.CHAR2OCTETRATIO;
 import static org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.asBytes;
 import static org.apache.jackrabbit.oak.plugins.document.rdb.RDBJDBCTools.closeResultSet;
@@ -53,9 +52,6 @@ import javax.annotation.Nonnull;
 import org.apache.jackrabbit.oak.plugins.document.Document;
 import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.QueryCondition;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.RDBTableMetaData;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStoreDB.FETCHFIRSTSYNTAX;
@@ -199,26 +195,13 @@ public class RDBDocumentStoreJDBC {
         return count;
     }
 
-    public int delete(Connection connection, RDBTableMetaData tmd, Map<String, Map<Key, Condition>> toDelete)
+    public int delete(Connection connection, RDBTableMetaData tmd, Map<String, Long> toDelete)
             throws SQLException, DocumentStoreException {
-        // sanity check on parameters; see OAK-6789
-        for (Entry<String, Map<Key, Condition>> entry : toDelete.entrySet()) {
-            if (entry.getValue().entrySet().size() != 1) {
-                throw new DocumentStoreException("Unsupported number of conditions in : " + entry.getValue().entrySet());
-            }
-            Entry<Key, Condition> c = entry.getValue().entrySet().iterator().next();
-            if (!c.getKey().getName().equals(MODIFIED) || c.getKey().getRevision() != null
-                    || c.getValue().type != Condition.Type.EQUALS) {
-                throw new DocumentStoreException("Unsupported condition: " + c);
-            }
-        }
-
         PreparedStatement stmt = connection.prepareStatement("delete from " + tmd.getName() + " where ID=? and MODIFIED=?");
-        UpdateOp.Key MODIFIEDKEY = new UpdateOp.Key(MODIFIED_IN_SECS, null);
         try {
-            for (Entry<String, Map<Key, Condition>> entry : toDelete.entrySet()) {
+            for (Entry<String, Long> entry : toDelete.entrySet()) {
                 setIdInStatement(tmd, stmt, 1, entry.getKey());
-                stmt.setLong(2, (Long) entry.getValue().get(MODIFIEDKEY).value);
+                stmt.setLong(2, entry.getValue());
                 stmt.addBatch();
             }
             int[] rets = stmt.executeBatch();

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LeaseCheckDocumentStoreWrapper.java Sun Oct 29 09:04:54 2017
@@ -30,8 +30,6 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.RevisionListener;
 import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
 import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.cache.CacheInvalidationStats;
 
 /**
@@ -103,7 +101,7 @@ public final class LeaseCheckDocumentSto
 
     @Override
     public final <T extends Document> int remove(Collection<T> collection,
-            Map<String, Map<Key, Condition>> toRemove) {
+            Map<String, Long> toRemove) {
         performLeaseCheck();
         return delegate.remove(collection, toRemove);
     }

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/LoggingDocumentStoreWrapper.java Sun Oct 29 09:04:54 2017
@@ -157,7 +157,7 @@ public class LoggingDocumentStoreWrapper
 
     @Override
     public <T extends Document> int remove(final Collection<T> collection,
-                                           final Map<String, Map<UpdateOp.Key, UpdateOp.Condition>> toRemove) {
+                                           final Map<String, Long> toRemove) {
         try {
             logMethod("remove", collection, toRemove);
             return logResult(new Callable<Integer>() {

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/SynchronizingDocumentStoreWrapper.java Sun Oct 29 09:04:54 2017
@@ -79,7 +79,7 @@ public class SynchronizingDocumentStoreW
 
     @Override
     public synchronized <T extends Document> int remove(Collection<T> collection,
-                                                        Map<String, Map<UpdateOp.Key, UpdateOp.Condition>> toRemove) {
+                                                        Map<String, Long> toRemove) {
         return store.remove(collection, toRemove);
     }
 

Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/TimingDocumentStoreWrapper.java Sun Oct 29 09:04:54 2017
@@ -197,7 +197,7 @@ public class TimingDocumentStoreWrapper
 
     @Override
     public <T extends Document> int remove(Collection<T> collection,
-                                           Map<String, Map<UpdateOp.Key, UpdateOp.Condition>> toRemove) {
+                                           Map<String, Long> toRemove) {
         try {
             long start = now();
             int result = base.remove(collection, toRemove);

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java Sun Oct 29 09:04:54 2017
@@ -34,8 +34,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
 
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.junit.Test;
 import org.slf4j.Logger;
@@ -1118,11 +1116,11 @@ public class BasicDocumentStoreTest exte
             assertNotNull(ds.find(Collection.NODES, op.getId()));
         }
 
-        Map<String, Map<Key, Condition>> toRemove = Maps.newHashMap();
-        removeDocument(toRemove, "/foo", 100); // matches
-        removeDocument(toRemove, "/bar", 300); // modified differs
-        removeDocument(toRemove, "/qux", 100); // does not exist
-        removeDocument(toRemove, "/baz", 300); // matches
+        Map<String, Long> toRemove = Maps.newHashMap();
+        toRemove.put(Utils.getIdFromPath("/foo"), 100L); // matches
+        toRemove.put(Utils.getIdFromPath("/bar"), 300L); // modified differs
+        toRemove.put(Utils.getIdFromPath("/qux"), 100L); // does not exist
+        toRemove.put(Utils.getIdFromPath("/baz"), 300L); // matches
 
         int removed = ds.remove(Collection.NODES, toRemove);
 
@@ -1141,10 +1139,7 @@ public class BasicDocumentStoreTest exte
         long modified = 1;
         removeMe.add(id);
         ds.create(Collection.NODES, Collections.singletonList(newDocument(id, modified)));
-
-        Map<Key, Condition> conditions = Collections.singletonMap(new Key(NodeDocument.MODIFIED_IN_SECS, null),
-                Condition.newEqualsCondition(modified));
-        ds.remove(Collection.NODES, Collections.singletonMap(id, conditions));
+        ds.remove(Collection.NODES, Collections.singletonMap(id, modified));
         assertNull(ds.getIfCached(Collection.NODES, id));
     }
 
@@ -1162,13 +1157,4 @@ public class BasicDocumentStoreTest exte
         op.set(NodeDocument.MODIFIED_IN_SECS, modified);
         return op;
     }
-
-    private void removeDocument(Map<String, Map<Key, Condition>> toRemove,
-                                String path,
-                                long modified) {
-        toRemove.put(Utils.getIdFromPath(path),
-                Collections.singletonMap(
-                        new Key(NodeDocument.MODIFIED_IN_SECS, null),
-                        Condition.newEqualsCondition(modified)));
-    }
 }

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/CountingDocumentStore.java Sun Oct 29 09:04:54 2017
@@ -23,8 +23,6 @@ import java.util.Map;
 import javax.annotation.Nonnull;
 
 import org.apache.jackrabbit.oak.cache.CacheStats;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.cache.CacheInvalidationStats;
 
 public class CountingDocumentStore implements DocumentStore, RevisionListener {
@@ -143,7 +141,7 @@ public class CountingDocumentStore imple
 
     @Override
     public <T extends Document> int remove(Collection<T> collection,
-                                           Map<String, Map<Key, Condition>> toRemove) {
+                                           Map<String, Long> toRemove) {
         getStats(collection).numRemoveCalls++;
         return delegate.remove(collection, toRemove);
     }

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreStatsIT.java Sun Oct 29 09:04:54 2017
@@ -28,8 +28,6 @@ import java.util.UUID;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
 import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
 import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
 import org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore;
@@ -39,10 +37,8 @@ import org.junit.Test;
 import org.junit.rules.TestName;
 
 import static java.util.Collections.singletonList;
-import static java.util.Collections.singletonMap;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS;
 import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.getModifiedInSecs;
-import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition.newEqualsCondition;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.mockito.Matchers.anyInt;
@@ -191,12 +187,11 @@ public class DocumentStoreStatsIT extend
     @Test
     public void removeConditional() throws Exception {
         Revision r = Revision.newRevision(1);
-        Key modified = new Key(MODIFIED_IN_SECS, null);
-        Condition c = newEqualsCondition(getModifiedInSecs(r.getTimestamp()));
-        Map<String, Map<Key, Condition>> ids = Maps.newHashMap();
+        long modified = getModifiedInSecs(r.getTimestamp());
+        Map<String, Long> ids = Maps.newHashMap();
         for (int i = 0; i < 10; i++) {
             String id = testName.getMethodName() + "-" + i;
-            ids.put(id, singletonMap(modified, c));
+            ids.put(id, modified);
             UpdateOp up = new UpdateOp(id, true);
             NodeDocument.setModified(up, r);
             ds.create(Collection.NODES, singletonList(up));

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreWrapper.java Sun Oct 29 09:04:54 2017
@@ -83,7 +83,7 @@ public class DocumentStoreWrapper implem
 
     @Override
     public <T extends Document> int remove(Collection<T> collection,
-                                           Map<String, Map<UpdateOp.Key, UpdateOp.Condition>> toRemove) {
+                                           Map<String, Long> toRemove) {
         return store.remove(collection, toRemove);
     }
 

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/FailingDocumentStore.java Sun Oct 29 09:04:54 2017
@@ -106,10 +106,10 @@ class FailingDocumentStore extends Docum
 
     @Override
     public <T extends Document> int remove(Collection<T> collection,
-                                           Map<String, Map<UpdateOp.Key, UpdateOp.Condition>> toRemove) {
+                                           Map<String, Long> toRemove) {
         int num = 0;
         // remove individually
-        for (Map.Entry<String, Map<UpdateOp.Key, UpdateOp.Condition>> rm : toRemove.entrySet()) {
+        for (Map.Entry<String, Long> rm : toRemove.entrySet()) {
             maybeFail();
             num += super.remove(collection, singletonMap(rm.getKey(), rm.getValue()));
         }

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/ReadOnlyDocumentStoreWrapperTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/ReadOnlyDocumentStoreWrapperTest.java?rev=1813674&r1=1813673&r2=1813674&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/ReadOnlyDocumentStoreWrapperTest.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/ReadOnlyDocumentStoreWrapperTest.java Sun Oct 29 09:04:54 2017
@@ -1,195 +1,194 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.jackrabbit.oak.plugins.document.util;
-
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import org.apache.jackrabbit.oak.plugins.document.Collection;
-import org.apache.jackrabbit.oak.plugins.document.Document;
-import org.apache.jackrabbit.oak.plugins.document.DocumentMKBuilderProvider;
-import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
-import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
-import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
-import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
-import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
-import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
-import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
-import org.junit.Assert;
-import org.junit.Rule;
-import org.junit.Test;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-public class ReadOnlyDocumentStoreWrapperTest {
-    @Rule
-    public DocumentMKBuilderProvider builderProvider = new DocumentMKBuilderProvider();
-
-    @Test
-    public void testPassthrough() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
-        final List<String> disallowedMethods = Lists.newArrayList(
-                "create", "update", "remove", "createOrUpdate", "findAndUpdate");
-        InvocationHandler handler = new InvocationHandler() {
-            @Override
-            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-                String methodName = method.getName();
-
-                if (disallowedMethods.contains(methodName)) {
-                    Assert.fail(String.format("Invalid passthrough of method (%s) with params %s", method, Arrays.toString(args)));
-                }
-
-                if ("determineServerTimeDifferenceMillis".equals(methodName)) {
-                    return new Long(0);
-                } else {
-                    return null;
-                }
-            }
-        };
-        DocumentStore proxyStore = (DocumentStore)Proxy.newProxyInstance(DocumentStore.class.getClassLoader(),
-                new Class[]{DocumentStore.class},
-                handler);
-
-        DocumentStore readOnlyStore = ReadOnlyDocumentStoreWrapperFactory.getInstance(proxyStore);
-
-        Collection<? extends Document> []collections = new Collection[] {
-                Collection.CLUSTER_NODES, Collection.JOURNAL, Collection.NODES, Collection.SETTINGS
-        };
-        for (Collection collection : collections) {
-            readOnlyStore.find(collection, null);
-            readOnlyStore.find(collection, null, 0);
-
-            readOnlyStore.query(collection, null, null, 0);
-            readOnlyStore.query(collection, null, null, null, 0, 0);
-
-            boolean uoeThrown = false;
-            try {
-                readOnlyStore.remove(collection, "");
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("remove must throw UnsupportedOperationException", uoeThrown);
-
-            uoeThrown = false;
-            try {
-                readOnlyStore.remove(collection, Lists.<String>newArrayList());
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("remove must throw UnsupportedOperationException", uoeThrown);
-
-            uoeThrown = false;
-            try {
-                readOnlyStore.remove(collection, Maps.<String, Map<UpdateOp.Key, UpdateOp.Condition>>newHashMap());
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("remove must throw UnsupportedOperationException", uoeThrown);
-            uoeThrown = false;
-
-            try {
-                readOnlyStore.create(collection, null);
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("create must throw UnsupportedOperationException", uoeThrown);
-            uoeThrown = false;
-
-            try {
-                readOnlyStore.update(collection, null, null);
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("update must throw UnsupportedOperationException", uoeThrown);
-            uoeThrown = false;
-
-            try {
-                readOnlyStore.createOrUpdate(collection, (UpdateOp) null);
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("createOrUpdate must throw UnsupportedOperationException", uoeThrown);
-            uoeThrown = false;
-
-            try {
-                readOnlyStore.createOrUpdate(collection, Lists.<UpdateOp>newArrayList());
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("createOrUpdate must throw UnsupportedOperationException", uoeThrown);
-            uoeThrown = false;
-
-            try {
-                readOnlyStore.findAndUpdate(collection, null);
-            } catch (UnsupportedOperationException uoe) {
-                //catch uoe thrown by read only wrapper
-                uoeThrown = true;
-            }
-            assertTrue("findAndUpdate must throw UnsupportedOperationException", uoeThrown);
-
-            readOnlyStore.invalidateCache(collection, null);
-            readOnlyStore.getIfCached(collection, null);
-        }
-
-        readOnlyStore.invalidateCache();
-        readOnlyStore.invalidateCache(null);
-
-        readOnlyStore.dispose();
-        readOnlyStore.setReadWriteMode(null);
-        readOnlyStore.getCacheStats();
-        readOnlyStore.getMetadata();
-        readOnlyStore.determineServerTimeDifferenceMillis();
-    }
-
-    @Test
-    public void backgroundRead() throws Exception {
-        DocumentStore docStore = new MemoryDocumentStore();
-
-        DocumentNodeStore store = builderProvider.newBuilder().setAsyncDelay(0)
-                .setDocumentStore(docStore).setClusterId(2).getNodeStore();
-        DocumentNodeStore readOnlyStore = builderProvider.newBuilder().setAsyncDelay(0)
-                .setDocumentStore(docStore).setClusterId(1).setReadOnlyMode().getNodeStore();
-
-        NodeBuilder builder = store.getRoot().builder();
-        builder.child("node");
-        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
-
-        store.runBackgroundOperations();
-
-        // at this point node must not be visible
-        assertFalse(readOnlyStore.getRoot().hasChildNode("node"));
-
-        readOnlyStore.runBackgroundOperations();
-
-        // at this point node should get visible
-        assertTrue(readOnlyStore.getRoot().hasChildNode("node"));
-    }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.oak.plugins.document.util;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.jackrabbit.oak.plugins.document.Collection;
+import org.apache.jackrabbit.oak.plugins.document.Document;
+import org.apache.jackrabbit.oak.plugins.document.DocumentMKBuilderProvider;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
+import org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ReadOnlyDocumentStoreWrapperTest {
+    @Rule
+    public DocumentMKBuilderProvider builderProvider = new DocumentMKBuilderProvider();
+
+    @Test
+    public void testPassthrough() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        final List<String> disallowedMethods = Lists.newArrayList(
+                "create", "update", "remove", "createOrUpdate", "findAndUpdate");
+        InvocationHandler handler = new InvocationHandler() {
+            @Override
+            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                String methodName = method.getName();
+
+                if (disallowedMethods.contains(methodName)) {
+                    Assert.fail(String.format("Invalid passthrough of method (%s) with params %s", method, Arrays.toString(args)));
+                }
+
+                if ("determineServerTimeDifferenceMillis".equals(methodName)) {
+                    return new Long(0);
+                } else {
+                    return null;
+                }
+            }
+        };
+        DocumentStore proxyStore = (DocumentStore)Proxy.newProxyInstance(DocumentStore.class.getClassLoader(),
+                new Class[]{DocumentStore.class},
+                handler);
+
+        DocumentStore readOnlyStore = ReadOnlyDocumentStoreWrapperFactory.getInstance(proxyStore);
+
+        Collection<? extends Document> []collections = new Collection[] {
+                Collection.CLUSTER_NODES, Collection.JOURNAL, Collection.NODES, Collection.SETTINGS
+        };
+        for (Collection collection : collections) {
+            readOnlyStore.find(collection, null);
+            readOnlyStore.find(collection, null, 0);
+
+            readOnlyStore.query(collection, null, null, 0);
+            readOnlyStore.query(collection, null, null, null, 0, 0);
+
+            boolean uoeThrown = false;
+            try {
+                readOnlyStore.remove(collection, "");
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("remove must throw UnsupportedOperationException", uoeThrown);
+
+            uoeThrown = false;
+            try {
+                readOnlyStore.remove(collection, Lists.<String>newArrayList());
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("remove must throw UnsupportedOperationException", uoeThrown);
+
+            uoeThrown = false;
+            try {
+                readOnlyStore.remove(collection, Maps.<String, Long>newHashMap());
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("remove must throw UnsupportedOperationException", uoeThrown);
+            uoeThrown = false;
+
+            try {
+                readOnlyStore.create(collection, null);
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("create must throw UnsupportedOperationException", uoeThrown);
+            uoeThrown = false;
+
+            try {
+                readOnlyStore.update(collection, null, null);
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("update must throw UnsupportedOperationException", uoeThrown);
+            uoeThrown = false;
+
+            try {
+                readOnlyStore.createOrUpdate(collection, (UpdateOp) null);
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("createOrUpdate must throw UnsupportedOperationException", uoeThrown);
+            uoeThrown = false;
+
+            try {
+                readOnlyStore.createOrUpdate(collection, Lists.<UpdateOp>newArrayList());
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("createOrUpdate must throw UnsupportedOperationException", uoeThrown);
+            uoeThrown = false;
+
+            try {
+                readOnlyStore.findAndUpdate(collection, null);
+            } catch (UnsupportedOperationException uoe) {
+                //catch uoe thrown by read only wrapper
+                uoeThrown = true;
+            }
+            assertTrue("findAndUpdate must throw UnsupportedOperationException", uoeThrown);
+
+            readOnlyStore.invalidateCache(collection, null);
+            readOnlyStore.getIfCached(collection, null);
+        }
+
+        readOnlyStore.invalidateCache();
+        readOnlyStore.invalidateCache(null);
+
+        readOnlyStore.dispose();
+        readOnlyStore.setReadWriteMode(null);
+        readOnlyStore.getCacheStats();
+        readOnlyStore.getMetadata();
+        readOnlyStore.determineServerTimeDifferenceMillis();
+    }
+
+    @Test
+    public void backgroundRead() throws Exception {
+        DocumentStore docStore = new MemoryDocumentStore();
+
+        DocumentNodeStore store = builderProvider.newBuilder().setAsyncDelay(0)
+                .setDocumentStore(docStore).setClusterId(2).getNodeStore();
+        DocumentNodeStore readOnlyStore = builderProvider.newBuilder().setAsyncDelay(0)
+                .setDocumentStore(docStore).setClusterId(1).setReadOnlyMode().getNodeStore();
+
+        NodeBuilder builder = store.getRoot().builder();
+        builder.child("node");
+        store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+        store.runBackgroundOperations();
+
+        // at this point node must not be visible
+        assertFalse(readOnlyStore.getRoot().hasChildNode("node"));
+
+        readOnlyStore.runBackgroundOperations();
+
+        // at this point node should get visible
+        assertTrue(readOnlyStore.getRoot().hasChildNode("node"));
+    }
+}