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