Search code examples
multithreadinglockingcluster-computingjcrjackrabbit

JCR locking on multi clustered environment


I have been struggling to come up with a working solution when it comes to adding content to JCR nodes executed in different instances of the same cluster.

It has been explained here that "when multiple cluster nodes write to the same nodes, those nodes must be locked first".

Which i have done, but i still get stale item exceptions like below:

javax.jcr.InvalidItemStateException: Unable to update a stale item: item.save()
at org.apache.jackrabbit.core.ItemSaveOperation.perform(ItemSaveOperation.java:262)
at org.apache.jackrabbit.core.session.SessionState.perform(SessionState.java:216)
at org.apache.jackrabbit.core.ItemImpl.perform(ItemImpl.java:91)
at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:329)
at org.apache.jackrabbit.core.session.SessionSaveOperation.perform(SessionSaveOperation.java:65)
at org.apache.jackrabbit.core.session.SessionState.perform(SessionState.java:216)
at org.apache.jackrabbit.core.SessionImpl.perform(SessionImpl.java:361)
at org.apache.jackrabbit.core.SessionImpl.save(SessionImpl.java:812)

I also follow the suggested approach on how to lock nodes here, (see 17.10 Locks and Transactions)

here is simplified version of my code when it comes to lock procedures

    session.getRootNode().addNode("one").addMixin("mix:lockable");
    session.save();
    session.getWorkspace().getLockManager().lock("/one", true, true, 5000, session.getUserID());
    session.save();// usually it explodes here
    session.getNode("/one").addNode("two").addMixin("mix:lockable");
    session.save();
    session.getWorkspace().getLockManager().unlock("/one");

Please note this would be executed on two different instances (clustered) at the same time.

As you can see in my code above it explodes after i attempt to save the lock which was just added to the node, however this is recommendation that is stated in the link i shared earlier. I understand why it explodes, this is because two instances were trying to add lock on the same node. When a lock is added to a node it modifies the node by adding two properties (jcr:lockOwner and jcr:lockIsDeep), so if instance 1 added lock then instance 2 added lock, and instance1 attempted to save then you get stale item, because instance 2 modified the node by adding a lock to it... so how would i prevent this from happening?

Many thanks for your support!


Solution

  • I somehow found this topic and have checked your code, what do you wrong here is that you are obtaining a session based lock therefore your clustered repositories has not idea of the lock since its not applied to clustered node.

    What you should have done instead is to do the following:

    session.getWorkspace().getLockManager().lock("/one", true, false, 5000, session.getUserID());
    

    More information can be found at: https://wiki.apache.org/jackrabbit/Clustering#Concurrent_Write_Behavior Especially under limitations column.