use of com.mongodb.ReadPreference in project jackrabbit-oak by apache.
the class MongoDocumentStore method getMongoReadPreference.
<T extends Document> ReadPreference getMongoReadPreference(@Nonnull Collection<T> collection, @Nullable String parentId, @Nullable String documentId, @Nonnull DocumentReadPreference preference) {
switch(preference) {
case PRIMARY:
return ReadPreference.primary();
case PREFER_PRIMARY:
return ReadPreference.primaryPreferred();
case PREFER_SECONDARY:
return getConfiguredReadPreference(collection);
case PREFER_SECONDARY_IF_OLD_ENOUGH:
if (collection != Collection.NODES) {
return ReadPreference.primary();
}
boolean secondarySafe;
if (fallbackSecondaryStrategy) {
// This is not quite accurate, because ancestors
// are updated in a background thread (_lastRev). We
// will need to revise this for low maxReplicationLagMillis
// values
long replicationSafeLimit = getTime() - maxReplicationLagMillis;
if (parentId == null) {
secondarySafe = false;
} else {
//If parent has been modified loooong time back then there children
//would also have not be modified. In that case we can read from secondary
NodeDocument cachedDoc = nodesCache.getIfPresent(parentId);
secondarySafe = cachedDoc != null && !cachedDoc.hasBeenModifiedSince(replicationSafeLimit);
}
} else if (localChanges != null) {
secondarySafe = true;
secondarySafe &= collection == Collection.NODES;
secondarySafe &= documentId == null || !localChanges.mayContain(documentId);
secondarySafe &= parentId == null || !localChanges.mayContainChildrenOf(parentId);
secondarySafe &= mostRecentAccessedRevisions == null || replicaInfo.isMoreRecentThan(mostRecentAccessedRevisions);
} else {
// localChanges not initialized yet
secondarySafe = false;
}
ReadPreference readPreference;
if (secondarySafe) {
readPreference = getConfiguredReadPreference(collection);
} else {
readPreference = ReadPreference.primary();
}
return readPreference;
default:
throw new IllegalArgumentException("Unsupported usage " + preference);
}
}
use of com.mongodb.ReadPreference in project jackrabbit-oak by apache.
the class ReadPreferenceIT method testMongoReadPreferences.
@Test
public void testMongoReadPreferences() throws Exception {
ReadPreference testPref = ReadPreference.secondary();
mongoDS.getDBCollection(NODES).getDB().setReadPreference(testPref);
NodeStore extNodeStore = mk2.getNodeStore();
NodeBuilder b1 = extNodeStore.getRoot().builder();
b1.child("x").child("y").setProperty("xyz", "123");
extNodeStore.merge(b1, EmptyHook.INSTANCE, CommitInfo.EMPTY);
// wait until the change is visible
NodeStore nodeStore = mk.getNodeStore();
while (true) {
if (nodeStore.getRoot().hasChildNode("x")) {
break;
} else {
Thread.sleep(100);
}
}
// the change hasn't been replicated yet, primary must be used
assertEquals(ReadPreference.primary(), mongoDS.getMongoReadPreference(NODES, null, "/x/y", DocumentReadPreference.PREFER_SECONDARY_IF_OLD_ENOUGH));
// make the secondary up-to-date
DocumentNodeState ns = (DocumentNodeState) nodeStore.getRoot().getChildNode("x").getChildNode("y");
// add revision for the local cluster node
RevisionVector lastSeenRev = ns.getLastRevision().update(new Revision(Revision.getCurrentTimestamp(), 0, 1));
primary.set(lastSeenRev);
secondary.set(lastSeenRev);
replica.updateRevisions();
// change has been replicated by now, it's fine to use secondary
assertEquals(testPref, mongoDS.getMongoReadPreference(NODES, null, "/x/y", DocumentReadPreference.PREFER_SECONDARY_IF_OLD_ENOUGH));
}
use of com.mongodb.ReadPreference in project jackrabbit-oak by apache.
the class MemoryDocumentStore method setReadWriteMode.
@Override
public void setReadWriteMode(String readWriteMode) {
if (readWriteMode == null || readWriteMode.equals(lastReadWriteMode)) {
return;
}
lastReadWriteMode = readWriteMode;
try {
Map<String, String> map = Splitter.on(", ").withKeyValueSeparator(":").split(readWriteMode);
String read = map.get("read");
if (read != null) {
ReadPreference readPref = ReadPreference.valueOf(read);
if (!readPref.equals(this.readPreference)) {
this.readPreference = readPref;
}
}
String write = map.get("write");
if (write != null) {
WriteConcern writeConcern = WriteConcern.valueOf(write);
if (!writeConcern.equals(this.writeConcern)) {
this.writeConcern = writeConcern;
}
}
} catch (Exception e) {
// unsupported or parse error - ignore
}
}
use of com.mongodb.ReadPreference in project jackrabbit-oak by apache.
the class MongoDocumentStore method findUncached.
@CheckForNull
protected <T extends Document> T findUncached(Collection<T> collection, String key, DocumentReadPreference docReadPref) {
log("findUncached", key, docReadPref);
DBCollection dbCollection = getDBCollection(collection);
final Stopwatch watch = startWatch();
boolean isSlaveOk = false;
boolean docFound = true;
try {
ReadPreference readPreference = getMongoReadPreference(collection, null, key, docReadPref);
if (readPreference.isSlaveOk()) {
LOG.trace("Routing call to secondary for fetching [{}]", key);
isSlaveOk = true;
}
DBObject obj = dbCollection.findOne(getByKeyQuery(key).get(), null, null, readPreference);
if (obj == null) {
docFound = false;
return null;
}
T doc = convertFromDBObject(collection, obj);
if (doc != null) {
doc.seal();
}
return doc;
} finally {
stats.doneFindUncached(watch.elapsed(TimeUnit.NANOSECONDS), collection, key, docFound, isSlaveOk);
}
}
use of com.mongodb.ReadPreference in project jackrabbit-oak by apache.
the class MongoDocumentStore method queryInternal.
@SuppressWarnings("unchecked")
@Nonnull
<T extends Document> List<T> queryInternal(Collection<T> collection, String fromKey, String toKey, String indexedProperty, long startValue, int limit, long maxQueryTime) {
log("query", fromKey, toKey, indexedProperty, startValue, limit);
DBCollection dbCollection = getDBCollection(collection);
QueryBuilder queryBuilder = QueryBuilder.start(Document.ID);
queryBuilder.greaterThan(fromKey);
queryBuilder.lessThan(toKey);
DBObject hint = new BasicDBObject(NodeDocument.ID, 1);
if (indexedProperty != null) {
if (NodeDocument.DELETED_ONCE.equals(indexedProperty)) {
if (startValue != 1) {
throw new DocumentStoreException("unsupported value for property " + NodeDocument.DELETED_ONCE);
}
queryBuilder.and(indexedProperty);
queryBuilder.is(true);
} else {
queryBuilder.and(indexedProperty);
queryBuilder.greaterThanEquals(startValue);
if (NodeDocument.MODIFIED_IN_SECS.equals(indexedProperty) && canUseModifiedTimeIdx(startValue)) {
hint = new BasicDBObject(NodeDocument.MODIFIED_IN_SECS, -1);
}
}
}
DBObject query = queryBuilder.get();
String parentId = Utils.getParentIdFromLowerLimit(fromKey);
long lockTime = -1;
final Stopwatch watch = startWatch();
boolean isSlaveOk = false;
int resultSize = 0;
CacheChangesTracker cacheChangesTracker = null;
if (parentId != null && collection == Collection.NODES) {
cacheChangesTracker = nodesCache.registerTracker(fromKey, toKey);
}
try {
DBCursor cursor = dbCollection.find(query).sort(BY_ID_ASC);
if (!disableIndexHint && !hasModifiedIdCompoundIndex) {
cursor.hint(hint);
}
if (maxQueryTime > 0) {
// OAK-2614: set maxTime if maxQueryTimeMS > 0
cursor.maxTime(maxQueryTime, TimeUnit.MILLISECONDS);
}
ReadPreference readPreference = getMongoReadPreference(collection, parentId, null, getDefaultReadPreference(collection));
if (readPreference.isSlaveOk()) {
isSlaveOk = true;
LOG.trace("Routing call to secondary for fetching children from [{}] to [{}]", fromKey, toKey);
}
cursor.setReadPreference(readPreference);
List<T> list;
try {
list = new ArrayList<T>();
for (int i = 0; i < limit && cursor.hasNext(); i++) {
DBObject o = cursor.next();
T doc = convertFromDBObject(collection, o);
list.add(doc);
}
resultSize = list.size();
} finally {
cursor.close();
}
if (cacheChangesTracker != null) {
nodesCache.putNonConflictingDocs(cacheChangesTracker, (List<NodeDocument>) list);
}
return list;
} finally {
if (cacheChangesTracker != null) {
cacheChangesTracker.close();
}
stats.doneQuery(watch.elapsed(TimeUnit.NANOSECONDS), collection, fromKey, toKey, indexedProperty != null, resultSize, lockTime, isSlaveOk);
}
}
Aggregations