Author: mreutegg
Date: Wed Sep 14 13:33:39 2016
New Revision: 1760709

URL: http://svn.apache.org/viewvc?rev=1760709&view=rev
Log:
OAK-4774: Check usage of DocumentStoreException in MongoDocumentStore

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/com/
    jackrabbit/oak/trunk/oak-core/src/test/java/com/mongodb/
    jackrabbit/oak/trunk/oak-core/src/test/java/com/mongodb/OakFongo.java   
(with props)
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoCacheConsistencyTest.java
   (with props)
Modified:
    jackrabbit/oak/trunk/oak-core/pom.xml
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java

Modified: jackrabbit/oak/trunk/oak-core/pom.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/pom.xml?rev=1760709&r1=1760708&r2=1760709&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-core/pom.xml Wed Sep 14 13:33:39 2016
@@ -352,5 +352,11 @@
       <version>1.1.1</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.github.fakemongo</groupId>
+      <artifactId>fongo</artifactId>
+      <version>2.0.6</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java?rev=1760709&r1=1760708&r2=1760709&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
 Wed Sep 14 13:33:39 2016
@@ -44,6 +44,7 @@ import javax.annotation.Nullable;
 import com.google.common.base.Stopwatch;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
 import com.google.common.util.concurrent.UncheckedExecutionException;
@@ -839,7 +840,7 @@ public class MongoDocumentStore implemen
             }
             return oldDoc;
         } catch (Exception e) {
-            throw DocumentStoreException.convert(e);
+            throw handleException(e, collection, updateOp.getId());
         } finally {
             if (lock != null) {
                 lock.unlock();
@@ -939,6 +940,14 @@ public class MongoDocumentStore implemen
                     results.put(op, oldDoc);
                 }
             }
+        } catch (MongoException e) {
+            throw handleException(e, collection, Iterables.transform(updateOps,
+                    new Function<UpdateOp, String>() {
+                @Override
+                public String apply(UpdateOp input) {
+                    return input.getId();
+                }
+            }));
         } finally {
             stats.doneCreateOrUpdate(watch.elapsed(TimeUnit.NANOSECONDS),
                     collection, Lists.transform(updateOps, new 
Function<UpdateOp, String>() {
@@ -1227,12 +1236,7 @@ public class MongoDocumentStore implemen
                     }
                 }
             } catch (MongoException e) {
-                // some documents may still have been updated
-                // invalidate all documents affected by this update call
-                for (String k : keys) {
-                    nodesCache.invalidate(k);
-                }
-                throw DocumentStoreException.convert(e);
+                throw handleException(e, collection, keys);
             }
         } finally {
             stats.doneUpdate(watch.elapsed(TimeUnit.NANOSECONDS), collection, 
keys.size());
@@ -1685,6 +1689,23 @@ public class MongoDocumentStore implemen
         }
     }
 
+    private <T extends Document> DocumentStoreException 
handleException(Exception ex,
+                                                                        
Collection<T> collection,
+                                                                        
Iterable<String> ids) {
+        if (collection == Collection.NODES) {
+            for (String id : ids) {
+                invalidateCache(collection, id);
+            }
+        }
+        return DocumentStoreException.convert(ex);
+    }
+
+    private <T extends Document> DocumentStoreException 
handleException(Exception ex,
+                                                                        
Collection<T> collection,
+                                                                        String 
id) {
+        return handleException(ex, collection, Collections.singleton(id));
+    }
+
     private static class BulkUpdateResult {
 
         private final Set<String> failedUpdates;

Added: jackrabbit/oak/trunk/oak-core/src/test/java/com/mongodb/OakFongo.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/com/mongodb/OakFongo.java?rev=1760709&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/com/mongodb/OakFongo.java 
(added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/com/mongodb/OakFongo.java Wed 
Sep 14 13:33:39 2016
@@ -0,0 +1,220 @@
+/*
+ * 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 com.mongodb;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+import com.github.fakemongo.Fongo;
+import com.mongodb.CommandResult;
+import com.mongodb.DBEncoder;
+import com.mongodb.DBObject;
+import com.mongodb.FongoDB;
+import com.mongodb.FongoDBCollection;
+import com.mongodb.InsertOptions;
+import com.mongodb.MongoException;
+import com.mongodb.ReadPreference;
+import com.mongodb.WriteConcern;
+import com.mongodb.WriteResult;
+import com.mongodb.connection.ServerVersion;
+
+public class OakFongo extends Fongo {
+
+    private final Map<String, FongoDB> dbMap;
+
+    public OakFongo(String name) throws Exception {
+        super(name);
+        this.dbMap = getDBMap();
+    }
+
+    @Override
+    public FongoDB getDB(String dbname) {
+        synchronized (dbMap) {
+            FongoDB fongoDb = dbMap.get(dbname);
+            if (fongoDb == null) {
+                try {
+                    fongoDb = new OakFongoDB(this, dbname);
+                } catch (Exception e) {
+                    throw new MongoException(e.getMessage(), e);
+                }
+                dbMap.put(dbname, fongoDb);
+            }
+            return fongoDb;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private Map<String, FongoDB> getDBMap() throws Exception {
+        Field f = Fongo.class.getDeclaredField("dbMap");
+        f.setAccessible(true);
+        return (Map<String, FongoDB>) f.get(this);
+    }
+
+    protected void beforeInsert(List<? extends DBObject> documents,
+                                InsertOptions insertOptions) {}
+
+    protected void afterInsert(WriteResult result) {}
+
+    protected void beforeFindAndModify(DBObject query,
+                                       DBObject fields,
+                                       DBObject sort,
+                                       boolean remove,
+                                       DBObject update,
+                                       boolean returnNew,
+                                       boolean upsert) {}
+
+    protected void afterFindAndModify(DBObject result) {}
+
+    protected void beforeUpdate(DBObject q,
+                                DBObject o,
+                                boolean upsert,
+                                boolean multi,
+                                WriteConcern concern,
+                                DBEncoder encoder) {}
+
+    protected void afterUpdate(WriteResult result) {}
+
+    protected void beforeRemove(DBObject query, WriteConcern writeConcern) {}
+
+    protected void afterRemove(WriteResult result) {}
+
+    protected void beforeExecuteBulkWriteOperation(boolean ordered,
+                                                   Boolean 
bypassDocumentValidation,
+                                                   List<?> writeRequests,
+                                                   WriteConcern aWriteConcern) 
{}
+
+    protected void afterExecuteBulkWriteOperation(BulkWriteResult result) {}
+    private class OakFongoDB extends FongoDB {
+
+        private final Map<String, FongoDBCollection> collMap;
+
+        public OakFongoDB(Fongo fongo, String name) throws Exception {
+            super(fongo, name);
+            this.collMap = getCollMap();
+        }
+
+        @SuppressWarnings("unchecked")
+        private Map<String, FongoDBCollection> getCollMap() throws Exception {
+            Field f = FongoDB.class.getDeclaredField("collMap");
+            f.setAccessible(true);
+            return (Map<String, FongoDBCollection>) f.get(this);
+        }
+
+        @Override
+        public CommandResult command(DBObject cmd,
+                                     ReadPreference readPreference,
+                                     DBEncoder encoder) {
+            if (cmd.containsField("serverStatus")) {
+                CommandResult commandResult = okResult();
+                commandResult.append("version", asString(getServerVersion()));
+                return commandResult;
+            } else {
+                return super.command(cmd, readPreference, encoder);
+            }
+        }
+
+        @Override
+        public synchronized FongoDBCollection doGetCollection(String name,
+                                                              boolean 
idIsNotUniq) {
+            if (name.startsWith("system.")) {
+                return super.doGetCollection(name, idIsNotUniq);
+            }
+            FongoDBCollection coll = collMap.get(name);
+            if (coll == null) {
+                coll = new OakFongoDBCollection(this, name, idIsNotUniq);
+                collMap.put(name, coll);
+            }
+            return coll;
+        }
+
+        private String asString(ServerVersion serverVersion) {
+            StringBuilder sb = new StringBuilder();
+            for (int i : serverVersion.getVersionList()) {
+                if (sb.length() != 0) {
+                    sb.append('.');
+                }
+                sb.append(String.valueOf(i));
+            }
+            return sb.toString();
+        }
+    }
+
+    private class OakFongoDBCollection extends FongoDBCollection {
+
+        public OakFongoDBCollection(FongoDB db,
+                                    String name,
+                                    boolean idIsNotUniq) {
+            super(db, name, idIsNotUniq);
+        }
+
+        @Override
+        public WriteResult insert(List<? extends DBObject> documents,
+                                               InsertOptions insertOptions) {
+            beforeInsert(documents, insertOptions);
+            WriteResult result = super.insert(documents, insertOptions);
+            afterInsert(result);
+            return result;
+        }
+
+        @Override
+        public WriteResult remove(DBObject query, WriteConcern writeConcern) {
+            beforeRemove(query, writeConcern);
+            WriteResult result = super.remove(query, writeConcern);
+            afterRemove(result);
+            return result;
+        }
+
+        @Override
+        public WriteResult update(DBObject q,
+                                  DBObject o,
+                                  boolean upsert,
+                                  boolean multi,
+                                  WriteConcern concern,
+                                  DBEncoder encoder) {
+            beforeUpdate(q, o, upsert, multi, concern, encoder);
+            WriteResult result = super.update(q, o, upsert, multi, concern, 
encoder);
+            afterUpdate(result);
+            return result;
+        }
+
+        @Override
+        public DBObject findAndModify(DBObject query,
+                                      DBObject fields,
+                                      DBObject sort,
+                                      boolean remove,
+                                      DBObject update,
+                                      boolean returnNew,
+                                      boolean upsert) {
+            beforeFindAndModify(query, fields, sort, remove, update, 
returnNew, upsert);
+            DBObject result = super.findAndModify(query, fields, sort, remove, 
update, returnNew, upsert);
+            afterFindAndModify(result);
+            return result;
+        }
+
+        @Override
+        BulkWriteResult executeBulkWriteOperation(boolean ordered,
+                                                  Boolean 
bypassDocumentValidation,
+                                                  List<WriteRequest> 
writeRequests,
+                                                  WriteConcern aWriteConcern) {
+            beforeExecuteBulkWriteOperation(ordered, bypassDocumentValidation, 
writeRequests, aWriteConcern);
+            BulkWriteResult result = super.executeBulkWriteOperation(ordered, 
bypassDocumentValidation, writeRequests, aWriteConcern);
+            afterExecuteBulkWriteOperation(result);
+            return result;
+        }
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/com/mongodb/OakFongo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoCacheConsistencyTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoCacheConsistencyTest.java?rev=1760709&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoCacheConsistencyTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoCacheConsistencyTest.java
 Wed Sep 14 13:33:39 2016
@@ -0,0 +1,112 @@
+/*
+ * 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.mongo;
+
+import java.util.List;
+
+import com.github.fakemongo.Fongo;
+import com.mongodb.BulkWriteResult;
+import com.mongodb.DBObject;
+import com.mongodb.MongoException;
+import com.mongodb.OakFongo;
+import com.mongodb.WriteConcern;
+import com.mongodb.WriteResult;
+
+import org.apache.jackrabbit.oak.plugins.document.CacheConsistencyTestBase;
+import org.apache.jackrabbit.oak.plugins.document.DocumentMK;
+import org.apache.jackrabbit.oak.plugins.document.DocumentMKBuilderProvider;
+import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.DocumentStoreFixture;
+import org.junit.Rule;
+
+public class MongoCacheConsistencyTest extends CacheConsistencyTestBase {
+
+    @Rule
+    public DocumentMKBuilderProvider provider = new 
DocumentMKBuilderProvider();
+
+    private String exceptionMsg;
+
+    @Override
+    public DocumentStoreFixture getFixture() throws Exception {
+        Fongo fongo = new OakFongo("fongo") {
+
+            private String suppressedEx = null;
+
+            @Override
+            protected void afterInsert(WriteResult result) {
+                maybeThrow();
+            }
+
+            @Override
+            protected void afterFindAndModify(DBObject result) {
+                maybeThrow();
+            }
+
+            @Override
+            protected void afterUpdate(WriteResult result) {
+                maybeThrow();
+            }
+
+            @Override
+            protected void afterRemove(WriteResult result) {
+                maybeThrow();
+            }
+
+            @Override
+            protected void beforeExecuteBulkWriteOperation(boolean ordered,
+                                                           Boolean 
bypassDocumentValidation,
+                                                           List<?> 
writeRequests,
+                                                           WriteConcern 
aWriteConcern) {
+                // suppress potentially set exception message because
+                // fongo bulk writes call other update methods
+                suppressedEx = exceptionMsg;
+                exceptionMsg = null;
+            }
+
+            @Override
+            protected void afterExecuteBulkWriteOperation(BulkWriteResult 
result) {
+                exceptionMsg = suppressedEx;
+                suppressedEx = null;
+                maybeThrow();
+            }
+
+            private void maybeThrow() {
+                if (exceptionMsg != null) {
+                    throw new MongoException(exceptionMsg);
+                }
+            }
+        };
+        DocumentMK.Builder builder = provider.newBuilder().setAsyncDelay(0);
+        final DocumentStore store = new MongoDocumentStore(fongo.getDB("oak"), 
builder);
+        return new DocumentStoreFixture() {
+            @Override
+            public String getName() {
+                return "MongoDB";
+            }
+
+            @Override
+            public DocumentStore createDocumentStore(int clusterId) {
+                return store;
+            }
+        };
+    }
+
+    @Override
+    public void setTemporaryUpdateException(String msg) {
+        this.exceptionMsg = msg;
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoCacheConsistencyTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to