You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2018/09/18 09:33:19 UTC

svn commit: r1841209 - in /jackrabbit/oak/trunk: oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/ oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/

Author: mduerig
Date: Tue Sep 18 09:33:19 2018
New Revision: 1841209

URL: http://svn.apache.org/viewvc?rev=1841209&view=rev
Log:
OAK-7760: Use NIO in the implementation of FileAccess.Mapped#read

Modified:
    jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/IOUtils.java
    jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java
    jackrabbit/oak/trunk/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/IOUtilsTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/FileAccess.java

Modified: jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/IOUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/IOUtils.java?rev=1841209&r1=1841208&r2=1841209&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/IOUtils.java (original)
+++ jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/IOUtils.java Tue Sep 18 09:33:19 2018
@@ -22,6 +22,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
 import java.util.Locale;
 
 /**
@@ -44,7 +46,7 @@ public final class IOUtils {
      * @param buffer the output buffer
      * @param off    the offset in the buffer
      * @param max    the number of bytes to read at most
-     * @return the number of bytes read, 0 meaning EOF
+     * @return the number of bytes read, 0 meaning EOF or no space in buffer
      * @throws java.io.IOException If an error occurs.
      */
     public static int readFully(InputStream in, byte[] buffer, int off, int max) throws IOException {
@@ -61,6 +63,31 @@ public final class IOUtils {
         }
         return result;
     }
+
+    /**
+     * Try to read the given number of bytes starting at the specified position
+     * into the buffer. This method reads until the maximum number of bytes have
+     * been read or until the end of the channel.
+     *
+     * @param channel     the input channel
+     * @param position    the position to start reading from the channel
+     * @param buffer      the output buffer
+     * @return the number of bytes read, 0 meaning EOF or no space in buffer
+     * @throws java.io.IOException If an error occurs.
+     */
+    public static int readFully(FileChannel channel, int position, ByteBuffer buffer)
+    throws IOException {
+        int result = 0;
+        while (buffer.remaining() > 0) {
+            int count = channel.read(buffer, position);
+            if (count < 0) {
+                break;
+            }
+            result += count;
+            position += count;
+        }
+        return result;
+    }
 
     /**
      * Skip a number of bytes in an input stream.

Modified: jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java?rev=1841209&r1=1841208&r2=1841209&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java Tue Sep 18 09:33:19 2018
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.1.1")
+@Version("1.2.1")
 package org.apache.jackrabbit.oak.commons;
 
 import org.osgi.annotation.versioning.Version;

Modified: jackrabbit/oak/trunk/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/IOUtilsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/IOUtilsTest.java?rev=1841209&r1=1841208&r2=1841209&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/IOUtilsTest.java (original)
+++ jackrabbit/oak/trunk/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/IOUtilsTest.java Tue Sep 18 09:33:19 2018
@@ -16,12 +16,17 @@
  */
 package org.apache.jackrabbit.oak.commons;
 
+import static org.apache.commons.io.FileUtils.writeByteArrayToFile;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.EOFException;
+import java.io.File;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicInteger;
 
@@ -33,6 +38,90 @@ import junit.framework.TestCase;
  */
 public class IOUtilsTest extends TestCase {
 
+    private File testFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        testFile = new File("target", "test");
+        writeByteArrayToFile(
+                testFile,
+                new byte[]{0,1,2,3,4,5,6,7});
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        testFile.delete();
+    }
+
+    public void testReadAll() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(8);
+            assertEquals(8, IOUtils.readFully(file.getChannel(), 0, buffer));
+            assertEquals(3, buffer.array()[3]);
+        }
+    }
+
+    public void testReadWithLargeBuffer() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(10);
+            assertEquals(8, IOUtils.readFully(file.getChannel(), 0, buffer));
+            assertEquals(3, buffer.array()[3]);
+        }
+    }
+
+    public void testReadWithSmallBuffer() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(6);
+            assertEquals(6, IOUtils.readFully(file.getChannel(), 0, buffer));
+            assertEquals(3, buffer.array()[3]);
+        }
+    }
+
+    public void testReadWithEmptyBuffer() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(0);
+            assertEquals(0, IOUtils.readFully(file.getChannel(), 0, buffer));
+        }
+    }
+
+    public void testReadAllFromOffset() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(7);
+            assertEquals(7, IOUtils.readFully(file.getChannel(), 1, buffer));
+            assertEquals(4, buffer.array()[3]);
+        }
+    }
+
+    public void testReadWithLargeBufferFromOffset() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(10);
+            assertEquals(7, IOUtils.readFully(file.getChannel(), 1, buffer));
+            assertEquals(4, buffer.array()[3]);
+        }
+    }
+
+    public void testReadWithSmallBufferFromOffset() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(6);
+            assertEquals(6, IOUtils.readFully(file.getChannel(), 1, buffer));
+            assertEquals(4, buffer.array()[3]);
+        }
+    }
+
+    public void testReadWithEmptyBufferFromOffset() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(0);
+            assertEquals(0, IOUtils.readFully(file.getChannel(), 1, buffer));
+        }
+    }
+
+    public void testReadOffsetOutOfBound() throws IOException {
+        try (RandomAccessFile file = new RandomAccessFile(testFile, "r")) {
+            ByteBuffer buffer = ByteBuffer.allocate(10);
+            assertEquals(0, IOUtils.readFully(file.getChannel(), 10, buffer));
+        }
+    }
+
     public void testReadFully() throws IOException {
         final Random r = new Random(1);
         byte[] data = new byte[1000];

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/FileAccess.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/FileAccess.java?rev=1841209&r1=1841208&r2=1841209&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/FileAccess.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tar/FileAccess.java Tue Sep 18 09:33:19 2018
@@ -20,11 +20,14 @@ package org.apache.jackrabbit.oak.segmen
 
 import static com.google.common.base.Preconditions.checkState;
 import static java.nio.channels.FileChannel.MapMode.READ_ONLY;
+import static org.apache.jackrabbit.oak.commons.IOUtils.readFully;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
 import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
 
 /**
  * A wrapper around either memory mapped files or random access files, to allow
@@ -88,9 +91,11 @@ abstract class FileAccess {
     static class Random extends FileAccess {
 
         private final RandomAccessFile file;
+        private final FileChannel channel;
 
         Random(RandomAccessFile file) {
             this.file = file;
+            this.channel = file.getChannel();
         }
 
         @Override
@@ -109,8 +114,10 @@ abstract class FileAccess {
         public synchronized ByteBuffer read(int position, int length)
                 throws IOException {
             ByteBuffer entry = ByteBuffer.allocate(length);
-            file.seek(position);
-            file.readFully(entry.array());
+            if (readFully(channel, position, entry) < length) {
+                throw new EOFException();
+            }
+            entry.flip();
             return entry;
         }