jackrabbit-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Stefan Guggisberg <stefan.guggisb...@gmail.com>
Subject Re: InvalidItemStateException with concurrent threads
Date Fri, 20 Mar 2009 10:38:07 GMT
On Fri, Mar 20, 2009 at 10:36 AM, Ian Boston <ieb@tfd.co.uk> wrote:
>
> On 20 Mar 2009, at 08:41, Stefan Guggisberg wrote:
>
>> On Fri, Mar 20, 2009 at 9:05 AM, Marc Speck <marcspeck@gmail.com> wrote:
>>>
>>> It looks like you always load the same item "randomFile1". Let's say that
>>> threadA and threadB fetch randomFile1, then threadA saves the change with
>>> session.save(). When threadB wants to save, it notices that randomFile1
>>> has
>>> been changed by an other thread since it loaded it and throws an
>>> InvalidItemStateException. This is an expected behaviour of Jackrabbit.
>>
>> absolutely correct. non-conflicting concurrent node modifications are
>> merged
>> silently, the aforementioned test case however includes non-mergable
>> conflicting
>> changes (the same property is written/removed by multiple threads). for
>> more
>> information please see [1].
>
> Yes I read [1] on my search and a similar thread from Jullian in April 2008
> on the dev list (Concurrent Modifications).
>
> Unfortunately building a  hashed tree of folders results in non-mergable
> changes.
> before
> /store/ab
>
> thread1
> /store/ab/ed/8c/data.json
>
> thread2
> /store/ab/ed/8c/otherdata.json
>
> the creation of ed is a non mergable change, and I don't fancy creating the
> 255^3 nodes to avoid the problem.
>
> besides, with a multiuser system, randomness will ensure that at some point
> *every* change is potentially non-mergable. Propagating the exception to
> users will in most cases not be acceptable. (eg sorry your PhD was not
> granted because of a non-mergable change :)... this is for Higher Ed)

agreed :)

>
> What's the best approach for handling this ?
> Locking (JCR or external) ?
>    slows everything down
> Exception Recovery strategy inside the request (ie resubmit) ?
>   complex

there's a utility class in jackrabbit-jcr-commons which addresses this
issue by using jcr locks (i.e. mix:lockable nodes):
org.apache.jackrabbit.util.Locked.java

alternatively you could write your own specialized utility class.
a method like getOrCreateChildNode would handle/encapsulate the
complexity of exception recovery and retrying.

that method could also be made synchronized and
therefore avoid complex exception recovery (at the cost
of potential lock contention).

test cases specific to your environment/use case will
probably help in choosing the most efficient approach.

cheers
stefan

>
> Ian
>
>>
>>
>> cheers
>> stefan
>>
>> [1] https://issues.apache.org/jira/browse/JCR-584
>>
>>>
>>>
>>>
>>> On Fri, Mar 20, 2009 at 12:07 AM, Ian Boston
>>> <ianboston@googlemail.com>wrote:
>>>
>>>>
>>>>
>>>> If I run the test below I reliably get the following exception, any
>>>> ideas, what should I be doing that I am not.
>>>>
>>>> This is jackrabbit core 1.4.8
>>>>
>>>> (btw jcrService performs logins into the repository, that has a
>>>> BundlePersistanceManager and a ClusterNode configuration, running on
>>>> Derby. There is no TransactionManager in this test)
>>>>
>>>>
>>>>
>>>> javax.jcr.InvalidItemStateException: e13c3bca-2d00-4717-
>>>> af77-02c385b10351/{http://www.sakaiproject.org/CHS/jcr/jackrabbit/
>>>> 1.0}test has been modified externally
>>>>       at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:1251)
>>>>       at
>>>> org.apache.jackrabbit.core.SessionImpl.save(SessionImpl.java:897)
>>>>       at
>>>> org.sakaiproject.kernel.util.JcrUtilsT$1.run(JcrUtilsT.java:137)
>>>>       at java.lang.Thread.run(Thread.java:613)
>>>>
>>>>  @Test
>>>>  public void multiThreadTest() throws Exception {
>>>>   Thread[] t = new Thread[20];
>>>>   running = 0;
>>>>   for (int i = 0; i < t.length; i++) {
>>>>     t[i] = new Thread(new Runnable() {
>>>>
>>>>       public void run() {
>>>>         running++;
>>>>         Random random = new Random();
>>>>         try {
>>>>           for (int i = 0; i < 20; i++) {
>>>>             try {
>>>>               Session session = jcrService.loginSystem();
>>>>               Node node = (Node) session.getItem(randomFile1);
>>>>               try {
>>>>                 node.getProperty("sakaijcr:test").remove();
>>>>               } catch (Exception e) {
>>>>
>>>>               }
>>>>               session.save();
>>>>               Thread.yield();
>>>>               node.setProperty("sakaijcr:test", "new
>>>> value"+random.nextLong());
>>>>               session.save();
>>>>             } catch (Exception e) {
>>>>               e.printStackTrace();
>>>>             } finally {
>>>>               try {
>>>>                 jcrService.logout();
>>>>               } catch (Exception e) {
>>>>                 e.printStackTrace();
>>>>               }
>>>>             }
>>>>           }
>>>>         } finally {
>>>>           running--;
>>>>         }
>>>>       }
>>>>
>>>>     });
>>>>   }
>>>>   for (int i = 0; i < t.length; i++) {
>>>>     t[i].start();
>>>>     Thread.yield();
>>>>   }
>>>>
>>>>   while (running > 0) {
>>>>     Thread.yield();
>>>>   }
>>>>
>>>>  }
>>>>
>>>
>
>

Mime
View raw message