I had to run the test code on 2.3.4 many times before I got the ConcurrentModificationException. I was not able to get a org.apache.jackrabbit.core.state.ItemStateException or javax.jcr.InvalidItemStateException on that version.

While I understand that the 1.6 branch is no longer maintained, I would like to be sure that I understand correct JCR behavior. Is it a bug in 1.6.x that the org.apache.jackrabbit.core.state.ItemStateExceptions are occurring or that they are being wrapped with a javax.jcr.RepositoryException rather than a javax.jcr.InvalidItemStateException? A sample 1.6.5 full stack is:

javax.jcr.RepositoryException: Unable to update item: node /: Child node entry with id 04afd8db-6515-4997-ac4e-83f066e39f53 has been removed, but is not present in the changelog: Child node entry with id 04afd8db-6515-4997-ac4e-83f066e39f53 has been removed, but is not present in the changelog
    at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:1134)
    at org.apache.jackrabbit.core.SessionImpl.save(SessionImpl.java:915)
    at test.JackrabbitTest$1.run(JackrabbitTest.java:38)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)
Caused by: org.apache.jackrabbit.core.state.ItemStateException: Child node entry with id 04afd8db-6515-4997-ac4e-83f066e39f53 has been removed, but is not present in the changelog at org.apache.jackrabbit.core.state.SharedItemStateManager.validateModified(SharedItemStateManager.java:1383) at org.apache.jackrabbit.core.state.SharedItemStateManager.validateHierarchy(SharedItemStateManager.java:1150) at org.apache.jackrabbit.core.state.SharedItemStateManager.access$1100(SharedItemStateManager.java:116) at org.apache.jackrabbit.core.state.SharedItemStateManager$Update.begin(SharedItemStateManager.java:717) at org.apache.jackrabbit.core.state.SharedItemStateManager.beginUpdate(SharedItemStateManager.java:1473) at org.apache.jackrabbit.core.state.SharedItemStateManager.update(SharedItemStateManager.java:1503) at org.apache.jackrabbit.core.state.LocalItemStateManager.update(LocalItemStateManager.java:351) at org.apache.jackrabbit.core.state.XAItemStateManager.update(XAItemStateManager.java:354) at org.apache.jackrabbit.core.state.LocalItemStateManager.update(LocalItemStateManager.java:326) at org.apache.jackrabbit.core.state.SessionItemStateManager.update(SessionItemStateManager.java:326)
    at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:1128)
    ... 5 more
org.apache.jackrabbit.core.state.ItemStateException: Child node entry with id 04afd8db-6515-4997-ac4e-83f066e39f53 has been removed, but is not present in the changelog at org.apache.jackrabbit.core.state.SharedItemStateManager.validateModified(SharedItemStateManager.java:1383) at org.apache.jackrabbit.core.state.SharedItemStateManager.validateHierarchy(SharedItemStateManager.java:1150) at org.apache.jackrabbit.core.state.SharedItemStateManager.access$1100(SharedItemStateManager.java:116) at org.apache.jackrabbit.core.state.SharedItemStateManager$Update.begin(SharedItemStateManager.java:717) at org.apache.jackrabbit.core.state.SharedItemStateManager.beginUpdate(SharedItemStateManager.java:1473) at org.apache.jackrabbit.core.state.SharedItemStateManager.update(SharedItemStateManager.java:1503) at org.apache.jackrabbit.core.state.LocalItemStateManager.update(LocalItemStateManager.java:351) at org.apache.jackrabbit.core.state.XAItemStateManager.update(XAItemStateManager.java:354) at org.apache.jackrabbit.core.state.LocalItemStateManager.update(LocalItemStateManager.java:326) at org.apache.jackrabbit.core.state.SessionItemStateManager.update(SessionItemStateManager.java:326)
    at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:1128)
    at org.apache.jackrabbit.core.SessionImpl.save(SessionImpl.java:915)
    at test.JackrabbitTest$1.run(JackrabbitTest.java:38)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

Thanks!

On 12/22/2011 03:46 PM, Stefan Guggisberg wrote:
On Thu, Dec 22, 2011 at 8:39 PM, Mat Lowery<[email protected]>  wrote:
My understanding of concurrent modifications is that I can receive an
InvalidItemStateException if I have a stale view of the repository when my
session is saved or my transaction is committed.  However, I can get other
exceptions using the code below.  Furthermore, I thought Jackrabbit would
allow concurrent child node additions to a single node given the child node
names were unique.
correct

So I wasn't even expecting an InvalidItemStateException
for the code below.

I understand that locking can prevent the InvalidItemStateException but I'm
using transactions and committing the transaction for the sole purpose of
exposing a lock is something I'd like to avoid at this time.  I'd like to
just catch the InvalidItemStateException and alert the user with a friendly
message.

Why do I get the given exceptions for the given code?  I can supply full
stacks if necessary; for now, just the class and error message are shown.
strange. i ran your test 20 times in a row on my macbook pro (os-x
10.7, java 6)
against the current head (svn r1222443). none of the runs failed.

cheers
stefan

Jackrabbit 1.6.0:
* org.apache.jackrabbit.core.state.ItemStateException: there's already a
property state instance with id
243f6e39-7a3e-4d48-b051-9b4198a6a16b/{http://www.jcp.org/jcr/1.0}primaryType
* javax.jcr.InvalidItemStateException: Item cannot be saved because it has
been modified externally: node /
* javax.jcr.InvalidItemStateException: node /: the node cannot be saved
because it has been modified externally.

Jackrabbit 1.6.5:
* javax.jcr.InvalidItemStateException: node /: the node cannot be saved
because it has been modified externally.
* javax.jcr.InvalidItemStateException: Item cannot be saved because it has
been modified externally: node /
* org.apache.jackrabbit.core.state.ItemStateException: Child node entry with
id 04afd8db-6515-4997-ac4e-83f066e39f53 has been removed, but is not present
in the changelog

Jackrabbit 2.3.4:
* java.util.ConcurrentModificationException
    at java.util.WeakHashMap$HashIterator.nextEntry(WeakHashMap.java:762)
    at java.util.WeakHashMap$KeyIterator.next(WeakHashMap.java:795)
    at
org.apache.jackrabbit.core.cache.CacheManager.logCacheStats(CacheManager.java:164)

package test;

import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;

import org.apache.jackrabbit.core.TransientRepository;

public class JackrabbitTest {

  public static void main(final String[] args) throws Exception {
    File dir = File.createTempFile("jackrabbit-test", "");
    dir.delete();
    dir.mkdir();
    System.out.println("created temporary directory: " +
        dir.getAbsolutePath());
    dir.deleteOnExit();

    final Repository jcrRepo = new TransientRepository(dir);
    final AtomicBoolean passed = new AtomicBoolean(true);
    final AtomicInteger counter = new AtomicInteger(0);
    ExecutorService executor = Executors.newFixedThreadPool(50);
    Runnable runnable = new Runnable() {

      @Override
      public void run() {
        try {
          Session session = jcrRepo.login(
              new SimpleCredentials("admin",
                  "admin".toCharArray()));
          session.getRootNode().addNode("n" +
                  counter.getAndIncrement()); //unique name
          session.save();
          session.logout();
        } catch (RepositoryException e) {
          e.printStackTrace();
          passed.set(false);
        }
      }

    };
    System.out.println("Running threads");
    for (int i = 0; i<  500; i++) {
      executor.execute(runnable);
    }
    executor.shutdown(); //Disable new tasks from being submitted
    if (!executor.awaitTermination(120, TimeUnit.SECONDS)) {
      System.err.println("timeout");
      System.exit(1);
    }
    if (!passed.get()) {
      System.err.println("one or more threads got an exception");
      System.exit(1);
    } else {
      System.out.println("all threads ran with no exceptions");
      System.exit(0);
    }

  }

}

Reply via email to