Author: mreutegg
Date: Tue May 19 14:21:11 2015
New Revision: 1680301
URL: http://svn.apache.org/r1680301
Log:
OAK-2888: ArrayIndexOutOfBoundsException in UnsavedModifications.put()
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java?rev=1680301&r1=1680300&r2=1680301&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
(original)
+++
jackrabbit/oak/branches/1.0/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
Tue May 19 14:21:11 2015
@@ -70,6 +70,11 @@ class UnsavedModifications implements Cl
private final ConcurrentMap<String, Revision> map = mapFactory.create();
/**
+ * Monitor object to synchronize updates on the {@link #map}. See OAK-2888.
+ */
+ private final Object update = new Object();
+
+ /**
* Puts a revision for the given path. The revision for the given path is
* only put if there is no modification present for the revision or if the
* current modification revision is older than the passed revision.
@@ -83,20 +88,22 @@ class UnsavedModifications implements Cl
public Revision put(@Nonnull String path, @Nonnull Revision revision) {
checkNotNull(path);
checkNotNull(revision);
- for (;;) {
- Revision previous = map.get(path);
- if (previous == null) {
- if (map.putIfAbsent(path, revision) == null) {
- return null;
- }
- } else {
- if (previous.compareRevisionTime(revision) < 0) {
- if (map.replace(path, previous, revision)) {
- return previous;
+ synchronized (update) {
+ for (;;) {
+ Revision previous = map.get(path);
+ if (previous == null) {
+ if (map.putIfAbsent(path, revision) == null) {
+ return null;
}
} else {
- // revision is earlier, do not update
- return null;
+ if (previous.compareRevisionTime(revision) < 0) {
+ if (map.replace(path, previous, revision)) {
+ return previous;
+ }
+ } else {
+ // revision is earlier, do not update
+ return null;
+ }
}
}
}
@@ -212,8 +219,10 @@ class UnsavedModifications implements Cl
}
store.getDocumentStore().update(NODES, ids, updateOp);
LOG.debug("Updated _lastRev to {} on {}", lastRev, ids);
- for (String path : pathList) {
- map.remove(path, lastRev);
+ synchronized (update) {
+ for (String path : pathList) {
+ map.remove(path, lastRev);
+ }
}
pathList.clear();
updateOp = null;
Modified:
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java?rev=1680301&r1=1680300&r2=1680301&view=diff
==============================================================================
---
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
(original)
+++
jackrabbit/oak/branches/1.0/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModificationsTest.java
Tue May 19 14:21:11 2015
@@ -31,7 +31,6 @@ import org.junit.Test;
*/
public class UnsavedModificationsTest {
- @Ignore
@Test
public void concurrent() throws Exception {
final List<Exception> exceptions = Collections.synchronizedList(
@@ -96,15 +95,20 @@ public class UnsavedModificationsTest {
});
t2.start();
- while (exceptions.isEmpty()) {
+ long end = System.currentTimeMillis() + 5000;
+ while (exceptions.isEmpty() && System.currentTimeMillis() < end) {
Thread.sleep(1000);
- System.out.println("size: " + mod.getPaths().size());
}
try {
for (Exception e : exceptions) {
throw e;
}
+
+ exceptions.add(new Exception("stop"));
+ t1.join();
+ t2.join();
+
} finally {
ns.dispose();
mod.close();