Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.jackrabbit.oak.plugins.document.memory.MemoryDocumentStore Maven / Gradle / Ivy
/*
* 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.memory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.apache.jackrabbit.oak.cache.CacheStats;
import org.apache.jackrabbit.oak.plugins.document.Collection;
import org.apache.jackrabbit.oak.plugins.document.Document;
import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
import org.apache.jackrabbit.oak.plugins.document.JournalEntry;
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.UpdateUtils;
import com.google.common.base.Splitter;
import com.mongodb.ReadPreference;
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.UpdateUtils.assertUnconditional;
import static org.apache.jackrabbit.oak.plugins.document.UpdateUtils.checkConditions;
/**
* Emulates a MongoDB store (possibly consisting of multiple shards and
* replicas).
*/
public class MemoryDocumentStore implements DocumentStore {
/**
* The 'nodes' collection.
*/
private ConcurrentSkipListMap nodes =
new ConcurrentSkipListMap();
/**
* The 'clusterNodes' collection.
*/
private ConcurrentSkipListMap clusterNodes =
new ConcurrentSkipListMap();
/**
* The 'settings' collection.
*/
private ConcurrentSkipListMap settings =
new ConcurrentSkipListMap();
/**
* The 'externalChanges' collection.
*/
private ConcurrentSkipListMap externalChanges =
new ConcurrentSkipListMap();
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private ReadPreference readPreference;
private WriteConcern writeConcern;
private Object lastReadWriteMode;
private final Map metadata;
public MemoryDocumentStore() {
metadata = ImmutableMap.builder()
.put("type", "memory")
.build();
}
@Override
public T find(Collection collection, String key, int maxCacheAge) {
return find(collection, key);
}
@Override
public T find(Collection collection, String key) {
Lock lock = rwLock.readLock();
lock.lock();
try {
ConcurrentSkipListMap map = getMap(collection);
return map.get(key);
} finally {
lock.unlock();
}
}
@Override
@Nonnull
public List query(Collection collection,
String fromKey,
String toKey,
int limit) {
return query(collection, fromKey, toKey, null, 0, limit);
}
@Override
@Nonnull
public List query(Collection collection,
String fromKey,
String toKey,
String indexedProperty,
long startValue,
int limit) {
Lock lock = rwLock.readLock();
lock.lock();
try {
ConcurrentSkipListMap map = getMap(collection);
ConcurrentNavigableMap sub = map.subMap(fromKey + "\0", toKey);
ArrayList list = new ArrayList();
for (T doc : sub.values()) {
if (indexedProperty != null) {
Object value = doc.get(indexedProperty);
if (value instanceof Boolean) {
long test = ((Boolean) value) ? 1 : 0;
if (test < startValue) {
continue;
}
} else if (value instanceof Long) {
if ((Long) value < startValue) {
continue;
}
} else if (value != null) {
throw new DocumentStoreException("unexpected type for property " + indexedProperty + ": "
+ value.getClass());
}
}
list.add(doc);
if (list.size() >= limit) {
break;
}
}
return list;
} finally {
lock.unlock();
}
}
@Override
public void remove(Collection collection, String key) {
Lock lock = rwLock.writeLock();
lock.lock();
try {
getMap(collection).remove(key);
} finally {
lock.unlock();
}
}
@Override
public void remove(Collection collection, List keys) {
for(String key : keys){
remove(collection, key);
}
}
@Override
public int remove(Collection collection,
Map> toRemove) {
int num = 0;
ConcurrentSkipListMap map = getMap(collection);
for (Map.Entry> entry : toRemove.entrySet()) {
Lock lock = rwLock.writeLock();
lock.lock();
try {
T doc = map.get(entry.getKey());
if (doc != null && checkConditions(doc, entry.getValue())) {
if (map.remove(entry.getKey()) != null) {
num++;
}
}
} finally {
lock.unlock();
}
}
return num;
}
@Override
public int remove(Collection collection,
final String indexedProperty, final long startValue, final long endValue)
throws DocumentStoreException {
ConcurrentSkipListMap map = getMap(collection);
int num = map.size();
Lock lock = rwLock.writeLock();
lock.lock();
try {
Maps.filterValues(map, new Predicate() {
@Override
public boolean apply(@Nullable T doc) {
Long modified = Utils.asLong((Number) doc.get(indexedProperty));
return startValue < modified && modified < endValue;
}
}).clear();
} finally {
lock.unlock();
}
num -= map.size();
return num;
}
@CheckForNull
@Override
public T createOrUpdate(Collection collection, UpdateOp update) {
assertUnconditional(update);
return internalCreateOrUpdate(collection, update, false);
}
@Override
public List createOrUpdate(Collection collection, List updateOps) {
List result = new ArrayList(updateOps.size());
for (UpdateOp update : updateOps) {
result.add(createOrUpdate(collection, update));
}
return result;
}
@Override
public T findAndUpdate(Collection collection, UpdateOp update) {
return internalCreateOrUpdate(collection, update, true);
}
/**
* @return a copy of this document store.
*/
@Nonnull
public MemoryDocumentStore copy() {
MemoryDocumentStore copy = new MemoryDocumentStore();
copyDocuments(Collection.NODES, copy);
copyDocuments(Collection.CLUSTER_NODES, copy);
copyDocuments(Collection.SETTINGS, copy);
copyDocuments(Collection.JOURNAL, copy);
return copy;
}
private void copyDocuments(Collection collection,
MemoryDocumentStore target) {
ConcurrentSkipListMap from = getMap(collection);
ConcurrentSkipListMap to = target.getMap(collection);
for (Map.Entry entry : from.entrySet()) {
T doc = collection.newDocument(target);
entry.getValue().deepCopy(doc);
doc.seal();
to.put(entry.getKey(), doc);
}
}
/**
* Get the in-memory map for this collection.
*
* @param collection the collection
* @return the map
*/
@SuppressWarnings("unchecked")
protected ConcurrentSkipListMap getMap(Collection collection) {
if (collection == Collection.NODES) {
return (ConcurrentSkipListMap) nodes;
} else if (collection == Collection.CLUSTER_NODES) {
return (ConcurrentSkipListMap) clusterNodes;
} else if (collection == Collection.SETTINGS) {
return (ConcurrentSkipListMap) settings;
} else if (collection == Collection.JOURNAL) {
return (ConcurrentSkipListMap) externalChanges;
} else {
throw new IllegalArgumentException(
"Unknown collection: " + collection.toString());
}
}
@CheckForNull
private T internalCreateOrUpdate(Collection collection,
UpdateOp update,
boolean checkConditions) {
ConcurrentSkipListMap map = getMap(collection);
T oldDoc;
Lock lock = rwLock.writeLock();
lock.lock();
try {
// get the node if it's there
oldDoc = map.get(update.getId());
T doc = collection.newDocument(this);
if (oldDoc == null) {
if (!update.isNew()) {
throw new DocumentStoreException("Document does not exist: " + update.getId());
}
} else {
oldDoc.deepCopy(doc);
}
if (checkConditions && !checkConditions(doc, update.getConditions())) {
return null;
}
// update the document
UpdateUtils.applyChanges(doc, update);
doc.seal();
map.put(update.getId(), doc);
return oldDoc;
} finally {
lock.unlock();
}
}
@Override
public boolean create(Collection collection,
List updateOps) {
Lock lock = rwLock.writeLock();
lock.lock();
try {
ConcurrentSkipListMap map = getMap(collection);
for (UpdateOp op : updateOps) {
if (map.containsKey(op.getId())) {
return false;
}
}
for (UpdateOp op : updateOps) {
assertUnconditional(op);
internalCreateOrUpdate(collection, op, false);
}
return true;
} finally {
lock.unlock();
}
}
@Override
public void update(Collection collection,
List keys,
UpdateOp updateOp) {
assertUnconditional(updateOp);
Lock lock = rwLock.writeLock();
lock.lock();
try {
ConcurrentSkipListMap map = getMap(collection);
for (String key : keys) {
if (!map.containsKey(key)) {
continue;
}
internalCreateOrUpdate(collection, updateOp.shallowCopy(key), true);
}
} finally {
lock.unlock();
}
}
@Override
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append("Nodes:\n");
for (String p : nodes.keySet()) {
buff.append("Path: ").append(p).append('\n');
NodeDocument doc = nodes.get(p);
for (Map.Entry entry : doc.entrySet()) {
buff.append(entry.getKey()).append('=').append(entry.getValue()).append('\n');
}
buff.append("\n");
}
return buff.toString();
}
@Override
public CacheInvalidationStats invalidateCache() {
return null;
}
@Override
public CacheInvalidationStats invalidateCache(Iterable keys) {
return null;
}
@Override
public void dispose() {
// ignore
}
@Override
public T getIfCached(Collection collection, String key) {
return find(collection, key);
}
@Override
public void invalidateCache(Collection collection, String key) {
// ignore
}
@Override
public void setReadWriteMode(String readWriteMode) {
if (readWriteMode == null || readWriteMode.equals(lastReadWriteMode)) {
return;
}
lastReadWriteMode = readWriteMode;
try {
Map 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
}
}
public ReadPreference getReadPreference() {
return readPreference;
}
public WriteConcern getWriteConcern() {
return writeConcern;
}
@Override
public Iterable getCacheStats() {
return null;
}
@Override
public Map getMetadata() {
return metadata;
}
@Override
public long determineServerTimeDifferenceMillis() {
// the MemoryDocumentStore has no delays, thus return 0
return 0;
}
}