You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by un...@apache.org on 2014/09/17 13:20:50 UTC

svn commit: r1625518 - in /jackrabbit/trunk: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/ jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/ jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/ jackrabbit-d...

Author: unico
Date: Wed Sep 17 11:20:49 2014
New Revision: 1625518

URL: http://svn.apache.org/r1625518
Log:
JCR-3811 Allow retrying of failed journal entry database inserts.
 - Add a new ResettableTempFileInputStream that is capable of being reset to the beginning of the stream in order to allow re-reading
 - Simplify TempFileInputStream to only be responsible for removing the temporary file when it is closed
 - Fix bug in ConnectionHelper where resources were not cleaned up when a SQL call would fail in batch mode
 - Fix bug in DbDataStore where temporary file was never removed in addRecord

Added:
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStream.java
    jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/
    jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStreamTest.java
    jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/TempFileInputStreamTest.java
Removed:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TempFileInputStreamTest.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
    jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java?rev=1625518&r1=1625517&r2=1625518&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AppendRecord.java Wed Sep 17 11:20:49 2014
@@ -16,19 +16,19 @@
  */
 package org.apache.jackrabbit.core.journal;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
+import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.BufferedOutputStream;
+
+import org.apache.jackrabbit.core.data.db.ResettableTempFileInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Default temporary record used for appending to some journal.
@@ -298,7 +298,7 @@ public class AppendRecord extends Abstra
     private InputStream openInput() throws JournalException {
         if (file != null) {
             try {
-                return new FileInputStream(file);
+                return new ResettableTempFileInputStream(file);
             } catch (IOException e) {
                 String msg = "Unable to open file input on: " + file.getPath();
                 throw new JournalException(msg, e);

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java?rev=1625518&r1=1625517&r2=1625518&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java Wed Sep 17 11:20:49 2014
@@ -48,7 +48,6 @@ public class TestAll extends TestCase {
         suite.addTestSuite(NodeTypeTest.class);
         suite.addTestSuite(OpenFilesTest.class);
         suite.addTestSuite(PersistenceManagerIteratorTest.class);
-        suite.addTestSuite(TempFileInputStreamTest.class);
         suite.addTestSuite(TestTwoGetStreams.class);
         suite.addTestSuite(WriteWhileReadingTest.class);
         suite.addTestSuite(GCSubtreeMoveTest.class);

Modified: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java?rev=1625518&r1=1625517&r2=1625518&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java (original)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/DbDataStore.java Wed Sep 17 11:20:49 2014
@@ -16,6 +16,7 @@
  */
 package org.apache.jackrabbit.core.data.db;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.input.CountingInputStream;
 import org.apache.jackrabbit.core.data.AbstractDataStore;
 import org.apache.jackrabbit.core.data.DataIdentifier;
@@ -35,8 +36,10 @@ import org.slf4j.LoggerFactory;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.lang.ref.WeakReference;
 import java.security.DigestInputStream;
 import java.security.MessageDigest;
@@ -349,7 +352,7 @@ public class DbDataStore extends Abstrac
             } else if (STORE_TEMP_FILE.equals(storeStream)) {
                 File temp = moveToTempFile(in);
                 long length = temp.length();
-                wrapper = new StreamWrapper(new TempFileInputStream(temp, true), length);
+                wrapper = new StreamWrapper(new ResettableTempFileInputStream(temp), length);
             } else {
                 throw new DataStoreException("Unsupported stream store algorithm: " + storeStream);
             }
@@ -471,10 +474,20 @@ public class DbDataStore extends Abstrac
      */
     private File moveToTempFile(InputStream in) throws IOException {
         File temp = File.createTempFile("dbRecord", null);
-        TempFileInputStream.writeToFileAndClose(in, temp);
+        writeToFileAndClose(in, temp);
         return temp;
     }
 
+    private void writeToFileAndClose(InputStream in, File file) throws IOException {
+        OutputStream out = new FileOutputStream(file);
+        try {
+            IOUtils.copy(in, out);
+        } finally {
+            IOUtils.closeQuietly(out);
+            IOUtils.closeQuietly(in);
+        }
+    }
+
     public synchronized void deleteRecord(DataIdentifier identifier) throws DataStoreException {
         try {
             conHelper.exec(deleteSQL, identifier.toString());
@@ -586,7 +599,7 @@ public class DbDataStore extends Abstrac
             } 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, false));
+                stream = new BufferedInputStream(new TempFileInputStream(temp));
                 DbUtility.close(rs);
             } else {
                 stream = new BufferedInputStream(stream);

Added: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStream.java?rev=1625518&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStream.java (added)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStream.java Wed Sep 17 11:20:49 2014
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.core.data.db;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+/**
+ * TempFileInputStream that can be reset in order to allow the
+ * ConnectionHelper to retry SQL execution in case of failure.
+ */
+public class ResettableTempFileInputStream extends TempFileInputStream {
+
+    private final FileChannel fileChannel;
+    private long mark = 0;
+
+    public ResettableTempFileInputStream(final File file) throws FileNotFoundException {
+        this(new FileInputStream(file), file);
+    }
+
+    private ResettableTempFileInputStream(final FileInputStream in, final File file) {
+        super(in, file);
+        this.fileChannel = in.getChannel();
+    }
+
+    @Override
+    public boolean markSupported() {
+        return true;
+    }
+
+    @Override
+    public synchronized void mark(int readlimit) {
+        try {
+            mark = fileChannel.position();
+        } catch (IOException ex) {
+            mark = -1;
+        }
+    }
+
+    @Override
+    public synchronized void reset() throws IOException {
+        if (mark == -1) {
+            throw new IOException("Mark failed");
+        }
+        fileChannel.position(mark);
+    }
+}

Modified: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java?rev=1625518&r1=1625517&r2=1625518&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java (original)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/data/db/TempFileInputStream.java Wed Sep 17 11:20:49 2014
@@ -16,133 +16,42 @@
  */
 package org.apache.jackrabbit.core.data.db;
 
-import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
+import java.io.FilterInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.input.AutoCloseInputStream;
+import org.apache.commons.io.input.ClosedInputStream;
 
 /**
  * An input stream from a temporary file. The file is deleted when the stream is
- * closed, fully read, or garbage collected.
- * <p>
- * This class does not support mark/reset. It is always to be wrapped
- * using a BufferedInputStream.
+ * closed or garbage collected.
  */
-public class TempFileInputStream extends AutoCloseInputStream {
+public class TempFileInputStream extends FilterInputStream {
 
     private final File file;
-    private boolean closed;
-    private boolean delayedResourceCleanup = true;
 
-    /**
-     * Copy the data to a file and close the input stream afterwards.
-     *
-     * @param in the input stream
-     * @param file the target file
-     * @return the size of the file
-     */
-    public static long writeToFileAndClose(InputStream in, File file) throws IOException {
-        OutputStream out = new FileOutputStream(file);
-        IOUtils.copy(in, out);
-        out.close();
-        in.close();
-        return file.length();
+    public TempFileInputStream(File file) throws FileNotFoundException {
+        this(new FileInputStream(file), file);
     }
 
-    /**
-     * Construct a new temporary file input stream.
-     * 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, boolean delayedResourceCleanup) throws FileNotFoundException {
-        super(new BufferedInputStream(new FileInputStream(file)));
+    protected TempFileInputStream(FileInputStream in, File file) {
+        super(in);
         this.file = file;
-        this.delayedResourceCleanup = delayedResourceCleanup;
-    }
-
-    public File getFile() {
-    	return file;
-    }
-    
-    public void deleteFile() {
-	    file.delete();
-	}
-
-	private int closeIfEOF(int read) throws IOException {
-        if (read < 0) {
-            close();
-        }
-        return read;
     }
 
+    @Override
     public void close() throws IOException {
-        if (!closed) {
-            in.close();
-            if (!delayedResourceCleanup) {
-            	deleteFile();
-            }
-            closed = true;
-        }
-    }
-
-    public int available() throws IOException {
-        return in.available();
-    }
-
-    /**
-     * This method does nothing.
-     */
-    public void mark(int readlimit) {
-        // do nothing
-    }
-
-    /**
-     * Check whether mark and reset are supported.
-     *
-     * @return false
-     */
-    public boolean markSupported() {
-        return false;
-    }
-
-    public long skip(long n) throws IOException {
-        return in.skip(n);
-    }
-
-    public void reset() throws IOException {
-        in.reset();
-    }
-
-    public int read(byte[] b, int off, int len) throws IOException {
-        if (closed) {
-            return -1;
-        }
-        return closeIfEOF(in.read(b, off, len));
-    }
-
-    public int read(byte[] b) throws IOException {
-        if (closed) {
-            return -1;
-        }
-        return closeIfEOF(in.read(b));
+        in.close();
+        in = new ClosedInputStream();
+        file.delete();
     }
 
-    public int read() throws IOException {
-        if (closed) {
-            return -1;
-        }
-        return closeIfEOF(in.read());
+    @Override
+    protected void finalize() throws Throwable {
+        close();
+        super.finalize();
     }
 
 }

Modified: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java?rev=1625518&r1=1625517&r2=1625518&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java (original)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/ConnectionHelper.java Wed Sep 17 11:20:49 2014
@@ -531,38 +531,40 @@ public class ConnectionHelper {
     	}
     	
         public final T doTry() throws SQLException {
-            if (inBatchMode()) {
-                return call();
-            } else {
-                boolean sleepInterrupted = false;
-                int failures = 0;
-                SQLException lastException = null;
-                while (!sleepInterrupted && (blockOnConnectionLoss || failures <= RETRIES)) {
-                    try {
-                    	T object = call(); 
-                        cleanupParamResources();
-                        return object;
-                    } catch (SQLException e) {
-                        lastException = e;
-                    }
-                    log.error("Failed to execute SQL (stacktrace on DEBUG log level): " + lastException);
-                    log.debug("Failed to execute SQL", lastException);
-                    if (!resetParamResources()) {
-                        break; // don't try again if streams cannot be reset
-                    }
-                    failures++;
-                    if (blockOnConnectionLoss || failures <= RETRIES) { // if we're going to try again
+            try {
+                if (inBatchMode()) {
+                    return call();
+                } else {
+                    boolean sleepInterrupted = false;
+                    int failures = 0;
+                    SQLException lastException = null;
+                    while (!sleepInterrupted && (blockOnConnectionLoss || failures <= RETRIES)) {
                         try {
-                            Thread.sleep(SLEEP_BETWEEN_RETRIES_MS);
-                        } catch (InterruptedException e1) {
-                            Thread.currentThread().interrupt();
-                            sleepInterrupted = true;
-                            log.error("Interrupted: canceling retry");
+                            return call();
+                        } catch (SQLException e) {
+                            lastException = e;
+                        }
+                        log.error("Failed to execute SQL (stacktrace on DEBUG log level): " + lastException);
+                        log.debug("Failed to execute SQL", lastException);
+                        if (!resetParamResources()) {
+                            log.warn("Could not reset parameters: not retrying SQL call");
+                            break;
+                        }
+                        failures++;
+                        if (blockOnConnectionLoss || failures <= RETRIES) { // if we're going to try again
+                            try {
+                                Thread.sleep(SLEEP_BETWEEN_RETRIES_MS);
+                            } catch (InterruptedException e1) {
+                                Thread.currentThread().interrupt();
+                                sleepInterrupted = true;
+                                log.error("Interrupted: canceling retry");
+                            }
                         }
                     }
+                    throw lastException;
                 }
+            } finally {
                 cleanupParamResources();
-                throw lastException;
             }
         }
 
@@ -570,15 +572,13 @@ public class ConnectionHelper {
 
 		/**
 		 * 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();
+		            wrapper.closeStream();
 		        }
 		    }
 		}
@@ -589,7 +589,6 @@ public class ConnectionHelper {
                 if (p instanceof StreamWrapper) {
                     StreamWrapper wrapper = (StreamWrapper) p;
                     if(!wrapper.resetStream()) {
-                        wrapper.cleanupResources();
                         return false;
                     }
                 }

Modified: jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java?rev=1625518&r1=1625517&r2=1625518&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java (original)
+++ jackrabbit/trunk/jackrabbit-data/src/main/java/org/apache/jackrabbit/core/util/db/StreamWrapper.java Wed Sep 17 11:20:49 2014
@@ -16,18 +16,17 @@
  */
 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.apache.commons.io.input.CloseShieldInputStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class StreamWrapper {
 
-    static Logger log = LoggerFactory.getLogger(StreamWrapper.class);
+    private final Logger log = LoggerFactory.getLogger(StreamWrapper.class);
 
     private InputStream stream;
     private final long size;
@@ -37,8 +36,7 @@ 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
      */
@@ -48,48 +46,30 @@ public class StreamWrapper {
     }
     
     public InputStream getStream() {
-        if (stream instanceof TempFileInputStream) {
-            return new BufferedInputStream(stream);
-        }
-        return stream;
+        return new CloseShieldInputStream(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");
-        	}
+    public void closeStream() {
+        try {
+            stream.close();
+        } catch (IOException e) {
+            log.error("Error while closing stream", e);
         }
-	}
+    }
 
     /**
      * Resets the internal InputStream that it could be re-read.<br>
      * Is used from {@link RetryManager} if a {@link SQLException} has occurred.<br>
+     * It relies on the assumption that the InputStream was not marked anywhere
+     * during reading so that resetting it moves the cursor to the beginning of the stream.
      *
      * @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);
-    		}
-    	}
         try {
             stream.reset();
             return true;

Added: jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStreamTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStreamTest.java?rev=1625518&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStreamTest.java (added)
+++ jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/ResettableTempFileInputStreamTest.java Wed Sep 17 11:20:49 2014
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.core.data.db;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import junit.framework.TestCase;
+import static org.junit.Assume.assumeTrue;
+
+public class ResettableTempFileInputStreamTest extends TestCase {
+
+    public void testResetStreamAllowsReadAgain() throws Exception {
+        final File tmp = createTemporaryFileWithContents(new byte[1]);
+        ResettableTempFileInputStream in = null;
+        try {
+            in = new ResettableTempFileInputStream(tmp);
+            assertEquals(0, in.read());
+            assertEquals(-1, in.read());
+            in.reset();
+            assertEquals(0, in.read());
+            assertEquals(-1, in.read());
+        } finally {
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+    public void testMarkStreamAllowsReadFromMark() throws Exception {
+        final File tmp = createTemporaryFileWithContents(createTestByteArray());
+        ResettableTempFileInputStream in = null;
+        try {
+            in = new ResettableTempFileInputStream(tmp);
+            assumeTrue(in.read(new byte[5]) == 5);
+            in.mark(Integer.MAX_VALUE);
+            assumeTrue(in.read(new byte[5]) == 5);
+            in.reset();
+            assertEquals(5, in.read());
+        } finally {
+            IOUtils.closeQuietly(in);
+        }
+    }
+
+    private File createTemporaryFileWithContents(byte[] data) throws IOException {
+        final File tmp = File.createTempFile("test", ".bin");
+        FileUtils.writeByteArrayToFile(tmp, data);
+        return tmp;
+    }
+
+    private byte[] createTestByteArray() {
+        byte[] bytes = new byte[10];
+        for (int i = 0; i < 10; i++) {
+            bytes[i] = (byte) i;
+        }
+        return bytes;
+    }
+}

Added: jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/TempFileInputStreamTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/TempFileInputStreamTest.java?rev=1625518&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/TempFileInputStreamTest.java (added)
+++ jackrabbit/trunk/jackrabbit-data/src/test/java/org/apache/jackrabbit/core/data/db/TempFileInputStreamTest.java Wed Sep 17 11:20:49 2014
@@ -0,0 +1,26 @@
+package org.apache.jackrabbit.core.data.db;
+
+import java.io.File;
+
+import junit.framework.TestCase;
+
+public class TempFileInputStreamTest extends TestCase {
+
+    private File tmp;
+    private TempFileInputStream in;
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        tmp = File.createTempFile("test", ".bin");
+        in = new TempFileInputStream(tmp);
+    }
+
+    public void testFileIsDeletedWhenStreamIsClosed() throws Exception {
+        assertTrue(tmp.exists());
+        in.close();
+        assertFalse(tmp.exists());
+    }
+
+}