Oooops,

there still seems to be a problem with this. When a PUT fails then the
stream containing the content will be empty, so you can not repeat it.
I guess I will introduce a new parameter that makes the content stream
into a tmp file for multiple access...

Is this a good idea?

Oliver

On Tue, 7 Dec 2004 18:17:33 +0100, Oliver Zeigermann
<[EMAIL PROTECTED]> wrote:
> Folks,
> 
> everyone who has watched some of my evil commits knows my style:
> Simple and dirty. This one is no different. I had to make
> ConcurrencyConflictException an error to let it come through untouched
> to the abstract request. A cleaner solution would be to add the
> exception to all store methods and pass it up properly, but this would
> cause so many API incompatibilites that it should be deferred to 3.0
> or so.
> 
> For now, any better ideas?
> 
> Oliver
> 
> On 7 Dec 2004 17:03:03 -0000, [EMAIL PROTECTED]
> 
> 
> <[EMAIL PROTECTED]> wrote:
> > 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]
> >
> >
>

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

Reply via email to