Re: Concurrent modifications
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
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
> 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
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
> 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Julian Reschke wrote: ... However, this test: ...passes, although I would expect it to fail. Sorry for the incomplete mail :-) BR, Julian
Re: Concurrent modifications ...
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 ...
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 ...
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 ...
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 ...
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
