You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ju...@apache.org on 2012/08/03 11:48:55 UTC

svn commit: r1368852 - in /jackrabbit/branches/2.4: ./ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/

Author: jukka
Date: Fri Aug  3 09:48:54 2012
New Revision: 1368852

URL: http://svn.apache.org/viewvc?rev=1368852&view=rev
Log:
2.4: Merged revisions 1349185 and 1358543 (JCR-3318 and JCR-3377)

Modified:
    jackrabbit/branches/2.4/   (props changed)
    jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
    jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java
    jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
    jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java
    jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java
    jackrabbit/branches/2.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TempFileInputStreamTest.java

Propchange: jackrabbit/branches/2.4/
------------------------------------------------------------------------------
  Merged /jackrabbit/trunk:r1349185,1358543

Modified: jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java?rev=1368852&r1=1368851&r2=1368852&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java Fri Aug  3 09:48:54 2012
@@ -346,9 +346,8 @@ public class DbDataStore implements Data
                 wrapper = new StreamWrapper(in, Integer.MAX_VALUE);
             } else if (STORE_TEMP_FILE.equals(storeStream)) {
                 File temp = moveToTempFile(in);
-                fileInput = new BufferedInputStream(new TempFileInputStream(temp));
                 long length = temp.length();
-                wrapper = new StreamWrapper(fileInput, length);
+                wrapper = new StreamWrapper(new TempFileInputStream(temp, true), length);
             } else {
                 throw new DataStoreException("Unsupported stream store algorithm: " + storeStream);
             }
@@ -579,7 +578,7 @@ public class DbDataStore implements Data
             } else if (copyWhenReading) {
                 // If we copy while reading, create a temp file and close the stream
                 File temp = moveToTempFile(stream);
-                stream = new BufferedInputStream(new TempFileInputStream(temp));
+                stream = new BufferedInputStream(new TempFileInputStream(temp, false));
                 DbUtility.close(rs);
             } else {
                 stream = new BufferedInputStream(stream);

Modified: jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java?rev=1368852&r1=1368851&r2=1368852&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java Fri Aug  3 09:48:54 2012
@@ -39,6 +39,7 @@ public class TempFileInputStream extends
 
     private final File file;
     private boolean closed;
+    private boolean delayedResourceCleanup = true;
 
     /**
      * Copy the data to a file and close the input stream afterwards.
@@ -57,17 +58,28 @@ public class TempFileInputStream extends
 
     /**
      * Construct a new temporary file input stream.
-     * The file is deleted if the input stream is closed or fully read.
+     * The file is deleted if the input stream is closed or fully read and 
+     * delayedResourceCleanup was set to true. Otherwise you must call {@link #deleteFile()}.
      * Deleting is only attempted once.
      *
      * @param file the temporary file
+     * @param delayedResourceCleanup
      */
-    public TempFileInputStream(File file) throws FileNotFoundException {
+    public TempFileInputStream(File file, boolean delayedResourceCleanup) throws FileNotFoundException {
         super(new BufferedInputStream(new FileInputStream(file)));
         this.file = file;
+        this.delayedResourceCleanup = delayedResourceCleanup;
     }
 
-    private int closeIfEOF(int read) throws IOException {
+    public File getFile() {
+    	return file;
+    }
+    
+    public void deleteFile() {
+	    file.delete();
+	}
+
+	private int closeIfEOF(int read) throws IOException {
         if (read < 0) {
             close();
         }
@@ -77,7 +89,9 @@ public class TempFileInputStream extends
     public void close() throws IOException {
         if (!closed) {
             in.close();
-            file.delete();
+            if (!delayedResourceCleanup) {
+            	deleteFile();
+            }
             closed = true;
         }
     }

Modified: jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java?rev=1368852&r1=1368851&r2=1368852&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java Fri Aug  3 09:48:54 2012
@@ -278,7 +278,7 @@ public class ConnectionHelper {
      * @throws SQLException on error
      */
     public final void exec(final String sql, final Object... params) throws SQLException {
-        new RetryManager<Void>() {
+        new RetryManager<Void>(params) {
 
             @Override
             protected Void call() throws SQLException {
@@ -316,7 +316,7 @@ public class ConnectionHelper {
      * @throws SQLException on error
      */
     public final int update(final String sql, final Object... params) throws SQLException {
-        return new RetryManager<Integer>() {
+        return new RetryManager<Integer>(params) {
 
             @Override
             protected Integer call() throws SQLException {
@@ -363,11 +363,11 @@ public class ConnectionHelper {
      */
     public final ResultSet exec(final String sql, final Object[] params, final boolean returnGeneratedKeys,
             final int maxRows) throws SQLException {
-        return new RetryManager<ResultSet>() {
+        return new RetryManager<ResultSet>(params) {
 
             @Override
             protected ResultSet call() throws SQLException {
-                return reallyExec(sql, params, returnGeneratedKeys, maxRows);
+            	return reallyExec(sql, params, returnGeneratedKeys, maxRows);
             }
 
         }.doTry();
@@ -463,7 +463,6 @@ public class ConnectionHelper {
     protected PreparedStatement execute(PreparedStatement stmt, Object[] params) throws SQLException {
         for (int i = 0; params != null && i < params.length; i++) {
             Object p = params[i];
-            // FIXME: what about already consumed input streams when in a retry?
             if (p instanceof StreamWrapper) {
                 StreamWrapper wrapper = (StreamWrapper) p;
                 stmt.setBinaryStream(i + 1, wrapper.getStream(), (int) wrapper.getSize());
@@ -471,17 +470,39 @@ public class ConnectionHelper {
                 stmt.setObject(i + 1, p);
             }
         }
-        stmt.execute();
+        try {
+        	stmt.execute();
+        } catch (SQLException e) {
+        	//Reset Stream for retry ...
+            for (int i = 0; params != null && i < params.length; i++) {
+                Object p = params[i];
+                if (p instanceof StreamWrapper) {
+                    StreamWrapper wrapper = (StreamWrapper) p;
+                    if(!wrapper.resetStream()) {
+                    	wrapper.cleanupResources();
+                    	throw new RuntimeException("Unable to reset the Stream.");
+                    }
+                }
+            }
+        	throw e;
+        }
         return stmt;
     }
 
     /**
      * This class encapsulates the logic to retry a method invocation if it threw an SQLException.
+     * The RetryManager must cleanup the Params it will get.
      *
      * @param <T> the return type of the method which is retried if it failed
      */
     public abstract class RetryManager<T> {
 
+    	private Object[] params;
+    	
+    	public RetryManager(Object[] params) {
+    		this.params = params;
+    	}
+    	
         public final T doTry() throws SQLException {
             if (inBatchMode()) {
                 return call();
@@ -491,7 +512,9 @@ public class ConnectionHelper {
                 SQLException lastException = null;
                 while (!sleepInterrupted && (blockOnConnectionLoss || failures <= RETRIES)) {
                     try {
-                        return call();
+                    	T object = call(); 
+                        cleanupParamResources();
+                        return object;
                     } catch (SQLException e) {
                         lastException = e;
                     }
@@ -508,10 +531,26 @@ public class ConnectionHelper {
                         }
                     }
                 }
+                cleanupParamResources();
                 throw lastException;
             }
         }
 
         protected abstract T call() throws SQLException;
+
+		/**
+		 * Cleans up the Parameter resources that are not automatically closed or deleted.
+		 *
+		 * @param params
+		 */
+		protected void cleanupParamResources() {
+		    for (int i = 0; params != null && i < params.length; i++) {
+		        Object p = params[i];
+		        if (p instanceof StreamWrapper) {
+		            StreamWrapper wrapper = (StreamWrapper) p;
+		            wrapper.cleanupResources();
+		        }
+		    }
+		}
     }
 }

Modified: jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java?rev=1368852&r1=1368851&r2=1368852&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/DbUtility.java Fri Aug  3 09:48:54 2012
@@ -71,7 +71,7 @@ public final class DbUtility {
                 logException("failed to close Statement", e);
             } finally {
                 try {
-                    if (con != null) {
+                    if (con != null && !con.isClosed()) {
                         con.close();
                     }
                 } catch (SQLException e) {

Modified: jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java?rev=1368852&r1=1368851&r2=1368852&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java Fri Aug  3 09:48:54 2012
@@ -16,11 +16,20 @@
  */
 package org.apache.jackrabbit.core.util.db;
 
+import java.io.BufferedInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.sql.SQLException;
+
+import org.apache.jackrabbit.core.data.db.TempFileInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class StreamWrapper {
 
-    private final InputStream stream;
+    static Logger log = LoggerFactory.getLogger(StreamWrapper.class);
+
+    private InputStream stream;
     private final long size;
 
     /**
@@ -28,7 +37,8 @@ public class StreamWrapper {
      * safely be passed as a parameter to the {@link ConnectionHelper#exec(String, Object...)},
      * {@link ConnectionHelper#exec(String, Object[], boolean, int)} and
      * {@link ConnectionHelper#update(String, Object[])} methods.
-     *
+     * If the wrapped Stream is a {@link TempFileInputStream} it will be wrapped again by a {@link BufferedInputStream}.
+     * 
      * @param in the InputStream to wrap
      * @param size the size of the input stream
      */
@@ -38,10 +48,49 @@ public class StreamWrapper {
     }
     
     public InputStream getStream() {
+        if (stream instanceof TempFileInputStream) {
+            return new BufferedInputStream(stream);
+        }
         return stream;
     }
     
     public long getSize() {
         return size;
     }
+
+    /**
+     * Cleans up the internal Resources
+     */
+	public void cleanupResources() {
+        if (stream instanceof TempFileInputStream) {
+        	try {
+        		stream.close();
+        		((TempFileInputStream) stream).deleteFile();
+        	} catch (IOException e) {
+        		log.warn("Unable to cleanup the TempFileInputStream");
+        	}
+        }
+	}
+
+    /**
+     * Resets the internal InputStream that it could be re-read.<br>
+     * Is used from {@link RetryManager} if a {@link SQLException} has occurred.<br>
+     * At the moment only a {@link TempFileInputStream} can be reseted.
+     * 
+     * @return returns true if it was able to reset the Stream
+     */
+    public boolean resetStream() {
+    	if (stream instanceof TempFileInputStream) {
+    		try {
+	    		TempFileInputStream tempFileInputStream = (TempFileInputStream) stream;
+	    		// Close it if it is not already closed ...
+	    		tempFileInputStream.close();
+    			stream = new TempFileInputStream(tempFileInputStream.getFile(), true);
+    			return true;
+    		} catch (Exception e) {
+    			log.warn("Failed to create a new TempFileInputStream", e);
+    		}
+    	}
+    	return false;
+	}
 }

Modified: jackrabbit/branches/2.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TempFileInputStreamTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/branches/2.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TempFileInputStreamTest.java?rev=1368852&r1=1368851&r2=1368852&view=diff
==============================================================================
--- jackrabbit/branches/2.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TempFileInputStreamTest.java (original)
+++ jackrabbit/branches/2.4/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TempFileInputStreamTest.java Fri Aug  3 09:48:54 2012
@@ -33,7 +33,7 @@ public class TempFileInputStreamTest ext
     public void testReadPastEOF() throws IOException {
         File temp = File.createTempFile("test", null);
         TempFileInputStream.writeToFileAndClose(new ByteArrayInputStream(new byte[1]), temp);
-        TempFileInputStream in = new TempFileInputStream(temp);
+        TempFileInputStream in = new TempFileInputStream(temp, false);
         assertEquals(0, in.read());
         assertEquals(-1, in.read());
         assertEquals(-1, in.read());
@@ -44,7 +44,7 @@ public class TempFileInputStreamTest ext
     public void testMarkReset() throws IOException {
         File temp = File.createTempFile("test", null);
         TempFileInputStream.writeToFileAndClose(new ByteArrayInputStream(new byte[10]), temp);
-        InputStream in = new BufferedInputStream(new TempFileInputStream(temp));
+        InputStream in = new BufferedInputStream(new TempFileInputStream(temp, false));
         in.mark(100);
         for (int i = 0; i < 10; i++) {
             assertEquals(0, in.read());