not sure if this is a related topic or if the problem has been fixed but when uploading a file for the very first time with an inputstream and the method webdavResource.putMethod(filePath+fileName,uploadFile.getInputStream()); with autoversioning enabled (Slide v2.1b2) the content length is always -1.
But if you upload a file to the same path again the version is increased and the content length is correct!
Is this a bug that has been fixed?
best regards Eiki, idega.
On 13.12.2004, at 16:00, Oliver Zeigermann wrote:
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]
Best Regards
Eirikur S. Hrafnsson, [EMAIL PROTECTED] Chief Software Engineer Idega Software http://www.idega.com
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
