Author: mreutegg
Date: Mon Mar 3 10:43:53 2014
New Revision: 1573517
URL: http://svn.apache.org/r1573517
Log:
OAK-1406: Background operations block writes
- better decouple background write from local commits
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java?rev=1573517&r1=1573516&r2=1573517&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/Commit.java
Mon Mar 3 10:43:53 2014
@@ -117,17 +117,6 @@ public class Commit {
diff.newline();
}
- /**
- * Update the "lastRev" and "modified" properties for the specified node
- * document.
- *
- * @param path the path
- */
- public void touchNode(String path) {
- UpdateOp op = getUpdateOperationForNode(path);
- NodeDocument.setLastRev(op, revision);
- }
-
void updateProperty(String path, String propertyName, String value) {
UpdateOp op = getUpdateOperationForNode(path);
String key = Utils.escapePropertyName(propertyName);
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1573517&r1=1573516&r2=1573517&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
Mon Mar 3 10:43:53 2014
@@ -1381,17 +1381,7 @@ public final class DocumentNodeStore
}
void backgroundWrite() {
- if (unsavedLastRevisions.getPaths().isEmpty()) {
- return;
- }
- // write back the pending _lastRevs with an exclusive lock to
- // ensure consistency
- backgroundOperationLock.writeLock().lock();
- try {
- unsavedLastRevisions.persist(this);
- } finally {
- backgroundOperationLock.writeLock().unlock();
- }
+ unsavedLastRevisions.persist(this,
backgroundOperationLock.writeLock());
}
//-----------------------------< internal
>---------------------------------
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java?rev=1573517&r1=1573516&r2=1573517&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
Mon Mar 3 10:43:53 2014
@@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Lock;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -31,6 +32,7 @@ import org.apache.jackrabbit.oak.plugins
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
@@ -135,17 +137,30 @@ class UnsavedModifications {
/**
* Persist the pending changes to _lastRev to the given store. This method
- * does not guarantee consistency when there are concurrent updates on
- * this instance through {@link #put(String, Revision)}. The caller must
- * use proper synchronization to ensure no paths are added while this
method
- * is called.
+ * will persist a snapshot of the pending revisions by acquiring the passed
+ * lock for a short period of time.
*
* @param store the document node store.
+ * @param lock the lock to acquire to get a consistent snapshot of the
+ * revisions to write back.
*/
- public void persist(@Nonnull DocumentNodeStore store) {
+ public void persist(@Nonnull DocumentNodeStore store,
+ @Nonnull Lock lock) {
+ if (map.isEmpty()) {
+ return;
+ }
checkNotNull(store);
+ checkNotNull(lock);
- ArrayList<String> paths = new ArrayList<String>(getPaths());
+ // get a copy of the map while holding the lock
+ lock.lock();
+ Map<String, Revision> pending;
+ try {
+ pending = Maps.newHashMap(map);
+ } finally {
+ lock.unlock();
+ }
+ ArrayList<String> paths = new ArrayList<String>(pending.keySet());
// sort by depth (high depth first), then path
Collections.sort(paths, PathComparator.INSTANCE);
@@ -154,7 +169,7 @@ class UnsavedModifications {
List<String> ids = new ArrayList<String>();
for (int i = 0; i < paths.size(); ) {
String p = paths.get(i);
- Revision r = map.get(p);
+ Revision r = pending.get(p);
if (r == null) {
i++;
continue;
@@ -163,8 +178,8 @@ class UnsavedModifications {
if (updateOp == null) {
// create UpdateOp
Commit commit = new Commit(store, null, r);
- commit.touchNode(p);
updateOp = commit.getUpdateOperationForNode(p);
+ NodeDocument.setLastRev(updateOp, r);
lastRev = r;
ids.add(Utils.getIdFromPath(p));
i++;
@@ -183,7 +198,7 @@ class UnsavedModifications {
|| ids.size() >= BACKGROUND_MULTI_UPDATE_LIMIT) {
store.getDocumentStore().update(NODES, ids, updateOp);
for (String id : ids) {
- map.remove(Utils.getPathFromId(id));
+ map.remove(Utils.getPathFromId(id), lastRev);
}
ids.clear();
updateOp = null;
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=1573517&r1=1573516&r2=1573517&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
Mon Mar 3 10:43:53 2014
@@ -420,6 +420,9 @@ public class MongoDocumentStore implemen
}
T oldDoc = convertFromDBObject(collection, oldNode);
applyToCache(collection, oldDoc, updateOp);
+ if (oldDoc != null) {
+ oldDoc.seal();
+ }
return oldDoc;
} catch (Exception e) {
throw new MicroKernelException(e);
@@ -686,12 +689,19 @@ public class MongoDocumentStore implemen
@Nonnull UpdateOp updateOp)
{
// cache the new document
if (collection == Collection.NODES) {
+ CacheValue key = new StringValue(updateOp.getId());
NodeDocument newDoc = (NodeDocument) collection.newDocument(this);
if (oldDoc != null) {
+ // we can only update the cache based on the oldDoc if we
+ // still have the oldDoc in the cache, otherwise we may
+ // update the cache with an outdated document
+ NodeDocument cached = nodesCache.getIfPresent(key);
+ if (cached == null) {
+ // cannot use oldDoc to update cache
+ return;
+ }
oldDoc.deepCopy(newDoc);
- oldDoc.seal();
}
- CacheValue key = new StringValue(updateOp.getId());
UpdateUtils.applyChanges(newDoc, updateOp, comparator);
newDoc.seal();