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 to...@apache.org on 2016/12/14 10:01:16 UTC
svn commit: r1774159 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/docume...
Author: tomekr
Date: Wed Dec 14 10:01:16 2016
New Revision: 1774159
URL: http://svn.apache.org/viewvc?rev=1774159&view=rev
Log:
OAK-4069: Use read concern majority when connected to a replica set
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatus.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatusTest.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MongoConnection.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoConnectionTest.java
jackrabbit/oak/trunk/oak-parent/pom.xml
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java?rev=1774159&r1=1774158&r2=1774159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentMK.java Wed Dec 14 10:01:16 2016
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkArgument;
import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
+import static org.apache.jackrabbit.oak.plugins.document.util.MongoConnection.readConcernLevel;
import java.io.InputStream;
import java.net.UnknownHostException;
@@ -45,6 +46,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.MoreExecutors;
import com.mongodb.DB;
+import com.mongodb.ReadConcernLevel;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.cache.CacheLIRS;
@@ -79,6 +81,7 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.document.rdb.RDBOptions;
import org.apache.jackrabbit.oak.plugins.document.rdb.RDBVersionGCSupport;
import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoStatus;
import org.apache.jackrabbit.oak.plugins.document.util.RevisionsKey;
import org.apache.jackrabbit.oak.plugins.document.util.StringValue;
import org.apache.jackrabbit.oak.spi.blob.AbstractBlobStore;
@@ -544,6 +547,7 @@ public class DocumentMK {
private DocumentNodeStore nodeStore;
private DocumentStore documentStore;
private String mongoUri;
+ private MongoStatus mongoStatus;
private DiffCache diffCache;
private BlobStore blobStore;
private int clusterId = Integer.getInteger("oak.documentMK.clusterId", 0);
@@ -606,10 +610,14 @@ public class DocumentMK {
this.mongoUri = uri;
DB db = new MongoConnection(uri).getDB(name);
+ MongoStatus status = new MongoStatus(db);
if (!MongoConnection.hasWriteConcern(uri)) {
db.setWriteConcern(MongoConnection.getDefaultWriteConcern(db));
}
- setMongoDB(db, blobCacheSizeMB);
+ if (status.isMajorityReadConcernSupported() && status.isMajorityReadConcernEnabled() && !MongoConnection.hasReadConcern(uri)) {
+ db.setReadConcern(MongoConnection.getDefaultReadConcern(db));
+ }
+ setMongoDB(db, status, blobCacheSizeMB);
return this;
}
@@ -621,10 +629,29 @@ public class DocumentMK {
*/
public Builder setMongoDB(@Nonnull DB db,
int blobCacheSizeMB) {
+ return setMongoDB(db, new MongoStatus(db), blobCacheSizeMB);
+ }
+
+ private Builder setMongoDB(@Nonnull DB db,
+ MongoStatus status,
+ int blobCacheSizeMB) {
if (!MongoConnection.hasSufficientWriteConcern(db)) {
LOG.warn("Insufficient write concern: " + db.getWriteConcern()
+ " At least " + MongoConnection.getDefaultWriteConcern(db) + " is recommended.");
}
+ if (status.isMajorityReadConcernSupported() && !status.isMajorityReadConcernEnabled()) {
+ LOG.warn("The read concern should be enabled on mongod using --enableMajorityReadConcern");
+ } else if (status.isMajorityReadConcernSupported() && !MongoConnection.hasSufficientReadConcern(db)) {
+ ReadConcernLevel currentLevel = readConcernLevel(db.getReadConcern());
+ ReadConcernLevel recommendedLevel = readConcernLevel(MongoConnection.getDefaultReadConcern(db));
+ if (currentLevel == null) {
+ LOG.warn("Read concern hasn't been set. At least " + recommendedLevel + " is recommended.");
+ } else {
+ LOG.warn("Insufficient read concern: " + currentLevel + ". At least " + recommendedLevel + " is recommended.");
+ }
+ }
+
+ this.mongoStatus = status;
if (this.documentStore == null) {
this.documentStore = new MongoDocumentStore(db, this);
}
@@ -662,6 +689,16 @@ public class DocumentMK {
}
/**
+ * Returns the status of the Mongo server configured in the {@link #setMongoDB(String, String, int)} method.
+ *
+ * @return the status or null if the {@link #setMongoDB(String, String, int)} method hasn't
+ * been called.
+ */
+ public MongoStatus getMongoStatus() {
+ return mongoStatus;
+ }
+
+ /**
* Sets a {@link DataSource} to use for the RDB document and blob
* stores.
*
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=1774159&r1=1774158&r2=1774159&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 Dec 14 10:01:16 2016
@@ -34,8 +34,6 @@ import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -43,7 +41,6 @@ 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;
@@ -135,11 +132,6 @@ public class MongoDocumentStore implemen
public static final int IN_CLAUSE_BATCH_SIZE = 500;
- private static final ImmutableSet<String> SERVER_DETAIL_FIELD_NAMES
- = ImmutableSet.<String>builder()
- .add("host", "process", "connections", "repl", "storageEngine", "mem")
- .build();
-
private final DBCollection nodes;
private final DBCollection clusterNodes;
private final DBCollection settings;
@@ -233,11 +225,14 @@ public class MongoDocumentStore implemen
private boolean hasModifiedIdCompoundIndex = true;
public MongoDocumentStore(DB db, DocumentMK.Builder builder) {
- CommandResult serverStatus = db.command("serverStatus");
- String version = checkVersion(db, serverStatus);
+ MongoStatus mongoStatus = builder.getMongoStatus();
+ if (mongoStatus == null) {
+ mongoStatus = new MongoStatus(db);
+ }
+ mongoStatus.checkVersion();
metadata = ImmutableMap.<String,String>builder()
.put("type", "mongo")
- .put("version", version)
+ .put("version", mongoStatus.getVersion())
.build();
this.db = db;
@@ -295,47 +290,9 @@ public class MongoDocumentStore implemen
LOG.info("Connected to MongoDB {} with maxReplicationLagMillis {}, " +
"maxDeltaForModTimeIdxSecs {}, disableIndexHint {}, " +
"{}, serverStatus {}",
- version, maxReplicationLagMillis, maxDeltaForModTimeIdxSecs,
+ mongoStatus.getVersion(), maxReplicationLagMillis, maxDeltaForModTimeIdxSecs,
disableIndexHint, db.getWriteConcern(),
- serverDetails(serverStatus));
- }
-
- @Nonnull
- private static String checkVersion(DB db, CommandResult serverStatus) {
- String version = serverStatus.getString("version");
- if (version == null) {
- // OAK-4841: serverStatus was probably unauthorized,
- // use buildInfo command to get version
- version = db.command("buildInfo").getString("version");
- }
- Matcher m = Pattern.compile("^(\\d+)\\.(\\d+)\\..*").matcher(version);
- if (!m.matches()) {
- throw new IllegalArgumentException("Malformed MongoDB version: " + version);
- }
- int major = Integer.parseInt(m.group(1));
- int minor = Integer.parseInt(m.group(2));
- if (major > 2) {
- return version;
- }
- if (minor < 6) {
- String msg = "MongoDB version 2.6.0 or higher required. " +
- "Currently connected to a MongoDB with version: " + version;
- throw new RuntimeException(msg);
- }
-
- return version;
- }
-
- @Nonnull
- private static String serverDetails(CommandResult serverStatus) {
- Map<String, Object> details = Maps.newHashMap();
- for (String key : SERVER_DETAIL_FIELD_NAMES) {
- Object value = serverStatus.get(key);
- if (value != null) {
- details.put(key, value);
- }
- }
- return details.toString();
+ mongoStatus.getServerDetails());
}
@Override
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatus.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatus.java?rev=1774159&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatus.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatus.java Wed Dec 14 10:01:16 2016
@@ -0,0 +1,185 @@
+/*
+ * 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 com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import com.mongodb.MongoQueryException;
+import com.mongodb.ReadConcern;
+import com.mongodb.client.model.DBCollectionFindOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class MongoStatus {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MongoStatus.class);
+
+ private static final ImmutableSet<String> SERVER_DETAIL_FIELD_NAMES
+ = ImmutableSet.<String>builder()
+ .add("host", "process", "connections", "repl", "storageEngine", "mem")
+ .build();
+
+ private final DB db;
+
+ private BasicDBObject serverStatus;
+
+ private BasicDBObject buildInfo;
+
+ private String version;
+
+ private Boolean majorityReadConcernSupported;
+
+ private Boolean majorityReadConcernEnabled;
+
+ public MongoStatus(@Nonnull DB db) {
+ this.db = db;
+ }
+
+ public void checkVersion() {
+ if (!isVersion(2, 6)) {
+ String msg = "MongoDB version 2.6.0 or higher required. " +
+ "Currently connected to a MongoDB with version: " + version;
+ throw new RuntimeException(msg);
+ }
+ }
+
+ /**
+ * Check if the majority read concern is supported by this storage engine.
+ * The fact that read concern is supported doesn't it can be used - it also
+ * has to be enabled.
+ *
+ * @return true if the majority read concern is supported
+ */
+ public boolean isMajorityReadConcernSupported() {
+ if (majorityReadConcernSupported == null) {
+ BasicDBObject stat = getServerStatus();
+ if (stat.isEmpty()) {
+ LOG.debug("User doesn't have privileges to get server status; falling back to the isMajorityReadConcernEnabled()");
+ return isMajorityReadConcernEnabled();
+ } else {
+ if (stat.containsField("storageEngine")) {
+ BasicDBObject storageEngine = (BasicDBObject) stat.get("storageEngine");
+ majorityReadConcernSupported = storageEngine.getBoolean("supportsCommittedReads");
+ } else {
+ majorityReadConcernSupported = false;
+ }
+ }
+ }
+ return majorityReadConcernSupported;
+ }
+
+ /**
+ * Check if the majority read concern is enabled and can be used for queries.
+ *
+ * @return true if the majority read concern is enabled
+ */
+ public boolean isMajorityReadConcernEnabled() {
+ if (majorityReadConcernEnabled == null) {
+ // Mongo API doesn't seem to provide an option to check whether the
+ // majority read concern has been enabled, so we have to try to use
+ // it and optionally catch the exception.
+ DBCollection emptyCollection = db.getCollection("emptyCollection-" + System.currentTimeMillis());
+ DBCursor cursor = emptyCollection.find(new BasicDBObject(), new DBCollectionFindOptions().readConcern(ReadConcern.MAJORITY));
+ try {
+ cursor.hasNext();
+ majorityReadConcernEnabled = true;
+ } catch (MongoQueryException e) {
+ majorityReadConcernEnabled = false;
+ } finally {
+ cursor.close();
+ }
+ }
+ return majorityReadConcernEnabled;
+ }
+
+ @Nonnull
+ public String getServerDetails() {
+ Map<String, Object> details = Maps.newHashMap();
+ for (String key : SERVER_DETAIL_FIELD_NAMES) {
+ Object value = getServerStatus().get(key);
+ if (value != null) {
+ details.put(key, value);
+ }
+ }
+ return details.toString();
+ }
+
+ @Nonnull
+ public String getVersion() {
+ if (version == null) {
+ String v = getServerStatus().getString("version");
+ if (v == null) {
+ // OAK-4841: serverStatus was probably unauthorized,
+ // use buildInfo command to get version
+ v = getBuildInfo().getString("version");
+ }
+ version = v;
+ }
+ return version;
+ }
+
+ private boolean isVersion(int requiredMajor, int requiredMinor) {
+ String v = getVersion();
+ Matcher m = Pattern.compile("^(\\d+)\\.(\\d+)\\..*").matcher(v);
+ if (!m.matches()) {
+ throw new IllegalArgumentException("Malformed MongoDB version: " + v);
+ }
+ int major = Integer.parseInt(m.group(1));
+ int minor = Integer.parseInt(m.group(2));
+
+ if (major > requiredMajor) {
+ return true;
+ } else if (major == requiredMajor) {
+ return minor >= requiredMinor;
+ } else {
+ return false;
+ }
+ }
+
+ private BasicDBObject getServerStatus() {
+ if (serverStatus == null) {
+ serverStatus = db.command("serverStatus");
+ }
+ return serverStatus;
+ }
+
+ private BasicDBObject getBuildInfo() {
+ if (buildInfo == null) {
+ buildInfo = db.command("buildInfo");
+ }
+ return buildInfo;
+ }
+
+ // for testing purposes
+ void setVersion(String version) {
+ this.version = version;
+ }
+
+ void setServerStatus(BasicDBObject serverStatus) {
+ this.majorityReadConcernSupported = null;
+ this.serverStatus = serverStatus;
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MongoConnection.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MongoConnection.java?rev=1774159&r1=1774158&r2=1774159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MongoConnection.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/util/MongoConnection.java Wed Dec 14 10:01:16 2016
@@ -17,15 +17,19 @@
package org.apache.jackrabbit.oak.plugins.document.util;
import java.net.UnknownHostException;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableSet;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoClientURI;
+import com.mongodb.ReadConcern;
+import com.mongodb.ReadConcernLevel;
import com.mongodb.WriteConcern;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -37,6 +41,7 @@ public class MongoConnection {
private static final int DEFAULT_MAX_WAIT_TIME = (int) TimeUnit.MINUTES.toMillis(1);
private static final WriteConcern WC_UNKNOWN = new WriteConcern("unknown");
+ private static final Set<ReadConcernLevel> REPLICA_RC = ImmutableSet.of(ReadConcernLevel.MAJORITY, ReadConcernLevel.LINEARIZABLE);
private final MongoClientURI mongoURI;
private final MongoClient mongo;
@@ -133,6 +138,18 @@ public class MongoConnection {
}
/**
+ * Returns {@code true} if the given {@code uri} has a read concern set.
+ * @param uri the URI to check.
+ * @return {@code true} if the URI has a read concern set, {@code false}
+ * otherwise.
+ */
+ public static boolean hasReadConcern(@Nonnull String uri) {
+ ReadConcern rc = new MongoClientURI(checkNotNull(uri))
+ .getOptions().getReadConcern();
+ return readConcernLevel(rc) != null;
+ }
+
+ /**
* Returns the default write concern depending on MongoDB deployment.
* <ul>
* <li>{@link WriteConcern#MAJORITY}: for a MongoDB replica set</li>
@@ -153,6 +170,36 @@ public class MongoConnection {
}
/**
+ * Returns the default read concern depending on MongoDB deployment.
+ * <ul>
+ * <li>{@link ReadConcern#MAJORITY}: for a MongoDB replica set with w=majority</li>
+ * <li>{@link ReadConcern#LOCAL}: for other cases</li>
+ * </ul>
+ *
+ * @param db the connection to MongoDB.
+ * @return the default write concern to use for Oak.
+ */
+ public static ReadConcern getDefaultReadConcern(@Nonnull DB db) {
+ ReadConcern r;
+ if (checkNotNull(db).getMongo().getReplicaSetStatus() != null && isMajorityWriteConcern(db)) {
+ r = ReadConcern.MAJORITY;
+ } else {
+ r = ReadConcern.LOCAL;
+ }
+ return r;
+ }
+
+ /**
+ * Returns true if the majority write concern is used for the given DB.
+ *
+ * @param db the connection to MongoDB.
+ * @return true if the majority write concern has been configured; false otherwise
+ */
+ public static boolean isMajorityWriteConcern(@Nonnull DB db) {
+ return "majority".equals(db.getWriteConcern().getWObject());
+ }
+
+ /**
* Returns {@code true} if the default write concern on the {@code db} is
* sufficient for Oak. On a replica set Oak expects at least w=2. For
* a single MongoDB node deployment w=1 is sufficient.
@@ -181,4 +228,29 @@ public class MongoConnection {
return w >= 1;
}
}
+
+ /**
+ * Returns {@code true} if the default read concern on the {@code db} is
+ * sufficient for Oak. On a replica set Oak expects majority or linear. For
+ * a single MongoDB node deployment local is sufficient.
+ *
+ * @param db the database.
+ * @return whether the read concern is sufficient.
+ */
+ public static boolean hasSufficientReadConcern(@Nonnull DB db) {
+ ReadConcernLevel r = readConcernLevel(checkNotNull(db).getReadConcern());
+ if (db.getMongo().getReplicaSetStatus() == null) {
+ return true;
+ } else {
+ return REPLICA_RC.contains(r);
+ }
+ }
+
+ public static ReadConcernLevel readConcernLevel(ReadConcern readConcern) {
+ if (readConcern.isServerDefault()) {
+ return null;
+ } else {
+ return ReadConcernLevel.fromString(readConcern.asDocument().getString("level").getValue());
+ }
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoConnectionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoConnectionTest.java?rev=1774159&r1=1774158&r2=1774159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoConnectionTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoConnectionTest.java Wed Dec 14 10:01:16 2016
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.plugin
import com.mongodb.DB;
import com.mongodb.Mongo;
+import com.mongodb.ReadConcern;
import com.mongodb.ReplicaSetStatus;
import com.mongodb.WriteConcern;
@@ -39,6 +40,12 @@ public class MongoConnectionTest {
}
@Test
+ public void hasReadConcern() throws Exception {
+ assertFalse(MongoConnection.hasReadConcern("mongodb://localhost:27017/foo"));
+ assertTrue(MongoConnection.hasReadConcern("mongodb://localhost:27017/foo?readconcernlevel=majority"));
+ }
+
+ @Test
public void sufficientWriteConcern() throws Exception {
sufficientWriteConcernReplicaSet(WriteConcern.ACKNOWLEDGED, false);
sufficientWriteConcernReplicaSet(WriteConcern.JOURNALED, false);
@@ -65,6 +72,17 @@ public class MongoConnectionTest {
sufficientWriteConcernSingleNode(WriteConcern.UNACKNOWLEDGED, false);
}
+ @Test
+ public void sufficientReadConcern() throws Exception {
+ sufficientReadConcernReplicaSet(ReadConcern.DEFAULT, false);
+ sufficientReadConcernReplicaSet(ReadConcern.LOCAL, false);
+ sufficientReadConcernReplicaSet(ReadConcern.MAJORITY, true);
+
+ sufficientReadConcernSingleNode(ReadConcern.DEFAULT, true);
+ sufficientReadConcernSingleNode(ReadConcern.LOCAL, true);
+ sufficientReadConcernSingleNode(ReadConcern.MAJORITY, true);
+ }
+
private void sufficientWriteConcernReplicaSet(WriteConcern w,
boolean sufficient) {
sufficientWriteConcern(w, true, sufficient);
@@ -78,6 +96,29 @@ public class MongoConnectionTest {
private void sufficientWriteConcern(WriteConcern w,
boolean replicaSet,
boolean sufficient) {
+ DB db = mockDB(ReadConcern.DEFAULT, w, replicaSet);
+ assertEquals(sufficient, MongoConnection.hasSufficientWriteConcern(db));
+ }
+
+ private void sufficientReadConcernReplicaSet(ReadConcern r,
+ boolean sufficient) {
+ sufficientReadConcern(r, true, sufficient);
+ }
+
+ private void sufficientReadConcernSingleNode(ReadConcern r,
+ boolean sufficient) {
+ sufficientReadConcern(r, false, sufficient);
+ }
+ private void sufficientReadConcern(ReadConcern r,
+ boolean replicaSet,
+ boolean sufficient) {
+ DB db = mockDB(r, replicaSet ? WriteConcern.MAJORITY : WriteConcern.W1, replicaSet);
+ assertEquals(sufficient, MongoConnection.hasSufficientReadConcern(db));
+ }
+
+ private DB mockDB(ReadConcern r,
+ WriteConcern w,
+ boolean replicaSet) {
ReplicaSetStatus status;
if (replicaSet) {
status = mock(ReplicaSetStatus.class);
@@ -88,7 +129,8 @@ public class MongoConnectionTest {
Mongo mongo = mock(Mongo.class);
when(db.getMongo()).thenReturn(mongo);
when(db.getWriteConcern()).thenReturn(w);
+ when(db.getReadConcern()).thenReturn(r);
when(mongo.getReplicaSetStatus()).thenReturn(status);
- assertEquals(sufficient, MongoConnection.hasSufficientWriteConcern(db));
+ return db;
}
}
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatusTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatusTest.java?rev=1774159&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatusTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoStatusTest.java Wed Dec 14 10:01:16 2016
@@ -0,0 +1,107 @@
+/*
+ * 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 com.mongodb.BasicDBObject;
+import org.apache.jackrabbit.oak.plugins.document.MongoConnectionFactory;
+import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.apache.jackrabbit.oak.plugins.document.MongoUtils.isAvailable;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+public class MongoStatusTest {
+
+ @Rule
+ public MongoConnectionFactory connectionFactory = new MongoConnectionFactory();
+
+ private MongoStatus status;
+
+ @BeforeClass
+ public static void mongoAvailable() {
+ assumeTrue(isAvailable());
+ }
+
+ @Before
+ public void createStatus() {
+ MongoConnection c = connectionFactory.getConnection();
+ status = new MongoStatus(c.getDB());
+ }
+
+ @Test
+ public void testDetails() {
+ String details = status.getServerDetails();
+ assertNotNull(details);
+ assertFalse(details.isEmpty());
+ assertTrue(details.startsWith("{"));
+ assertTrue(details.endsWith("}"));
+ assertTrue(details.contains("host="));
+ }
+
+ @Test
+ public void testReadConcern() {
+ BasicDBObject mockServerStatus = new BasicDBObject();
+ BasicDBObject storageEngine = new BasicDBObject();
+ status.setServerStatus(mockServerStatus);
+
+ assertFalse(status.isMajorityReadConcernSupported());
+
+ mockServerStatus.put("storageEngine", storageEngine);
+ status.setServerStatus(mockServerStatus);
+ assertFalse(status.isMajorityReadConcernSupported());
+
+ storageEngine.put("supportsCommittedReads", false);
+ status.setServerStatus(mockServerStatus);
+ assertFalse(status.isMajorityReadConcernSupported());
+
+ storageEngine.put("supportsCommittedReads", true);
+ status.setServerStatus(mockServerStatus);
+ assertTrue(status.isMajorityReadConcernSupported());
+ }
+
+ @Test
+ public void testGetVersion() {
+ assertTrue(status.getVersion().matches("^\\d+\\.\\d+\\.\\d+$"));
+ }
+
+ @Test
+ public void testCheckVersionValid() {
+ for (String v : new String[] { "2.6.0", "2.7.0", "3.0.0"}) {
+ status.setVersion(v);
+ status.checkVersion();
+ }
+ }
+
+ @Test
+ public void testCheckVersionInvalid() {
+ for (String v : new String[] { "1.0.0", "2.0.0", "2.5.0"}) {
+ status.setVersion(v);
+ try {
+ status.checkVersion();
+ fail("Version " + v + " shouldn't be allowed");
+ } catch (Exception e) {
+ }
+ }
+ }
+}
Modified: jackrabbit/oak/trunk/oak-parent/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-parent/pom.xml?rev=1774159&r1=1774158&r2=1774159&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-parent/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-parent/pom.xml Wed Dec 14 10:01:16 2016
@@ -49,7 +49,7 @@
<mongo.db2>MongoMKDB2</mongo.db2>
<segment.db>SegmentMK</segment.db>
<lucene.version>4.7.1</lucene.version>
- <mongo.driver.version>3.2.2</mongo.driver.version>
+ <mongo.driver.version>3.4.0</mongo.driver.version>
<!-- Note that we're using SLF4J API version 1.7 when compiling -->
<!-- core Oak components but more recent SLF4J and Logback versions -->
<!-- when compiling and running test cases and the oak-run jar. -->