[
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
dependent.
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
(v6.2#6252)