OK, fixed this provisionally. I found this code in the PUT method:
if (contentLength == -1) {
contentLength =
revisionContent.getContentBytes().length;
}
which will buffer the whole content in memory and just added my stuff to it
if (contentLength == -1 || retryUponConflict) {
contentLength =
revisionContent.getContentBytes().length;
}
However, this is not a really good soltution...
Oliver
On Mon, 13 Dec 2004 16:43:33 +0100, Oliver Zeigermann
<[EMAIL PROTECTED]> wrote:
> 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]