You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oz...@apache.org on 2004/10/31 21:25:59 UTC

cvs commit: jakarta-commons-sandbox/transaction/xdocs/maps wrappers-comparision.xml

ozeigermann    2004/10/31 12:25:59

  Modified:    transaction/xdocs navigation.xml
               transaction/xdocs/locks tutorial.xml index.xml
               transaction/xdocs/maps wrappers-comparision.xml
  Log:
  Largely added to the docs
  
  Revision  Changes    Path
  1.3       +3 -0      jakarta-commons-sandbox/transaction/xdocs/navigation.xml
  
  Index: navigation.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/transaction/xdocs/navigation.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- navigation.xml	23 Jun 2004 10:19:05 -0000	1.2
  +++ navigation.xml	31 Oct 2004 20:25:59 -0000	1.3
  @@ -8,6 +8,9 @@
               <item name="Transactional Maps" href="/maps/index.html">
               	<item name="Map Wrapper comparision" href="/maps/wrappers-comparision.html"/>
               </item>	
  +            <item name="Locking" href="/locks/index.html">
  +            	<item name="Lock tutorial" href="/locks/tutorial.html"/>
  +            </item>	
   <!--            <item name="Configuration"                 href="/configuration.html" /> -->
               <item name="API&#xA0;Documentation"        href="/apidocs/index.html"/>
   <!--
  
  
  
  1.2       +235 -0    jakarta-commons-sandbox/transaction/xdocs/locks/tutorial.xml
  
  Index: tutorial.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/transaction/xdocs/locks/tutorial.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- tutorial.xml	31 Oct 2004 14:06:24 -0000	1.1
  +++ tutorial.xml	31 Oct 2004 20:25:59 -0000	1.2
  @@ -10,10 +10,245 @@
    <body>
   
   <section name="Locking tutorial">
  +
  +<p>The <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/package-summary.html">locking
  +package</a> merely consists of two interfaces for a <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/LockManager.html">lock
  +manager</a> and a <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/MultiLevelLock.html">multilevel
  +lock</a> and specific implementations. There is a <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/GenericLock.html">generic
  +implementation</a> of a multi level lock with a subtle, yet simple
  +compatibility mechanism. This mechanism allows to implement quite a
  +number of different lock types such as a read write lock which is
  +<a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/ReadWriteLock.html">provided
  +for covenience</a>, although very easy to implement. As already
  +<a href="index.html">exlained</a> in the locking agent can be any Java
  +object. Have a look at the simple <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/ReadWriteLock.html#acquireRead(java.lang.Object,%20long)">
  +method for acquiring a lock for read access</a> as a reference.</p>
  +<p>If you
  +need a single or pre-determined number of classes the generic or
  +read/write lock is all you need. However, sometimes you may not know
  +how many locks and which locks you will need in advance. In this case you can use the
  +lock manager with its <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/GenericLockManager.html">default
  +implementation</a>. The most <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/LockManager.html#atomicGetOrCreateLock(java.lang.Object)">important
  +method</a> is for either creating a non existing lock in a specified
  +resource or retrieving it if it was created before. It is important to
  +make this atomically so there is no chance of acciently creating more
  +than one lock for a single resource.</p>
  +<p><em>The whole trick is to have at
  +most one lock for a resource and have different compatible lock levels
  +for different agents acquiring the lock on that resource</em>.
  +</p>
  +
  +
  +<subsection name="Example: Fine grained locks in Jakarta Slide">
  +
  +<p>Lets get to the first example which is how Jakarta Slide handles
  +fine grained locking in its WebDAV layer. Slide can store resources to
  +all kinds of stores which most likely have locks for consistency as
  +well. However, there is this generic locking to be very sure there are
  +no deadlocks, the behavior is similar for all stores and finally to
  +provide locking for stores that do not have locks of their own. All
  +locks must be set at the very beginning of a request and release at
  +the end of the request in an atomic 
  +block to ban the hazard of deadlocks. Slide does this with a simple
  +synchronized block, but to have something to show here we will exercise it
  +with a multi level lock. Such a lock is very simple and is merely
  +exclusive, it will look like this:
  +<source>
  +GenericLock exclusive = new new GenericLock("Mutex", 1,
  +            new PrintWriterLogger(new PrintWriter(System.out), "Locking", false));
  +</source>
  +Now we have a lock called "Mutex" with the highest lock level of
  +<code>1</code> and a logger that simply writes to stdout. Different
  +lock levels and their compatibility is a special feature of
  +<a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/GenericLock.html">GenericLock</a>
  +and is explained there in detail. As we have one locking level, this
  +also is the only level we can possibly acquire causing an exclusive lock:  
  +<source>
  +exclusive.acquire("Owner", 1, true, true, Long.MAX_VALUE);
  +</source>
  +This tries to <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/GenericLock.html#acquire(java.lang.Object,%20int,%20boolean,%20boolean,%20long)">acquire
  +a lock</a> of level one (=exclusive) for the agent 
  +"Owner". Parameters three and four tells the lock that it should block
  +the current thread if this lock level can not be acquired and that
  +this lock is reentrant. Reentrant means that the same agant can
  +require lock levels otherwise incompatible. Finally, there is a
  +timeout which is the maximum time the agent will wait for a lock. If a
  +lock still is unavailable after this time the method will return
  +false. In our case the request will (practically) never time out, we just wait until
  +we are served.</p>
  +
  +<p>Now all requests to fine grained locks will be braced with the
  +above statement and the <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/GenericLock.html#release(java.lang.Object)">release
  +statement</a> after all fine grained locks are acquired:    
  +<source>
  +exclusive.release("Owner");
  +</source>
  +As a single agent ("Owner" in our case) can have at most one lock
  +level on a lock - only the highest will be effective - no more than
  +the agent is required as a parameter.
  +</p>
  +
  +<p>Coming to the fain grained locks: Slide puts read and write locks
  +on resources accessed by WebDAV requests. As we really have no idea
  +with resources will be accessed until we receive the actual request we
  +use a lock manager which looks like this:
  +<source>
  +public final static READ_LOCK = 1;
  +public final static WRITE_LOCK = 2;
  +
  +LockManager lockManager = new GenericLockManager(WRITE_LOCK,
  +            new PrintWriterLogger(new PrintWriter(System.out), "Locking", false));
  +</source>
  +
  +Logs are the same as with the generic lock, they go to stdout. Before
  +explaining more details, let's see how we get a lock from that manager: 
  +<source>
  +GenericLock lock = (GenericLock) lockManager.atomicGetOrCreateLock("/");
  +</source>
  +This gives us the lock for the resource called "/" which of course is semantically
  +associated with the root of Slide's resource tree. The highst lock
  +level for the lock has been defined to two using the constant
  +<code>WRITE_LOCK</code>. Besides, it is good practice to use constants for the
  +lock levels in order to avoid unreadable code. Anyway, this returns a
  +lock that might have been created by this statement as well:
  +
  +<source>
  +GenericLock readWrite = new new GenericLock("/", 2,
  +            new PrintWriterLogger(new PrintWriter(System.out), "Locking", false));
  +</source>
  +
  +However, if we ask the lock manager for this lock the next time it
  +will not create a new lock, but will return the one created first
  +- preserving all lock levels already set. The assertion that all this
  +will be done atomically is very important for correctness and because
  +of this is reflected in the name of the method.
  +
  +</p>
  +
  +<p>The locks created by the above lock manager have two levels where
  +write is exclusive and read is shared. This means if there is a
  +write lock there can be no read locks and the other way
  +round. However, in the absense of a write lock read locks can happily
  +coexist with other read locks - they are shared - while write locks can not coexist with
  +other write locks - they are exclusive. This is very useful for server
  +locks as a there is no reason not to allow two GET requests to the
  +same resource at the same time. However, you should not allow a PUT
  +and a GET request to the same resource at the same time or even two PUT
  +requests. This means that none of the below statements will block
  +<source>
  +readWrite.acquire("request1", READ_LOCK, true, true, Long.MAX_VALUE);
  +readWrite.acquire("request2", READ_LOCK, true, true, Long.MAX_VALUE);
  +</source>
  +which would mean two requests called "request1" and "request2" can
  +read the root resource at the same time. Without releasing both of the
  +above locks the following write request will be blocked: 
  +<source>
  +readWrite.acquire("request3", WRITE_LOCK, true, true, Long.MAX_VALUE);
  +</source>
  +</p>
  +
  +</subsection>
  +
  +<subsection name="Advanced Example: Mixing fine grained with global locks">
  +
  +<p>In Slide there is a search method that allows you to
  +query for a set of documents that satisfy certain search
  +conditions. When you execute such a query at least the result
  +documents and indices will be touched with read access. As we learned
  +before we need to acquire all locks on the documents accessed before
  +starting the actual request to guarantee correctness and eliminate the
  +hazard of any deadlock. Of course there is no way to determine which
  +documents this will be beforehand as this would require anticipate the
  +result. Effectively, we need a global read lock. Now, while there is a
  +global read lock no other request must be allowed to write
  +concurrently. More than one concurrent search request all having a
  +global read lock would be no problem, but all requests that write in
  +any way must acquire an exclusive write lock. Easy, one could say, so
  +we have a lock with levels READ and WRITE which is a
  +simple read/write-lock as we have seen above. However, this is not quite adequate as it
  +will demolish our fine grained locking mentioned before: writes would
  +now be globally exclusive again. So, what we want from our lock is
  +that an unrestricted number of search requests - in absence of any
  +write request - may be done concurrently. Additionally, an
  +unrestricted number of concurrent write requests - in absence of any
  +search request - should be allowed as well. Sometimes the solution to
  +a problem becomes obvious as soon as you have written it down - like
  +in or case: we need two read/write locks!</p>  
  +
   <p>
  +Now a search request would try to acquire those locks before it executes:
  +<source>
  +public final static SHARED_LOCK = 1;
  +public final static EXCLUSIVE_LOCK = 2;
  +
  +searchLock.acquire("search request", SHARED_LOCK, true, true, Long.MAX_VALUE);
  +writeLock.acquire("search request", EXCLUSIVE_LOCK, true, true, Long.MAX_VALUE);
  +</source>
  +Note that we now call lock level one SHARED and lock level two
  +EXCLUSIVE instead of READ and WRITE as it fits the semantics of these
  +operations better. Any write request will call these statements 
  +<source>
  +writeLock.acquire("write request", SHARED_LOCK, true, true, Long.MAX_VALUE);
  +searchLock.acquire("write request", EXCLUSIVE_LOCK, true, true, Long.MAX_VALUE);
  +</source>
  +as the counter part of the above. 
   </p>
   
  +<p>That's it, isn't it? No, it is not. You might have already noticed,
  +that nothing has been gained. Now all write methods block each other
  +in the searchLock and all search methods block each other in the
  +writeLock! <em>Sigh</em>! This is not what we wanted, we just wanted
  +to disallow any search when writing and any write when searching. The
  +exclusive locks for write and search should have been
  +<em>compatible</em>. This is tough as the compatibility mechanism of
  +the generic lock is based on the order of the levels and the highest
  +simply is exclusive. Adding another lock level to make the formerly
  +highest non exclusive would only cause a mess as no one would
  +understand anything any more and most important it would still not be
  +compatible to itself. Luckily, next to the additional reentrant compatibility we
  +have already used above there is the so called <code>support</code>
  +compatibility of locks. When acquiring a lock level you can ask the
  +generic lock not to consider lock levels acquired by other locking
  +agents - such as the search method - for compatibility calculation if
  +they have the same lock level you desire. This results in the
  +following code which is the final version:
  +
  +<source>
  +searchLock.acquire("search request", SHARED_LOCK, true, true, Long.MAX_VALUE);
  +writeLock.acquire("search request", EXCLUSIVE_LOCK, true, GenericLock.COMPATIBILITY_REENTRANT_AND_SUPPORT, Long.MAX_VALUE);
  +</source>
  +
  +and
  +
  +<source>
  +writeLock.acquire("write request", SHARED_LOCK, true, true, Long.MAX_VALUE);
  +searchLock.acquire("write request", EXCLUSIVE_LOCK, true, GenericLock.COMPATIBILITY_REENTRANT_AND_SUPPORT, Long.MAX_VALUE);
  +</source>
  +
  +As much for our short round trip. More information about this additional compatibility can be found <a
  +href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/locking/GenericLock.html#acquire(java.lang.Object,%20int,%20boolean,%20int,%20long)">here</a>.
  +If you still need more turn
  +to the mailing list, get through the Javadocs and as the last resort through
  +the sources ;) 
  +
  +</p>
  + 
  +</subsection>
  +
   </section>
  +
  +
   
   </body>
   </document>
  
  
  
  1.2       +8 -7      jakarta-commons-sandbox/transaction/xdocs/locks/index.xml
  
  Index: index.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/transaction/xdocs/locks/index.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- index.xml	31 Oct 2004 14:06:24 -0000	1.1
  +++ index.xml	31 Oct 2004 20:25:59 -0000	1.2
  @@ -12,16 +12,16 @@
   <section name="Locking">
    <p>Locking refers to the procedure of restricting access to certain
    resources like objects or files on your hard disk. Such a restriction
  - might be necessary to guarantee validity and consistency of data and
  + might be necessary to guarantee validity and consistency of data in
    concurrent scenarios. E.g. consider two independent threads trying to
    write to one and the same file. The result would be undefined unless
  - same sort of restriction on access applied. Java already offers the
  + same sort of restriction on access applied.</p>
  +
  +<p>Java already offers the
    powerful and flexible high-level monitor concept. Every object
    can be used as a monitor and an associated (invisible) lock is used
    to protected critical secions in your code. Java 1.5 even introduces
  - explicite locking as an alternative.</p>
  -
  -<p>This may sound like there really is no need for additional locking
  + explicite locking as an alternative. This may sound like there really is no need for additional locking
   classes - at least when you can use Java 1.5. If you can not it might
   be nice to have something like a well tested read/write lock. Such a
   lock allows many threads to acquire access when reading, but only a
  @@ -37,10 +37,11 @@
    package you are not restricted to the usual lock types like e.g. an
    exclusive lock or a read/write lock, but you have simple, but
    powerful mechanisms to customize which lock types are
  - compatible. Maybe even more important you are decoupled from threads
  + compatible. Maybe even more important, you are decoupled from threads
    as the locking agents and are completely free to ascribe the lock to
    a process, a request or any other Java object you would like. Both
  - the transactional maps and the transactional file system make heavy
  + the transactional maps and the transactional file system of this
  + component make heavy
    use of them.
    </p>
   <p>To learn more about multi level locks and how you can use them continue
  
  
  
  1.3       +4 -3      jakarta-commons-sandbox/transaction/xdocs/maps/wrappers-comparision.xml
  
  Index: wrappers-comparision.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-commons-sandbox/transaction/xdocs/maps/wrappers-comparision.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- wrappers-comparision.xml	24 Jun 2004 15:07:55 -0000	1.2
  +++ wrappers-comparision.xml	31 Oct 2004 20:25:59 -0000	1.3
  @@ -18,9 +18,10 @@
   <thead>
   <tr>
   <th align="left" valign="bottom" scope="col"></th>
  -<th align="left" valign="bottom" scope="col"> <font face="Arial, Helvetica, sans-serif"><strong>TransactionalMapWrapper</strong></font></th>
  -<th align="left" valign="bottom" scope="col"> <font face="Arial, Helvetica, sans-serif"><strong>OptimisticMapWrapper</strong></font></th>
  -<th align="left" valign="bottom" scope="col"> <font face="Arial, Helvetica, sans-serif"><strong>PessimisticMapWrapper</strong></font></th>
  +<th align="left" valign="bottom" scope="col"> <font face="Arial,
  +Helvetica, sans-serif"><strong><a href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/memory/TransactionalMapWrapper.html">TransactionalMapWrapper</a></strong></font></th>
  +<th align="left" valign="bottom" scope="col"> <font face="Arial, Helvetica, sans-serif"><strong><a href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/memory/OptimisticMapWrapper.html">OptimisticMapWrapper</a></strong></font></th>
  +<th align="left" valign="bottom" scope="col"> <font face="Arial, Helvetica, sans-serif"><strong><a href="http://jakarta.apache.org/commons/sandbox/transaction/apidocs/org/apache/commons/transaction/memory/PessimisticMapWrapper.html">PessimisticMapWrapper</a></strong></font></th>
   </tr>
   </thead>
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org