You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by "Pill, Juergen" <Ju...@softwareag.com> on 2001/09/07 22:10:32 UTC

forcedEnlist - dirty read (was RE: cvs commit: jakarta-slide/s rc/webdav/server/org/apache/slide/webdav/method CopyMethod.java MoveMetho d.java PropPatchMethod.java PutMethod.java)

Hello Remy,

sorry for the late response. We are fighting against multi user problems.

I have used your code and I have two problems found:

1) I receive a XA exception, I will look into this Monday again.
2) The current implementation transiently locks all objects until the root
is reached. One responsible method is "isLockedInternal", which will
navigate through the complete scope tree, reading the WebDAV locks and
transiently lock all the read objects for write. Would there be a
possibility to exclude all those accessed objects (in that method) from the
dirty read prevention, e.g. setting the forcedEnlist to false for those
read-only-used objects.
3) I had to include (un)lock, mkcol and delete in this forcedEnlist
processing too (not returned to CVS yet).

Instead of transient read locking all objects by default, I would prefer to
tell the stores only those URIs, which are going to be modified. This would
give us a finer control over the transient locking process and therefore
improve the overall through-put of the server.

Have a nice weekend

Juergen



	/**
	 * Tests if an element is locked.
	 *
	 * @param token Lock token to test
	 * @return boolean True if locked
	 * @exception ServiceAccessException Low level service access
exception
	 * @exception ObjectNotFoundException One of the objects referenced
	 * in the lock token were not found
	 */
	private boolean isLockedInternal
		(SlideToken slideToken, NodeLock token,
		 boolean tryToLock, ObjectIsAlreadyLockedException
nestedException)
		throws ServiceAccessException, ObjectNotFoundException {

		Uri objectUri = namespace.getUri(slideToken,
token.getObjectUri());
		ObjectNode initialObject = objectUri.getStore()
			.retrieveObject(objectUri);
		Enumeration scopes = objectUri.getScopes();
		
		// At the end of the test, this boolean's value is true if
we can
		// actually put the lock on the desired subject.
		boolean isLocked = false;
		
		// We parse all of the scopes which encompass the subject we
want
		// to lock.
		// First, we parse all the parents of the subject.
		while (!isLocked && scopes.hasMoreElements()) {
			String currentScope = (String) scopes.nextElement();
			Uri currentScopeUri = namespace.getUri(slideToken,
currentScope);
			Enumeration locks = currentScopeUri.getStore()
				.enumerateLocks(currentScopeUri);
			
			while (locks.hasMoreElements()) {
				NodeLock currentLockToken = (NodeLock)
locks.nextElement();
				if (!isCompatible(slideToken, token,
currentLockToken,
	
tryToLock)) {
					isLocked = true;
					if (nestedException != null) {
						nestedException.addException
							(new
ObjectLockedException
	
(currentScopeUri.toString()));
					}
				}
			}
		}
		
		// Then, if the desired scope is inheritable, we parse the
		// locked subject's children to see if any of them has been
		// locked with an incompatible lock.
		if (token.isInheritable()) {
			Stack childrenStack = new Stack();
			childrenStack.push(initialObject);
			while (!isLocked && !childrenStack.empty()) {
				ObjectNode currentObject = (ObjectNode)
childrenStack.pop();
				Uri currentObjectUri =
					namespace.getUri(slideToken,
currentObject.getUri());
				// We test the compatibility of the child
				Enumeration locks =
currentObjectUri.getStore()
					.enumerateLocks(currentObjectUri);
				
				while (locks.hasMoreElements()) {
					NodeLock currentLockToken =
(NodeLock) locks.nextElement();
					if (!isCompatible(slideToken, token,
	
currentLockToken, tryToLock)) {
						isLocked = true;
						if (nestedException != null)
{
	
nestedException.addException
								(new
ObjectLockedException
	
(currentObjectUri.toString()));
						}
					}
				}
				
				// We get the children and add them to the
Stack.
				
				Vector childrenVector = new Vector();
				Enumeration childrenUri =
currentObject.enumerateChildren();
				while (childrenUri.hasMoreElements()) {
					String childUri = (String)
childrenUri.nextElement();
					Uri tempUri =
namespace.getUri(slideToken, childUri);
					ObjectNode child =
tempUri.getStore()
						.retrieveObject(tempUri);
					childrenVector.addElement(child);
				}
				
				Enumeration children =
childrenVector.elements();
				while (children.hasMoreElements()) {
					ObjectNode tempObject =
						(ObjectNode)
children.nextElement();
					childrenStack.push(tempObject);
				}
			}
		}
		
		return isLocked;
		
	}


-----Original Message-----
From: remm@apache.org [mailto:remm@apache.org]
Sent: Friday, August 31, 2001 05.22 AM
To: jakarta-slide-cvs@apache.org
Subject: cvs commit:
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method
CopyMethod.java MoveMethod.java PropPatchMethod.java PutMethod.java


remm        01/08/30 20:21:45

  Modified:    src/webdav/server/org/apache/slide/webdav/method
                        CopyMethod.java MoveMethod.java
                        PropPatchMethod.java PutMethod.java
  Log:
  - Use the new ForceStoreEnlistment flag in COPY, MOVE, PROPPATCH
    and PUT, to prevent dirty reads (Juergen, is it doing what it is
supposed to be doing ?).
  
  Revision  Changes    Path
  1.19      +6 -3
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/CopyMethod.ja
va
  
  Index: CopyMethod.java
  ===================================================================
  RCS file:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Cop
yMethod.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- CopyMethod.java	2001/08/01 16:30:58	1.18
  +++ CopyMethod.java	2001/08/31 03:21:45	1.19
  @@ -1,7 +1,7 @@
   /*
  - * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Cop
yMethod.java,v 1.18 2001/08/01 16:30:58 cmlenz Exp $
  - * $Revision: 1.18 $
  - * $Date: 2001/08/01 16:30:58 $
  + * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Cop
yMethod.java,v 1.19 2001/08/31 03:21:45 remm Exp $
  + * $Revision: 1.19 $
  + * $Date: 2001/08/31 03:21:45 $
    *
    * ====================================================================
    *
  @@ -118,6 +118,9 @@
        */
       protected void executeRequest()
           throws WebdavException {
  +        
  +        // Prevent dirty reads
  +        slideToken.setForceStoreEnlistment(true);
           
           MacroParameters macroParameters = null;
           String status = null;
  
  
  
  1.19      +6 -3
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/MoveMethod.ja
va
  
  Index: MoveMethod.java
  ===================================================================
  RCS file:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Mov
eMethod.java,v
  retrieving revision 1.18
  retrieving revision 1.19
  diff -u -r1.18 -r1.19
  --- MoveMethod.java	2001/08/01 16:30:58	1.18
  +++ MoveMethod.java	2001/08/31 03:21:45	1.19
  @@ -1,7 +1,7 @@
   /*
  - * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Mov
eMethod.java,v 1.18 2001/08/01 16:30:58 cmlenz Exp $
  - * $Revision: 1.18 $
  - * $Date: 2001/08/01 16:30:58 $
  + * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Mov
eMethod.java,v 1.19 2001/08/31 03:21:45 remm Exp $
  + * $Revision: 1.19 $
  + * $Date: 2001/08/31 03:21:45 $
    *
    * ====================================================================
    *
  @@ -115,6 +115,9 @@
        */
       protected void executeRequest()
           throws WebdavException {
  +        
  +        // Prevent dirty reads
  +        slideToken.setForceStoreEnlistment(true);
           
           MacroParameters macroParameters = null;
           boolean isCollection = isCollection(sourceUri);
  
  
  
  1.20      +6 -3
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PropPatchMeth
od.java
  
  Index: PropPatchMethod.java
  ===================================================================
  RCS file:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Pro
pPatchMethod.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- PropPatchMethod.java	2001/08/17 14:39:12	1.19
  +++ PropPatchMethod.java	2001/08/31 03:21:45	1.20
  @@ -1,7 +1,7 @@
   /*
  - * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Pro
pPatchMethod.java,v 1.19 2001/08/17 14:39:12 cmlenz Exp $
  - * $Revision: 1.19 $
  - * $Date: 2001/08/17 14:39:12 $
  + * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Pro
pPatchMethod.java,v 1.20 2001/08/31 03:21:45 remm Exp $
  + * $Revision: 1.20 $
  + * $Date: 2001/08/31 03:21:45 $
    *
    * ====================================================================
    *
  @@ -250,6 +250,9 @@
        */
       protected void executeRequest()
           throws WebdavException {
  +        
  +        // Prevent dirty reads
  +        slideToken.setForceStoreEnlistment(true);
           
           try {
               
  
  
  
  1.17      +6 -3
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/PutMethod.jav
a
  
  Index: PutMethod.java
  ===================================================================
  RCS file:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Put
Method.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- PutMethod.java	2001/08/17 14:39:12	1.16
  +++ PutMethod.java	2001/08/31 03:21:45	1.17
  @@ -1,7 +1,7 @@
   /*
  - * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Put
Method.java,v 1.16 2001/08/17 14:39:12 cmlenz Exp $
  - * $Revision: 1.16 $
  - * $Date: 2001/08/17 14:39:12 $
  + * $Header:
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/Put
Method.java,v 1.17 2001/08/31 03:21:45 remm Exp $
  + * $Revision: 1.17 $
  + * $Date: 2001/08/31 03:21:45 $
    *
    * ====================================================================
    *
  @@ -137,6 +137,9 @@
        */
       protected void executeRequest()
           throws WebdavException {
  +        
  +        // Prevent dirty reads
  +        slideToken.setForceStoreEnlistment(true);
           
           try {
               
  
  
  

Re: forcedEnlist - dirty read (was RE: cvs commit: jakarta-slide/src/webdav/server/org/apache/slide/webdav/method CopyMethod.java MoveMethod.java PropPatchMethod.java PutMethod.java)

Posted by Remy Maucherat <re...@apache.org>.
> Hello Remy,
>
> sorry for the late response. We are fighting against multi user problems.

Yes, I read the commit messages. Thanks for the time spent doing stress
tests :)

> I have used your code and I have two problems found:
>
> 1) I receive a XA exception, I will look into this Monday again.

Ok.

> 2) The current implementation transiently locks all objects until the root
> is reached. One responsible method is "isLockedInternal", which will
> navigate through the complete scope tree, reading the WebDAV locks and
> transiently lock all the read objects for write. Would there be a
> possibility to exclude all those accessed objects (in that method) from
the
> dirty read prevention, e.g. setting the forcedEnlist to false for those
> read-only-used objects.

True. I forgot about that :-(

It's easy to allow dirty reading the lock and the security (remove the
enlist/delist for enumeratePermissions and enumerateLocks), but I don't
think it's a really good idea.

Maybe we can add a second flag in the token which would be set during
security / lock checking (something called accessCheck). If set to true,
then we can allow dirty reads for security / lock.

> 3) I had to include (un)lock, mkcol and delete in this forcedEnlist
> processing too (not returned to CVS yet).

Sure.

> Instead of transient read locking all objects by default, I would prefer
to
> tell the stores only those URIs, which are going to be modified. This
would
> give us a finer control over the transient locking process and therefore
> improve the overall through-put of the server.
>
> Have a nice weekend

You too. Could you vote/comment on the release plan and proposed features
list when you get the chance ?

Remy

> /**
> * Tests if an element is locked.
> *
> * @param token Lock token to test
> * @return boolean True if locked
> * @exception ServiceAccessException Low level service access
> exception
> * @exception ObjectNotFoundException One of the objects referenced
> * in the lock token were not found
> */
> private boolean isLockedInternal
> (SlideToken slideToken, NodeLock token,
> boolean tryToLock, ObjectIsAlreadyLockedException
> nestedException)
> throws ServiceAccessException, ObjectNotFoundException {
>
> Uri objectUri = namespace.getUri(slideToken,
> token.getObjectUri());
> ObjectNode initialObject = objectUri.getStore()
> .retrieveObject(objectUri);
> Enumeration scopes = objectUri.getScopes();
>
> // At the end of the test, this boolean's value is true if
> we can
> // actually put the lock on the desired subject.
> boolean isLocked = false;
>
> // We parse all of the scopes which encompass the subject we
> want
> // to lock.
> // First, we parse all the parents of the subject.
> while (!isLocked && scopes.hasMoreElements()) {
> String currentScope = (String) scopes.nextElement();
> Uri currentScopeUri = namespace.getUri(slideToken,
> currentScope);
> Enumeration locks = currentScopeUri.getStore()
> .enumerateLocks(currentScopeUri);
>
> while (locks.hasMoreElements()) {
> NodeLock currentLockToken = (NodeLock)
> locks.nextElement();
> if (!isCompatible(slideToken, token,
> currentLockToken,
>
> tryToLock)) {
> isLocked = true;
> if (nestedException != null) {
> nestedException.addException
> (new
> ObjectLockedException
>
> (currentScopeUri.toString()));
> }
> }
> }
> }
>
> // Then, if the desired scope is inheritable, we parse the
> // locked subject's children to see if any of them has been
> // locked with an incompatible lock.
> if (token.isInheritable()) {
> Stack childrenStack = new Stack();
> childrenStack.push(initialObject);
> while (!isLocked && !childrenStack.empty()) {
> ObjectNode currentObject = (ObjectNode)
> childrenStack.pop();
> Uri currentObjectUri =
> namespace.getUri(slideToken,
> currentObject.getUri());
> // We test the compatibility of the child
> Enumeration locks =
> currentObjectUri.getStore()
> .enumerateLocks(currentObjectUri);
>
> while (locks.hasMoreElements()) {
> NodeLock currentLockToken =
> (NodeLock) locks.nextElement();
> if (!isCompatible(slideToken, token,
>
> currentLockToken, tryToLock)) {
> isLocked = true;
> if (nestedException != null)
> {
>
> nestedException.addException
> (new
> ObjectLockedException
>
> (currentObjectUri.toString()));
> }
> }
> }
>
> // We get the children and add them to the
> Stack.
>
> Vector childrenVector = new Vector();
> Enumeration childrenUri =
> currentObject.enumerateChildren();
> while (childrenUri.hasMoreElements()) {
> String childUri = (String)
> childrenUri.nextElement();
> Uri tempUri =
> namespace.getUri(slideToken, childUri);
> ObjectNode child =
> tempUri.getStore()
> .retrieveObject(tempUri);
> childrenVector.addElement(child);
> }
>
> Enumeration children =
> childrenVector.elements();
> while (children.hasMoreElements()) {
> ObjectNode tempObject =
> (ObjectNode)
> children.nextElement();
> childrenStack.push(tempObject);
> }
> }
> }
>
> return isLocked;
>
> }