ozeigermann    2004/12/07 09:03:03

  Modified:    src/stores/org/apache/slide/store/impl/rdbms
                        MySqlRDBMSAdapter.java
               src/webdav/server/org/apache/slide/webdav/method
                        AbstractWebdavMethod.java
               src/stores/org/apache/slide/store/txfile
                        AbstractTxFileStoreService.java
  Added:       src/share/org/apache/slide/store
                        ConcurrencyConflictException.java
  Log:
  Added rudimentary support for internal and transparent repeat
  of conflicting transactions.
  
  Revision  Changes    Path
  1.11      +7 -5      
jakarta-slide/src/stores/org/apache/slide/store/impl/rdbms/MySqlRDBMSAdapter.java
  
  Index: MySqlRDBMSAdapter.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/stores/org/apache/slide/store/impl/rdbms/MySqlRDBMSAdapter.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- MySqlRDBMSAdapter.java    11 Nov 2004 17:15:35 -0000      1.10
  +++ MySqlRDBMSAdapter.java    7 Dec 2004 17:03:02 -0000       1.11
  @@ -35,6 +35,7 @@
   import org.apache.slide.content.*;
   import org.apache.slide.common.*;
   import org.apache.slide.macro.ConflictException;
  +import org.apache.slide.store.ConcurrencyConflictException;
   import org.apache.slide.structure.ObjectNotFoundException;
   import org.apache.slide.util.logger.Logger;
   
  @@ -61,7 +62,8 @@
           switch (e.getErrorCode()) {
               case 1213 : // thread was deadlock victim
                   getLogger().log(e.getErrorCode() + ": Deadlock resolved on " 
+ uri, LOG_CHANNEL, Logger.WARNING);
  -                return new ServiceAccessException(service, new 
ConflictException(uri));
  +                throw new ConcurrencyConflictException(e, uri);
  +//              throw new ServiceAccessException(this, new 
ConflictException(uri));
   
               default :
                   getLogger().log(
  
  
  
  1.64      +112 -45   
jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AbstractWebdavMethod.java
  
  Index: AbstractWebdavMethod.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/webdav/server/org/apache/slide/webdav/method/AbstractWebdavMethod.java,v
  retrieving revision 1.63
  retrieving revision 1.64
  diff -u -r1.63 -r1.64
  --- AbstractWebdavMethod.java 6 Dec 2004 08:54:13 -0000       1.63
  +++ AbstractWebdavMethod.java 7 Dec 2004 17:03:02 -0000       1.64
  @@ -61,12 +61,19 @@
   import org.apache.slide.content.NodeRevisionContent;
   import org.apache.slide.content.NodeRevisionDescriptor;
   import org.apache.slide.content.NodeRevisionDescriptors;
  +import org.apache.slide.content.RevisionDescriptorNotFoundException;
   import org.apache.slide.content.NodeProperty.NamespaceCache;
  +import org.apache.slide.event.VetoException;
   import org.apache.slide.lock.Lock;
   import org.apache.slide.lock.NodeLock;
  +import org.apache.slide.lock.ObjectLockedException;
  +import org.apache.slide.macro.ConflictException;
   import org.apache.slide.macro.Macro;
   import org.apache.slide.search.Search;
  +import org.apache.slide.security.AccessDeniedException;
   import org.apache.slide.security.Security;
  +import org.apache.slide.store.ConcurrencyConflictException;
  +import org.apache.slide.structure.LinkedObjectNotFoundException;
   import org.apache.slide.structure.ObjectNode;
   import org.apache.slide.structure.ObjectNotFoundException;
   import org.apache.slide.structure.Structure;
  @@ -185,6 +192,9 @@
       private static final GenericLock GLOBAL_WRITE_LOCK = new 
GenericLock("GLOBAL WRITE", EXCLUSIVE_LOCK,
               new PrintWriterLogger(new PrintWriter(System.out), LOG_CHANNEL, 
false));
   
  +    
  +    private static final int DEFAULT_MAX_RETRY_REPEATS = 1;
  +    
       // ----------------------------------------------------- Instance 
Variables
   
   
  @@ -413,53 +423,32 @@
               } catch (ObjectNotFoundException e) {
                   // ignore, it can't have locks
               }
  +            
  +            boolean done = false;
  +            boolean retryUponConflict = isRepeatUponConflict() && 
!slideToken.isExternalTransaction();
  +            int retries = getMaxRetryRepeats();
   
  -            boolean responseIsRedirected = false;
  -            if (!requestHeaders.getApplyToRedirectRef(false)) {
  -                try {
  -                    NodeRevisionDescriptors revisionDescriptors
  -                            = content.retrieve(slideToken, requestUri);
  -                    NodeRevisionDescriptor revisionDescriptor
  -                            = content.retrieve(slideToken, 
revisionDescriptors);
  -                    if (WebdavUtils.isRedirectref(revisionDescriptor)) {
  -                        NodeProperty refTarget
  -                                = 
revisionDescriptor.getProperty(P_REFTARGET);
  -
  -                        // Add the header indicating that this redirect is 
the
  -                        // result of a redirect reference.
  -                        resp.addHeader(H_REDIRECT_REF,
  -                                refTarget.getValue().toString());
  -                     
  -                        // Set the location header for the redirect.
  -                        resp.addHeader("Location",
  -                                refTarget.getValue().toString());
  -                               
  -                        // Determine the appropriate status code.
  -                        boolean permanent
  -                                = revisionDescriptor.propertyValueContains(
  -                                P_REDIRECT_LIFETIME, "permanent");
  -                        if (permanent) {
  -                            
resp.setStatus(WebdavStatus.SC_MOVED_PERMANENTLY);
  -                            resp.addHeader(H_CACHE_CONTROL, PRIVATE_CACHE);
  -                        }
  -                        else {
  -                            
resp.setStatus(WebdavStatus.SC_MOVED_TEMPORARILY);
  -                            resp.addHeader(H_CACHE_CONTROL, NO_CACHE);
  -                        }
  +            ConcurrencyConflictException finalCce = null;
   
  -                        // Set this flag so that we don't attempt to execute 
the
  -                        // request on the redirect reference itself.
  -                        responseIsRedirected = true;
  +            while (!done && retries != 0) {
  +                try {
  +                    executeRedirect();
  +                    done = true;
  +                } catch (ConcurrencyConflictException cce) {
  +                    finalCce = cce;
  +                    if (retryUponConflict) {
  +                        retries--;
  +                        token.getLogger().log(cce.getMessage(), LOG_CHANNEL, 
Logger.WARNING);
  +                        token.rollback();
  +                        token.begin();
  +                    } else {
  +                        break;
                       }
                   }
  -                catch (ObjectNotFoundException notFound) {
  -                    token.getLogger().log("Error while trying to send 
redirect",
  -                            notFound, LOG_CHANNEL, Logger.ERROR);
  -                }
               }
  -            
  -            if (!responseIsRedirected) {
  -                executeRequest();
  +            if (!done) {
  +                // rethrow it as an ordinary conflict exception
  +                throw new ConflictException(finalCce.getUri(), finalCce);
               }
   
               if (!slideToken.isExternalTransaction() && transactionIsStarted) 
{
  @@ -512,6 +501,57 @@
           }
       }
   
  +    protected void executeRedirect() throws AccessDeniedException, 
LinkedObjectNotFoundException,
  +            ObjectLockedException, RevisionDescriptorNotFoundException, 
ServiceAccessException,
  +            VetoException, WebdavException, IOException {
  +        boolean responseIsRedirected = false;
  +        if (!requestHeaders.getApplyToRedirectRef(false)) {
  +            try {
  +                NodeRevisionDescriptors revisionDescriptors
  +                        = content.retrieve(slideToken, requestUri);
  +                NodeRevisionDescriptor revisionDescriptor
  +                        = content.retrieve(slideToken, revisionDescriptors);
  +                if (WebdavUtils.isRedirectref(revisionDescriptor)) {
  +                    NodeProperty refTarget
  +                            = revisionDescriptor.getProperty(P_REFTARGET);
  +
  +                    // Add the header indicating that this redirect is the
  +                    // result of a redirect reference.
  +                    resp.addHeader(H_REDIRECT_REF,
  +                            refTarget.getValue().toString());
  +                 
  +                    // Set the location header for the redirect.
  +                    resp.addHeader("Location",
  +                            refTarget.getValue().toString());
  +                           
  +                    // Determine the appropriate status code.
  +                    boolean permanent
  +                            = revisionDescriptor.propertyValueContains(
  +                            P_REDIRECT_LIFETIME, "permanent");
  +                    if (permanent) {
  +                        resp.setStatus(WebdavStatus.SC_MOVED_PERMANENTLY);
  +                        resp.addHeader(H_CACHE_CONTROL, PRIVATE_CACHE);
  +                    }
  +                    else {
  +                        resp.setStatus(WebdavStatus.SC_MOVED_TEMPORARILY);
  +                        resp.addHeader(H_CACHE_CONTROL, NO_CACHE);
  +                    }
  +
  +                    // Set this flag so that we don't attempt to execute the
  +                    // request on the redirect reference itself.
  +                    responseIsRedirected = true;
  +                }
  +            }
  +            catch (ObjectNotFoundException notFound) {
  +                token.getLogger().log("Error while trying to send redirect",
  +                        notFound, LOG_CHANNEL, Logger.ERROR);
  +            }
  +        }
  +        if (!responseIsRedirected) {
  +            executeRequest();
  +        }
  +    }
  +    
       // --------------------------------------------------------- Public 
Methods
   
   
  @@ -921,6 +961,33 @@
                   "sequential-mode"));
       }
   
  +    /**
  +     * Checks if Slide is configured to internally repeat a request if it 
conflicts with other
  +     * concurrent ones.
  +     */
  +    protected boolean isRepeatUponConflict() {
  +        return 
"true".equalsIgnoreCase(token.getNamespaceConfig().getParameter(
  +                "repeat-upon-conflict"));
  +    }
  +    
  +    /**
  +     * Checks if Slide is configured to internally repeat a request if it 
conflicts with other
  +     * concurrent ones.
  +     */
  +    protected int getMaxRetryRepeats() {
  +        String maxRepeat = 
token.getNamespaceConfig().getParameter("max-retry-repeat");
  +        if (maxRepeat != null) {
  +            try {
  +                int repeats = Integer.parseInt(maxRepeat);
  +                return repeats;
  +            } catch (NumberFormatException nfe) {
  +                token.getLogger().log("max-retry-repeat must be an integer, 
using default",
  +                        LOG_CHANNEL_LOCKING, Logger.WARNING);
  +            }
  +        }
  +        return DEFAULT_MAX_RETRY_REPEATS;
  +    }
  +    
       protected void assureGlobalLocks() {
           if (this instanceof FineGrainedLockingMethod && 
isFineGrainSequential()) {
               synchronized (ATOMIC_LOCKING_MONITOR) {
  
  
  
  1.17      +7 -4      
jakarta-slide/src/stores/org/apache/slide/store/txfile/AbstractTxFileStoreService.java
  
  Index: AbstractTxFileStoreService.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-slide/src/stores/org/apache/slide/store/txfile/AbstractTxFileStoreService.java,v
  retrieving revision 1.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- AbstractTxFileStoreService.java   9 Aug 2004 09:35:20 -0000       1.16
  +++ AbstractTxFileStoreService.java   7 Dec 2004 17:03:02 -0000       1.17
  @@ -38,6 +38,7 @@
   import javax.transaction.xa.XAResource;
   import javax.transaction.xa.Xid;
   
  +import org.apache.slide.store.ConcurrencyConflictException;
   import org.apache.slide.util.logger.TxLogger;
   import org.apache.slide.util.logger.Logger;
   
  @@ -408,7 +409,9 @@
                   getLogChannel(),
                   Logger.INFO);
   
  -            throw new ServiceAccessException(this, new 
ConflictException(uri));
  +//            throw new ServiceAccessException(this, new 
ConflictException(uri));
  +            throw new 
ConcurrencyConflictException(((ResourceManagerException) cause).getStatus(),
  +                    ((ResourceManagerException) cause).getMessage(), uri);
   
           } else {
   
  
  
  
  1.1                  
jakarta-slide/src/share/org/apache/slide/store/ConcurrencyConflictException.java
  
  Index: ConcurrencyConflictException.java
  ===================================================================
  /*
   * $Header: 
/home/cvs/jakarta-slide/src/share/org/apache/slide/store/ConcurrencyConflictException.java,v
 1.1 2004/12/07 17:03:03 ozeigermann Exp $
   * $Revision: 1.1 $
   * $Date: 2004/12/07 17:03:03 $
   *
   * ====================================================================
   *
   * Copyright 1999-2002 The Apache Software Foundation 
   *
   * Licensed 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.slide.store;
  
  import java.sql.SQLException;
  
  /**
   * Exception gets thrown from the store layer upon failure caused by
   * other concurrent requests. Such failures include deadlocks, unserializable
   * transactions and other spurious behaviour caused by insufficient isolation.
   *
   * @version $Revision: 1.1 $
   */
  public class ConcurrencyConflictException extends Error {
      
      protected int errorCode;
      protected String uri;
      
      public ConcurrencyConflictException(int errorCode, String message, String 
uri) {
          super(message);
          this.errorCode = errorCode;
          this.uri = uri;
      }
  
      public ConcurrencyConflictException(SQLException e, String uri) {
          this(e.getErrorCode(), e.getMessage(), uri);
      }
  
      public String toString() {
          StringBuffer buf = new StringBuffer();
          
          if (uri != null) {
              buf.append(uri).append(": ");
          }
          if (getMessage() != null) {
              buf.append(getMessage());
          }
          if (errorCode != -1) {
              buf.append("(").append(errorCode).append(")");
          }
          return buf.toString();
      }
      /**
       * @return Returns the errorCode.
       */
      public int getErrorCode() {
          return errorCode;
      }
      /**
       * @return Returns the uri.
       */
      public String getUri() {
          return uri;
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to