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]