Re: Concurrent modifications

2008-05-18 Thread Julian Reschke

OK,

I saw no feedback on this.

Unless there are some immediate objections, I'll thus open a ticket 
against JCR2SPI inability to pass the Session.refresh() call down to the 
SPI layer.


BR, Julian


Julian Reschke wrote:

OK,

sorry for getting back to this discussion late.

I modified the test case so that the InvalidItemStateException indeed 
occurs with jackrabbit-core (see attachment).


I think we have consensus that JSR-170 doesn't require a store to behave 
like that; it's truly optional.


Now, with the same test and with jcr2spi (connecting to jackrabbit-core 
through spi2jcr) the InvalidItemStateException is *not* thrown.


This doesn't come as a surprise, because -- as far as I understand -- 
JCR2SPI lacks the necessary information to do so.


It seems to me that the SPI APIshould *allow* stores to expose the same 
behaviour as jackrabbit-core, and the simplest way to achieve that would 
(IMHO) be to allow the SPI implementation to keep state. (*)


Feedback appreciated,

Julian

(*) Right now, when it does keep state, we see TCK failures, as JCR's 
refresh() method is not delegated to the SPI SessionInfo. I think we 
need to fix that.









Re: Concurrent modifications

2008-05-05 Thread Julian Reschke

OK,

sorry for getting back to this discussion late.

I modified the test case so that the InvalidItemStateException indeed 
occurs with jackrabbit-core (see attachment).


I think we have consensus that JSR-170 doesn't require a store to behave 
like that; it's truly optional.


Now, with the same test and with jcr2spi (connecting to jackrabbit-core 
through spi2jcr) the InvalidItemStateException is *not* thrown.


This doesn't come as a surprise, because -- as far as I understand -- 
JCR2SPI lacks the necessary information to do so.


It seems to me that the SPI APIshould *allow* stores to expose the same 
behaviour as jackrabbit-core, and the simplest way to achieve that would 
(IMHO) be to allow the SPI implementation to keep state. (*)


Feedback appreciated,

Julian

(*) Right now, when it does keep state, we see TCK failures, as JCR's 
refresh() method is not delegated to the SPI SessionInfo. I think we 
need to fix that.




/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jackrabbit.benchmark;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;

import javax.jcr.InvalidItemStateException;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.jackrabbit.test.AbstractJCRTest;

public class ConcurrentUpdateTest extends AbstractJCRTest {

  public void testoverlappingUpdate() throws RepositoryException, 
UnsupportedEncodingException {

String testcontent = "base version";

Session session1 = testRootNode.getSession();
Session session2 = helper.getReadWriteSession();

assertTrue(session1 != session2);

// create the test node

Node testnode = testRootNode.addNode("testconcurrent", "nt:file");
String testnodepath = testnode.getPath();
Node testnodec = testnode.addNode("jcr:content", "nt:resource");
testnodec.setProperty("jcr:data", new 
ByteArrayInputStream(testcontent.getBytes("UTF-8")));
testnodec.setProperty("jcr:lastModified", Calendar.getInstance());
testnodec.setProperty("jcr:mimeType", "text/plain");
session1.save();
session1.refresh(false);

// retrieve it through both sessions

Node n1 = (Node)session1.getItem(testnodepath);
Node c1 = n1.getNode("jcr:content");
Property d1 = c1.getProperty("jcr:data");
assertEquals(testcontent, d1.getString());

Node n2 = (Node)session2.getItem(testnodepath);
Node c2 = n2.getNode("jcr:content");
Property d2 = c2.getProperty("jcr:data");
assertEquals(testcontent, d2.getString());

// modify through session1

c1.setProperty("jcr:data", testcontent + ", as modified by session 1");

// modify persisted property through session 2
c2.setProperty("jcr:data", testcontent + ", as modified by session 2");
n2.save();

// now try to save session 1... should fail
try {
n1.save(); 
fail("expected InvalidItemStateException");
}
catch (InvalidItemStateException expected) {
//
}
  }

}


Re: Concurrent modifications

2008-04-24 Thread David Nuescheler
>  Yes, that is correct -- this is not about JCR compliance, but about what we
> expect *Jackrabbit* to do.
ah i see... ok, my expectation would be that jackrabbit does not throw ;)

regards,
david

-- 
Visit: http://dev.day.com/ - Day JCR Cup 08 - Win a MacBook Pro


Re: Concurrent modifications

2008-04-24 Thread Julian Reschke

David Nuescheler wrote:

 I indeed get the expected exception, but not for

  n1.getProp
  n2.getProp

  n1.setProp
  n1.save

  n2.setProp
  n2.save

 ...which I hoped for.


i think it would be totally legitimate for a content repository to either
throw or not... personally, i would not support a test case in the tck
that test for either behavior.


Yes, that is correct -- this is not about JCR compliance, but about what 
we expect *Jackrabbit* to do.


BR, Julian


Re: Concurrent modifications

2008-04-24 Thread David Nuescheler
>  I indeed get the expected exception, but not for
>
>   n1.getProp
>   n2.getProp
>
>   n1.setProp
>   n1.save
>
>   n2.setProp
>   n2.save
>
>  ...which I hoped for.

i think it would be totally legitimate for a content repository to either
throw or not... personally, i would not support a test case in the tck
that test for either behavior.

regards,
david

-- 
Visit: http://dev.day.com/ - Day JCR Cup 08 - Win a MacBook Pro


Re: Concurrent modifications

2008-04-23 Thread Julian Reschke

Jukka Zitting wrote:

Hi,

On Wed, Apr 23, 2008 at 3:31 PM, Julian Reschke <[EMAIL PROTECTED]> wrote:

 See attached test case -- which passes over here.
 [...]
Session session1 = testRootNode.getSession();
Session session2 = super.superuser;


These are the same session.

> ...

Oh well.

So, yes, for

  n1.setProp
  n2.setProp
  n2.save
  n1.save

I indeed get the expected exception, but not for

  n1.getProp
  n2.getProp

  n1.setProp
  n1.save

  n2.setProp
  n2.save

...which I hoped for.

BR, Julian



Re: Concurrent modifications

2008-04-23 Thread Jukka Zitting
Hi,

On Wed, Apr 23, 2008 at 3:31 PM, Julian Reschke <[EMAIL PROTECTED]> wrote:
>  See attached test case -- which passes over here.
>  [...]
> Session session1 = testRootNode.getSession();
> Session session2 = super.superuser;

These are the same session.

BR,

Jukka Zitting


Re: Concurrent modifications

2008-04-23 Thread Julian Reschke

Stefan Guggisberg wrote:

 According to Julian, it does not throw an exception for him. Which is a
bug.


it does throw an exception in my case.


See attached test case -- which passes over here.

Maybe it depends on config/pm settings/whatever?

BR, Julian
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jackrabbit.benchmark;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;

import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.jackrabbit.test.AbstractJCRTest;

public class ConcurrentUpdateTest extends AbstractJCRTest {

  public void testoverlappingUpdate() throws RepositoryException, 
UnsupportedEncodingException {

String testcontent = "base version";

Session session1 = testRootNode.getSession();
Session session2 = super.superuser;

// create the test node

Node testnode = testRootNode.addNode("testconcurrent", "nt:file");
String testnodepath = testnode.getPath();
Node testnodec = testnode.addNode("jcr:content", "nt:resource");
testnodec.setProperty("jcr:data", new 
ByteArrayInputStream(testcontent.getBytes("UTF-8")));
testnodec.setProperty("jcr:lastModified", Calendar.getInstance());
testnodec.setProperty("jcr:mimeType", "text/plain");
session1.save();
session1.refresh(false);

// retrieve it through both sessions

Node n1 = (Node)session1.getItem(testnodepath);
Node c1 = n1.getNode("jcr:content");
Property d1 = c1.getProperty("jcr:data");
assertEquals(testcontent, d1.getString());

Node n2 = (Node)session2.getItem(testnodepath);
Node c2 = n2.getNode("jcr:content");
Property d2 = c2.getProperty("jcr:data");
assertEquals(testcontent, d2.getString());

// modify through session1

c1.setProperty("jcr:data", testcontent + ", as modified by session 1");

// modify persisted property through session 2
c2.setProperty("jcr:data", testcontent + ", as modified by session 2");
n2.save();

// now try to save session 1... should fail
n1.save(); 
  }

}


Re: Concurrent modifications

2008-04-23 Thread Thomas Mueller
Hi,

I have had similar problems recently. I have now a test case:

public static void main(String[] args) throws Exception {
Repository repository = new TransientRepository();
Session s1 = repository.login(new SimpleCredentials("", new char[0]));
Session s2 = repository.login(new SimpleCredentials("", new char[0]));
s1.getRootNode().setProperty("b", "0"); // init with zero
s1.getRootNode().setProperty("b", (String) null); // delete
s1.save();
s1.getRootNode().setProperty("b", "1");
s2.getRootNode().setProperty("b", "2");
s1.save();
s2.save();
System.out.println("Success");
s1.logout();
s2.logout();
System.out.println("End");
}

As is, the code prints "Success" "End" for me.
If the line marked "... // delete" is commented out, it fails with the
exception

javax.jcr.InvalidItemStateException:
cafebabe-cafe-babe-cafe-babecafebabe/{}b: the item cannot be saved
because it has been modified externally.
at 
org.apache.jackrabbit.core.ItemImpl.getTransientStates(ItemImpl.java:246)
at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:928)
at org.apache.jackrabbit.core.SessionImpl.save(SessionImpl.java:849)
at Test.main(Test.java:33)
Exception in thread "main"

It's a bit strange that it works in one case but not the other.

The second problem is that the application doesn't exit (some threads
are still running). Is this the expected behavior? If not I will log a
bug about that.

Regards,
Thomas

On Wed, Apr 23, 2008 at 2:11 PM, Jukka Zitting <[EMAIL PROTECTED]> wrote:
> Hi,
>
>
>  On Wed, Apr 23, 2008 at 3:06 PM, Julian Reschke <[EMAIL PROTECTED]> wrote:
>  > So, to make this useful, a client would need to re-read the property value
>  > before, checking it's still the same as earlier on? Is that the proposal?
>
>  Re-reading won't help as another session could still make changes
>  before the save.
>
>  My suggestion is that the client should use an explicit lock if it
>  needs such synchronization.
>
>  BR,
>
>  Jukka Zitting
>


Re: Concurrent modifications

2008-04-23 Thread Stefan Guggisberg
On Wed, Apr 23, 2008 at 2:09 PM, Alexander Klimetschek <[EMAIL PROTECTED]> 
wrote:
>
>  Am 23.04.2008 um 13:49 schrieb Jukka Zitting:
>
>
> >
> > > @All: Is this a bug? Are there any test cases? WDYT?
> > >
> >
> > No, it's a feature. See ConcurrentNodeModificationTest. See my previous
> message.
> >
>
>  I don't mean his original example (where the the modifications and saves
> are not "interleaved"). I meant the second one, which Stefan and me pointed
> out:
>
>   n1.getNode("jcr:content").setProperty("jcr:data", testcontent + ", as
> modified by session 1");
>
>   n2.getNode("jcr:content").setProperty("jcr:data", testcontent + ", as
> modified by session 2");
>   n2.save();
>   n1.save();
>
>  According to Julian, it does not throw an exception for him. Which is a
> bug.

it does throw an exception in my case.

cheers
stefan

>
>
>
>  Alex
>
>  --
>  Alexander Klimetschek
>  [EMAIL PROTECTED]
>
>  >> Day JCR Cup 08 | Win a MacBook Pro: http://dev.day.com/ <<
>
>
>
>
>


Re: Concurrent modifications

2008-04-23 Thread Jukka Zitting
Hi,

On Wed, Apr 23, 2008 at 3:06 PM, Julian Reschke <[EMAIL PROTECTED]> wrote:
> So, to make this useful, a client would need to re-read the property value
> before, checking it's still the same as earlier on? Is that the proposal?

Re-reading won't help as another session could still make changes
before the save.

My suggestion is that the client should use an explicit lock if it
needs such synchronization.

BR,

Jukka Zitting


Re: Concurrent modifications

2008-04-23 Thread Alexander Klimetschek


Am 23.04.2008 um 13:49 schrieb Jukka Zitting:

@All: Is this a bug? Are there any test cases? WDYT?


No, it's a feature. See ConcurrentNodeModificationTest. See my  
previous message.


I don't mean his original example (where the the modifications and  
saves are not "interleaved"). I meant the second one, which Stefan and  
me pointed out:


  n1.getNode("jcr:content").setProperty("jcr:data", testcontent + ",  
as modified by session 1");
  n2.getNode("jcr:content").setProperty("jcr:data", testcontent + ",  
as modified by session 2");

  n2.save();
  n1.save();

According to Julian, it does not throw an exception for him. Which is  
a bug.


Alex

--
Alexander Klimetschek
[EMAIL PROTECTED]

>> Day JCR Cup 08 | Win a MacBook Pro: http://dev.day.com/ <<






Re: Concurrent modifications

2008-04-23 Thread Jukka Zitting
Hi,

On Wed, Apr 23, 2008 at 2:49 PM, Stefan Guggisberg
<[EMAIL PROTECTED]> wrote:
>  the following code will trigger the InvalidItemStateException:
>
>  n1.getNode("jcr:content").setProperty("jcr:data", testcontent +
>  ", session 1");
>
>  n2.getNode("jcr:content").setProperty("jcr:data", testcontent +
>  ", session 2");
>  n2.save();
>  n1.save();

I would argue that it shouldn't throw the exception. IMHO the only
time setProperty() should throw an exception is if another session has
removed the parent node.

BR,

Jukka Zitting


Re: Concurrent modifications

2008-04-23 Thread Julian Reschke

Stefan Guggisberg wrote:

no. it's a feature ;)  in your case session2 modifies the property
*after* session1
saved the change, i.e. session2 is already aware of the new value.


Well.

Session 2 retrieved the old value, and this is what the client currently 
has (such as in an edit window).



in jackrabbit changes made by one session are instantly visible
to all other sessions as soon as they're saved (i.e. committed if
transactions are supported).


I guess the important difference here is between "is visible in the 
other session" and "the client has seen the change".


So, to make this useful, a client would need to re-read the property 
value before, checking it's still the same as earlier on? Is that the 
proposal?


In which case I'd argue we really need Binary.getEntityTag to make this 
efficient.



...


BR, Julian


Re: Concurrent modifications

2008-04-23 Thread Jukka Zitting
Hi,

On Wed, Apr 23, 2008 at 2:45 PM, Alexander Klimetschek <[EMAIL PROTECTED]> 
wrote:
> @All: Is this a bug? Are there any test cases? WDYT?

No, it's a feature. See ConcurrentNodeModificationTest. See my previous message.

BR,

Jukka Zitting


Re: Concurrent modifications

2008-04-23 Thread Stefan Guggisberg
hi julian

On Tue, Apr 22, 2008 at 7:04 PM, Julian Reschke <[EMAIL PROTECTED]> wrote:
> Hi,
>
>  I was expecting that Jackrabbit is detecting concurrent modifications to a
> node, and reject them with an InvalidItemStateException.

yes, it should (and AFAIK it does ;).

>
>  However, this test:
>
>   public void testoverlappingUpdate() throws RepositoryException,
> UnsupportedEncodingException {
>
> String testcontent = "base version";
>
> Session session1 = testRootNode.getSession();
> Session session2 = super.superuser;
>
> // create the test node
>
> Node testnode = testRootNode.addNode("testconcurrent", "nt:file");
> String testnodepath = testnode.getPath();
> Node testnodec = testnode.addNode("jcr:content", "nt:resource");
> testnodec.setProperty("jcr:data", new
> ByteArrayInputStream(testcontent.getBytes("UTF-8")));
> testnodec.setProperty("jcr:lastModified", Calendar.getInstance());
> testnodec.setProperty("jcr:mimeType", "text/plain");
> session1.save();
> session1.refresh(false);
>
> // retrieve it through both sessions
>
> Node n1 = (Node)session1.getItem(testnodepath);
> assertEquals(testcontent,
> n1.getProperty("jcr:content/jcr:data").getString());
>
> Node n2 = (Node)session2.getItem(testnodepath);
> assertEquals(testcontent,
> n2.getProperty("jcr:content/jcr:data").getString());
>
> // modify through session1
>
> n1.getNode("jcr:content").setProperty("jcr:data", testcontent + ", as
> modified by session 1");
> n1.save();
>
> // modify through session2
>
> n2.getNode("jcr:content").setProperty("jcr:data", testcontent + ", as
> modified by session 2");
> n2.save();
>   }
>
>  Is this a regression?

no. it's a feature ;)  in your case session2 modifies the property
*after* session1
saved the change, i.e. session2 is already aware of the new value.

in jackrabbit changes made by one session are instantly visible
to all other sessions as soon as they're saved (i.e. committed if
transactions are supported).

the following code will trigger the InvalidItemStateException:

 n1.getNode("jcr:content").setProperty("jcr:data", testcontent +
", session 1");
 n2.getNode("jcr:content").setProperty("jcr:data", testcontent +
", session 2");
 n2.save();
 n1.save();

cheers
stefan

>
>  BR, Julian
>
>  (I'm aware that detecting this is optional, but my understanding was that
> the RI was doing this at some point of time...)
>


Re: Concurrent modifications

2008-04-23 Thread Jukka Zitting
Hi,

On Wed, Apr 23, 2008 at 2:23 PM, Julian Reschke <[EMAIL PROTECTED]> wrote:
> Well, the normal update cycle is *getting* the content, modifying it, then
> writing it back. To be useful, that's the sequence of operations that needs
> to be supported, right?

Yes, and we of course support that. What's debatable though is whether
and how Jackrabbit should implement database-like isolation levels or
if it's OK for reads and writes from multiple sessions to be
interleaved.

Personally I'd prefer if Jackrabbit did *not* throw exceptions on such
write conflicts, and instead automatically merged the changes from
multiple sessions. If a client wants or needs better isolation levels,
it should use JCR locks or some other explicit synchronization
mechanism.

BR,

Jukka Zitting


Re: Concurrent modifications

2008-04-23 Thread Alexander Klimetschek


Am 23.04.2008 um 13:23 schrieb Julian Reschke:
Well, the normal update cycle is *getting* the content, modifying  
it, then writing it back. To be useful, that's the sequence of  
operations that needs to be supported, right?


Yes, from the user point of view. But the Jackrabbit implementation is  
copy-on-write, so technically the transient space is "touched" in the  
modifying-it step.



I've tried it, and it doesn't seem to make a difference.


Well, at least some consistency here ;-)

Another reason might be that you are using a binary property  
("jcr:data"). These are handled differently inside Jackrabbit  
because they tend to be large and are stored in the DataStore for  
example. (Although this should only apply for larger ones...).  
Maybe you could try to test with a simple DOUBLE property instead.


I can try that, but believe me, that wasn't the goal of this exercise.


Would be cool if you could try that too.


Shouldn't we have test cases for this kind of stuff???


True! Your code is a good test case. (Binary and double etc.  
properties should probably tested separately)


@All: Is this a bug? Are there any test cases? WDYT?

Alex

--
Alexander Klimetschek
[EMAIL PROTECTED]

>> Day JCR Cup 08 | Win a MacBook Pro: http://dev.day.com/ <<






Re: Concurrent modifications

2008-04-23 Thread Julian Reschke

Alexander Klimetschek wrote:


Am 22.04.2008 um 20:17 schrieb Julian Reschke:
I think it's correct. The property 
"testconcurrent/jcr:content/jcr:data" in session 2 is never put into 
the transient space *before* session 1 saves. It is fetched for the 
first time when you modify it. That you


Actually, it *is* fetched before (in the assertEquals).


Yes, but it is fetched for read only.

What I actually meant is fetched *and* modified, but not yet saved. This 
is the way something goes into the transient space - at least in 
Jackrabbit's implementation. AFAIK.


Well, the normal update cycle is *getting* the content, modifying it, 
then writing it back. To be useful, that's the sequence of operations 
that needs to be supported, right?


Changing the test as suggested doesn't affect the result; still no 
exception.



Ok, this comes as a surprise. Maybe it's different when you actually get 
the Node and its Property as object? Like this:


  // modify property in session 1's transient space
  Node content = n1.getNode("jcr:content");
  Property prop = content.getProperty("jcr:data");
  prop.setValue(testcontent + ", as modified by session 1");

  // modify persisted property through session 2
  n2.getNode("jcr:content").setProperty("jcr:data", testcontent + ", as 
modified by session 2");

  n2.save();

  // now try to save session 1... should fail
  n1.save();

But this would be quite awkward.


It would.

I've tried it, and it doesn't seem to make a difference.

Another reason might be that you are using a binary property 
("jcr:data"). These are handled differently inside Jackrabbit because 
they tend to be large and are stored in the DataStore for example. 
(Although this should only apply for larger ones...). Maybe you could 
try to test with a simple DOUBLE property instead.


I can try that, but believe me, that wasn't the goal of this exercise.

Wild guess: maybe something was broken when 
 was addressed?


Shouldn't we have test cases for this kind of stuff???

BR, Julian


Re: Concurrent modifications

2008-04-22 Thread Alexander Klimetschek


Am 22.04.2008 um 20:17 schrieb Julian Reschke:
I think it's correct. The property "testconcurrent/jcr:content/ 
jcr:data" in session 2 is never put into the transient space  
*before* session 1 saves. It is fetched for the first time when you  
modify it. That you


Actually, it *is* fetched before (in the assertEquals).


Yes, but it is fetched for read only.

What I actually meant is fetched *and* modified, but not yet saved.  
This is the way something goes into the transient space - at least in  
Jackrabbit's implementation. AFAIK.


Changing the test as suggested doesn't affect the result; still no  
exception.



Ok, this comes as a surprise. Maybe it's different when you actually  
get the Node and its Property as object? Like this:


  // modify property in session 1's transient space
  Node content = n1.getNode("jcr:content");
  Property prop = content.getProperty("jcr:data");
  prop.setValue(testcontent + ", as modified by session 1");

  // modify persisted property through session 2
  n2.getNode("jcr:content").setProperty("jcr:data", testcontent + ",  
as modified by session 2");

  n2.save();

  // now try to save session 1... should fail
  n1.save();

But this would be quite awkward.

Another reason might be that you are using a binary property  
("jcr:data"). These are handled differently inside Jackrabbit because  
they tend to be large and are stored in the DataStore for example.  
(Although this should only apply for larger ones...). Maybe you could  
try to test with a simple DOUBLE property instead.


Alex

--
Alexander Klimetschek
[EMAIL PROTECTED]

>> Day JCR Cup 08 | Win a MacBook Pro: http://dev.day.com/ <<






Re: Concurrent modifications

2008-04-22 Thread Julian Reschke

Alexander Klimetschek wrote:

Hi Julian!
I think it's correct. The property "testconcurrent/jcr:content/jcr:data" 
in session 2 is never put into the transient space *before* session 1 
saves. It is fetched for the first time when you modify it. That you 


Actually, it *is* fetched before (in the assertEquals).

have done it above while creating the properties for the first time is 
irrelevant, since you did a save() then, which took those properties 
"out" of the transient space again.


IIUC this is an example of the "copy-on-write" style that Jackrabbit 
implements. See "7.1.3.4 Seeing Changes Made by Other Sessions" in the 
JSR-170 spec.


It should only throw an exception if you did this:

   // modify property in session 1's transient space
   n1.getNode("jcr:content").setProperty("jcr:data", testcontent + ", as 
modified by session 1");


   // modify persisted property through session 2
   n2.getNode("jcr:content").setProperty("jcr:data", testcontent + ", as 
modified by session 2");

   n2.save();

   // now try to save session 1... should fail
   n1.save();


Please note that the above statement is purely theoretical at the moment 
;-)


It is :-)

Changing the test as suggested doesn't affect the result; still no 
exception.


BR, Julian


Re: Concurrent modifications

2008-04-22 Thread Alexander Klimetschek

Hi Julian!

Am 22.04.2008 um 19:04 schrieb Julian Reschke:

   // modify through session1

   n1.getNode("jcr:content").setProperty("jcr:data", testcontent +  
", as modified by session 1");

   n1.save();

   // modify through session2

   n2.getNode("jcr:content").setProperty("jcr:data", testcontent +  
", as modified by session 2");

   n2.save();
 }


I think it's correct. The property "testconcurrent/jcr:content/ 
jcr:data" in session 2 is never put into the transient space *before*  
session 1 saves. It is fetched for the first time when you modify it.  
That you have done it above while creating the properties for the  
first time is irrelevant, since you did a save() then, which took  
those properties "out" of the transient space again.


IIUC this is an example of the "copy-on-write" style that Jackrabbit  
implements. See "7.1.3.4 Seeing Changes Made by Other Sessions" in the  
JSR-170 spec.


It should only throw an exception if you did this:

   // modify property in session 1's transient space
   n1.getNode("jcr:content").setProperty("jcr:data", testcontent + ",  
as modified by session 1");


   // modify persisted property through session 2
   n2.getNode("jcr:content").setProperty("jcr:data", testcontent + ",  
as modified by session 2");

   n2.save();

   // now try to save session 1... should fail
   n1.save();


Please note that the above statement is purely theoretical at the  
moment ;-)


Regards,
Alex

--
Alexander Klimetschek
[EMAIL PROTECTED]

>> Day JCR Cup 08 | Win a MacBook Pro: http://dev.day.com/ <<






Re: Concurrent modifications

2008-04-22 Thread Julian Reschke

Julian Reschke wrote:

...
However, this test:



...passes, although I would expect it to fail.

Sorry for the incomplete mail :-)

BR, Julian


Re: Concurrent modifications ...

2006-04-21 Thread Robert Shiner
Marcel,

Thanks for your quick response,

Bob

On 4/21/06, Marcel Reutegger <[EMAIL PROTECTED]> wrote:
>
> Robert Shiner wrote:
> > Yup, that seems to work, thanks.  Although not against 1.0, I needed to
> > checkout and build the latest snapshot.
>
> oh, you are right. thanks for pointing that out. the related issue is:
> JCR-336.
>
> > Does anyone know when the next release with the lock fixes in is due?
> >
> > Also I have a question around applying the lockable mixin.
> >
> > I understand that a node can not be locked unless it has the lockable
> mixin
> > applied.
>
> IMO a good node type design already has the mix:lockable mixin in its
> definition for nodes that should be lockable. with such a design it is
> then not necessary for an application to add mixins on node instances.
>
> > If I want to lock a node, but I'm not sure whether it already has
> > the lockable mixin, how can I check and then add the mixin in such a way
> > that is safe in a concurrent environment?
>
> node.isNodeType("mix:lockable") will return true if it is lockable.
>
> you need to aquire a deep lock on a lockable ancestor of that node then
> you can add a mixin to the desired node. but as I pointed out before I
> suggest you do not add mixins to individual node instances but define
> lockable mixins in your type hierarchy.
>
> regards
>   marcel
>


Re: Concurrent modifications ...

2006-04-21 Thread Marcel Reutegger

Robert Shiner wrote:

Yup, that seems to work, thanks.  Although not against 1.0, I needed to
checkout and build the latest snapshot.


oh, you are right. thanks for pointing that out. the related issue is: 
JCR-336.



Does anyone know when the next release with the lock fixes in is due?

Also I have a question around applying the lockable mixin.

I understand that a node can not be locked unless it has the lockable mixin
applied.


IMO a good node type design already has the mix:lockable mixin in its 
definition for nodes that should be lockable. with such a design it is 
then not necessary for an application to add mixins on node instances.



If I want to lock a node, but I'm not sure whether it already has
the lockable mixin, how can I check and then add the mixin in such a way
that is safe in a concurrent environment?


node.isNodeType("mix:lockable") will return true if it is lockable.

you need to aquire a deep lock on a lockable ancestor of that node then 
you can add a mixin to the desired node. but as I pointed out before I 
suggest you do not add mixins to individual node instances but define 
lockable mixins in your type hierarchy.


regards
 marcel


Re: Concurrent modifications ...

2006-04-21 Thread Robert Shiner
Hi,

Yup, that seems to work, thanks.  Although not against 1.0, I needed to
checkout and build the latest snapshot.

Does anyone know when the next release with the lock fixes in is due?

Also I have a question around applying the lockable mixin.

I understand that a node can not be locked unless it has the lockable mixin
applied.  If I want to lock a node, but I'm not sure whether it already has
the lockable mixin, how can I check and then add the mixin in such a way
that is safe in a concurrent environment?

Thanks for you help with this, I appreciate you are all busy guys!

Thanks,
Bob

On 4/20/06, Robert Shiner <[EMAIL PROTECTED]> wrote:
>
> Thanks Marcel,
>
> I'll give that a try.
>
> Bob
>
>
> On 4/20/06, Marcel Reutegger <[EMAIL PROTECTED]> wrote:
> >
> > Hi Bob,
> >
> > in general your code should work, but the while loop is more or less a
> > busy wait. that is your cpu will go to 100% while waiting for the lock.
> >
> > There is a utility in jackrabbit that you can use to achieve exactly
> > what you are trying to do:
> > org.apache.jackrabbit.util.Locked
> >
> > here's an example how to use it:
> >
> > final Node n =  // the node where you want to add a folder
> > Node folder = (Node) new Locked() {
> >  protected Object run() throws RepositoryException {
> >  Node f = n.addNode("testFolder_" + System.currentTimeMillis(),
> > "nt:folder");
> >  n.save();
> >  return f;
> >  }
> > }.with(n, false);
> > // do something with the newly created folder
> > folder.getPath();
> >
> > The utility however is not included in the jackrabbit 1.0 release. You
> > have to look it up in the jackrabbit svn trunk or build jackrabbit from
> > trunk.
> >
> > regards
> >   marcel
> >
> > Robert Shiner wrote:
> > > Hi,
> > >
> > > I wonder if you can help me.
> > >
> > > I would like to write some code that adds a folder to a parent, but I
> > want
> > > to do this in such a way that it will work during concurrent
> > modifications.
> > >
> > > The code I currently have is as follows ...
> > >
> > >   // Start the session
> > >   Session session = repository.login(new SimpleCredentials("admin",
> > > "admin".toCharArray()));
> > >   try
> > >   {
> > >   // Get the root node for now
> > >   Node rootNode = session.getRootNode();
> > >
> > >  // Wait untill a lock is available on the parent folder
> > >  boolean hasLock = false;
> > >  while (hasLock == false)
> > >  {
> > > if (folder.isLocked() == false)
> > > {
> > >try
> > >{
> > >   // Take the lock out on the parent
> > >   folder.lock(false, true);
> > >   hasLock = true;
> > >}
> > >catch (Exception exception)
> > >{
> > >   // Ignore and retry
> > >}
> > > }
> > >
> > >  Thread.yield();
> > >   }
> > >
> > >   // Add the new folder
> > >   rootNode.addNode ("testFolder_" + System.currentTimeMillis(),
> > > "nt:folder");
> > >
> > >   // Save the session
> > >   session.save();
> > >   }
> > >   finally
> > >   {
> > >   // Log out, lock is revoked
> > >   session.logout();
> > >   }
> > >
> > > I have a couple of questions:
> > >
> > > 1)  Is this pattern ok or is there a better way to do things?
> > > 2)  I have assumed that the parent node (the root node in this
> > example) is
> > > lockable.  If it isn't what is the best way to apply the lockable
> > aspect in
> > > a concurrent safe way?
> > >
> > > I'm new to JackRabbit and trying to evaluate its capabilities.  Any
> > help or
> > > feedback will be gratefully received.
> > >
> > > Thanks in advance,
> > > Bob
> > >
> >
> >
>


Re: Concurrent modifications ...

2006-04-20 Thread Robert Shiner
Thanks Marcel,

I'll give that a try.

Bob

On 4/20/06, Marcel Reutegger <[EMAIL PROTECTED]> wrote:
>
> Hi Bob,
>
> in general your code should work, but the while loop is more or less a
> busy wait. that is your cpu will go to 100% while waiting for the lock.
>
> There is a utility in jackrabbit that you can use to achieve exactly
> what you are trying to do:
> org.apache.jackrabbit.util.Locked
>
> here's an example how to use it:
>
> final Node n =  // the node where you want to add a folder
> Node folder = (Node) new Locked() {
>  protected Object run() throws RepositoryException {
>  Node f = n.addNode("testFolder_" + System.currentTimeMillis(),
> "nt:folder");
>  n.save();
>  return f;
>  }
> }.with(n, false);
> // do something with the newly created folder
> folder.getPath();
>
> The utility however is not included in the jackrabbit 1.0 release. You
> have to look it up in the jackrabbit svn trunk or build jackrabbit from
> trunk.
>
> regards
>   marcel
>
> Robert Shiner wrote:
> > Hi,
> >
> > I wonder if you can help me.
> >
> > I would like to write some code that adds a folder to a parent, but I
> want
> > to do this in such a way that it will work during concurrent
> modifications.
> >
> > The code I currently have is as follows ...
> >
> >   // Start the session
> >   Session session = repository.login(new SimpleCredentials("admin",
> > "admin".toCharArray()));
> >   try
> >   {
> >   // Get the root node for now
> >   Node rootNode = session.getRootNode();
> >
> >  // Wait untill a lock is available on the parent folder
> >  boolean hasLock = false;
> >  while (hasLock == false)
> >  {
> > if (folder.isLocked() == false)
> > {
> >try
> >{
> >   // Take the lock out on the parent
> >   folder.lock(false, true);
> >   hasLock = true;
> >}
> >catch (Exception exception)
> >{
> >   // Ignore and retry
> >}
> > }
> >
> >  Thread.yield();
> >   }
> >
> >   // Add the new folder
> >   rootNode.addNode ("testFolder_" + System.currentTimeMillis(),
> > "nt:folder");
> >
> >   // Save the session
> >   session.save();
> >   }
> >   finally
> >   {
> >   // Log out, lock is revoked
> >   session.logout();
> >   }
> >
> > I have a couple of questions:
> >
> > 1)  Is this pattern ok or is there a better way to do things?
> > 2)  I have assumed that the parent node (the root node in this example)
> is
> > lockable.  If it isn't what is the best way to apply the lockable aspect
> in
> > a concurrent safe way?
> >
> > I'm new to JackRabbit and trying to evaluate its capabilities.  Any help
> or
> > feedback will be gratefully received.
> >
> > Thanks in advance,
> > Bob
> >
>
>


Re: Concurrent modifications ...

2006-04-20 Thread Marcel Reutegger

Hi Bob,

in general your code should work, but the while loop is more or less a 
busy wait. that is your cpu will go to 100% while waiting for the lock.


There is a utility in jackrabbit that you can use to achieve exactly 
what you are trying to do:

org.apache.jackrabbit.util.Locked

here's an example how to use it:

final Node n =  // the node where you want to add a folder
Node folder = (Node) new Locked() {
protected Object run() throws RepositoryException {
Node f = n.addNode("testFolder_" + System.currentTimeMillis(), 
"nt:folder");

n.save();
return f;
}
}.with(n, false);
// do something with the newly created folder
folder.getPath();

The utility however is not included in the jackrabbit 1.0 release. You 
have to look it up in the jackrabbit svn trunk or build jackrabbit from 
trunk.


regards
 marcel

Robert Shiner wrote:

Hi,

I wonder if you can help me.

I would like to write some code that adds a folder to a parent, but I want
to do this in such a way that it will work during concurrent modifications.

The code I currently have is as follows ...

  // Start the session
  Session session = repository.login(new SimpleCredentials("admin",
"admin".toCharArray()));
  try
  {
  // Get the root node for now
  Node rootNode = session.getRootNode();

 // Wait untill a lock is available on the parent folder
 boolean hasLock = false;
 while (hasLock == false)
 {
if (folder.isLocked() == false)
{
   try
   {
  // Take the lock out on the parent
  folder.lock(false, true);
  hasLock = true;
   }
   catch (Exception exception)
   {
  // Ignore and retry
   }
}

 Thread.yield();
  }

  // Add the new folder
  rootNode.addNode ("testFolder_" + System.currentTimeMillis(),
"nt:folder");

  // Save the session
  session.save();
  }
  finally
  {
  // Log out, lock is revoked
  session.logout();
  }

I have a couple of questions:

1)  Is this pattern ok or is there a better way to do things?
2)  I have assumed that the parent node (the root node in this example) is
lockable.  If it isn't what is the best way to apply the lockable aspect in
a concurrent safe way?

I'm new to JackRabbit and trying to evaluate its capabilities.  Any help or
feedback will be gratefully received.

Thanks in advance,
Bob