jackrabbit-oak-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Marcel Reutegger (JIRA)" <j...@apache.org>
Subject [jira] [Commented] (OAK-1909) addNode throws InvalidItemStateException instead of ItemExistsException
Date Tue, 01 Jul 2014 08:22:24 GMT

    [ https://issues.apache.org/jira/browse/OAK-1909?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14048627#comment-14048627

Marcel Reutegger commented on OAK-1909:

I had a look at this issue in a bit more detail. I think there are two aspects:

# InvalidItemStateException vs. ItemExistsException
# Visibility of changes done by a session on another cluster node

Regarding the exception types when a node is added: I think both exceptions
are legitimate but what type of exception is thrown may be implementation

Even in a non-clustered Jackrabbit 2 setup with two concurrent sessions you may
get an InvalidItemStateException (or an ItemExistsException) depending on the
timing of the method invocation. Consider the following sequence of operations
with session s1 and s2, both from a single Jackrabbit 2 repository instance
without any content:

- s1.itemExists("/foo") -> false
- s2.itemExists("/"foo") -> false
- s1.getRootNode().addNode("foo")
- s2.getRootNode().addNode("foo")
- s1.save()
- s2.save() -> InvalidItemStateException

A slightly different sequence will result in an ItemExistsException:

- s1.itemExists("/foo") -> false
- s2.itemExists("/"foo") -> false
- s1.getRootNode().addNode("foo")
- s1.save()
- s2.getRootNode().addNode("foo") -> ItemExistsException

This is because changes become with Jackrabbit 2 changes from other sessions
are visible immediately.

The spec does say an implementation will throw an ItemExistsException either immediately
or on save, but it also says Session.save() may throw an InvalidItemStateException:

bq. InvalidItemStateException - if any of the changes to be persisted conflicts with a change
already persisted through another session and the implementation is such that this conflict
can only be detected at save-time and therefore was not detected earlier, at change-time.

Now with Oak, the behaviour is a bit different because we use MVCC and the
conflict resolution is not exactly the same. In fact with the current
implementation both examples will not throw any exceptions, even when you
run it with two sessions on different cluster nodes. Though, on a very busy system
with two MongoMK cluster nodes you may still see an InvalidItemStateException.
See also below regarding visibility of changes in a cluster.

In the first example, the slightly different conflict handling comes into play.
Oak silently merges concurrently added nodes if they do not have conflicting
properties set. When you add a simple node, this is the case and s2.save()
will not throw an exception. This even works with MongoMK with its incomplete
conflict handling.

Running the second example with Oak will also not throw an exception, because
changes from other sessions are not immediately visible. A session operates on
a snapshot of the repository. With Oak you can finally perform s2.save(), which will succeed.

Regarding visibility of changes in a clustered MongoMK setup: as mentioned 
before you may still see an InvalidItemStateException if the system is very busy
and propagation of changes across cluster nodes is slowed down.

With MongoMK changes from one cluster node are made visible to other cluster node
periodically. The default configuration is once a second. At the same time each
cluster node polls for those changes. This happens also once a second.

Looking at the above example, the save call of the second session will internally
fail with a conflict, because the node was already added to MongoDB. The MongoMK
internally detects this and enters a retry loop. The commit waits a while, performs
a rebase and then attempts to apply the changes again. Because of the wait, the
changes from the other cluster node become visible and the rebase operation together
with the conflict handling (including conflict resolution) will result in successful
save(). Again, this is not guaranteed with MongoMK because there is a limit on the
number of retries and it may happen that changes are not propagated within that time.

In any case, I think the current behaviour is more or less in line with Jackrabbit 2
and according to the specification.

> addNode throws InvalidItemStateException instead of ItemExistsException
> -----------------------------------------------------------------------
>                 Key: OAK-1909
>                 URL: https://issues.apache.org/jira/browse/OAK-1909
>             Project: Jackrabbit Oak
>          Issue Type: Bug
>          Components: mongomk
>            Reporter: Laurie byrum
> We are doing some testing with active-active on mongomk. We have some code that creates
a node and the same node can be created by multiple instances/threads/whatever. The node will
look exactly the same regardless of who creates it, and we don't care who creates it, we just
want it to exist. On mongomk, if 2 threads create the same node, we get an InvalidItemStateException.
I would have expected an ItemExistsException, based on 
> http://www.day.com/maven/jsr170/javadocs/jcr-2.0/javax/jcr/Node.html?is-external=true
> To repro, run this code in 2 threads:
> {code}
> try {
>     retBucketNode = root.addNode(name, nodeType);
>     session.save();
> } catch (final ItemExistsException e) { 
>     //…handle the failure via session.refresh(false)…
> }
> {code}
> Note that you get an InvalidItemStateException instead of the expected ItemExistsException.

This message was sent by Atlassian JIRA

View raw message