Browse Source

Added block-aligned read/write

Sebastian Stenzel 9 years ago
parent
commit
634f176cf9

+ 1 - 1
main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/blockaligned/BlockAlignedFile.java

@@ -21,7 +21,7 @@ class BlockAlignedFile extends DelegatingFile<BlockAlignedReadableFile, BlockAli
 
 	@Override
 	public BlockAlignedWritableFile openWritable() throws UncheckedIOException {
-		return new BlockAlignedWritableFile(delegate.openWritable(), blockSize);
+		return new BlockAlignedWritableFile(delegate.openWritable(), delegate.openReadable(), blockSize);
 	}
 
 }

+ 39 - 5
main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/blockaligned/BlockAlignedReadableFile.java

@@ -5,23 +5,57 @@ import java.nio.ByteBuffer;
 
 import org.cryptomator.filesystem.ReadableFile;
 import org.cryptomator.filesystem.delegating.DelegatingReadableFile;
+import org.cryptomator.io.ByteBuffers;
 
 class BlockAlignedReadableFile extends DelegatingReadableFile {
 
+	private final int blockSize;
+	private final ByteBuffer currentBlockBuffer;
+	private boolean eofReached = false;
+
 	public BlockAlignedReadableFile(ReadableFile delegate, int blockSize) {
 		super(delegate);
+		if (blockSize < 1) {
+			throw new IllegalArgumentException("Invalid block size");
+		}
+		this.blockSize = blockSize;
+		this.currentBlockBuffer = ByteBuffer.allocate(blockSize);
+		this.currentBlockBuffer.flip(); // so the next attempt will read from source.
 	}
 
 	@Override
-	public void position(long position) throws UncheckedIOException {
-		// TODO Auto-generated method stub
-		super.position(position);
+	public void position(long logicalPosition) throws UncheckedIOException {
+		long blockNumber = logicalPosition / blockSize;
+		long physicalPosition = blockNumber * blockSize;
+		super.position(physicalPosition);
+		eofReached = false;
+		readCurrentBlock();
+		int advance = (int) (logicalPosition - physicalPosition);
+		currentBlockBuffer.position(advance);
 	}
 
 	@Override
 	public int read(ByteBuffer target) throws UncheckedIOException {
-		// TODO Auto-generated method stub
-		return super.read(target);
+		int read = -1;
+		while (!eofReached && target.hasRemaining()) {
+			read += ByteBuffers.copy(currentBlockBuffer, target);
+			readCurrentBlockIfNeeded();
+		}
+		return read;
+	}
+
+	private void readCurrentBlockIfNeeded() {
+		if (!currentBlockBuffer.hasRemaining()) {
+			readCurrentBlock();
+		}
+	}
+
+	private void readCurrentBlock() {
+		currentBlockBuffer.clear();
+		if (super.read(currentBlockBuffer) == -1) {
+			eofReached = true;
+		}
+		currentBlockBuffer.flip();
 	}
 
 }

+ 50 - 6
main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/blockaligned/BlockAlignedWritableFile.java

@@ -3,25 +3,69 @@ package org.cryptomator.filesystem.blockaligned;
 import java.io.UncheckedIOException;
 import java.nio.ByteBuffer;
 
+import org.cryptomator.filesystem.ReadableFile;
 import org.cryptomator.filesystem.WritableFile;
 import org.cryptomator.filesystem.delegating.DelegatingWritableFile;
+import org.cryptomator.io.ByteBuffers;
 
 class BlockAlignedWritableFile extends DelegatingWritableFile {
 
-	public BlockAlignedWritableFile(WritableFile delegate, int blockSize) {
+	private final int blockSize;
+	private final ReadableFile readableFile;
+	private final ByteBuffer currentBlockBuffer;
+
+	public BlockAlignedWritableFile(WritableFile delegate, ReadableFile readableFile, int blockSize) {
 		super(delegate);
+		this.readableFile = readableFile;
+		this.blockSize = blockSize;
+		this.currentBlockBuffer = ByteBuffer.allocate(blockSize);
 	}
 
 	@Override
-	public void position(long position) throws UncheckedIOException {
-		// TODO Auto-generated method stub
-		super.position(position);
+	public void position(long logicalPosition) throws UncheckedIOException {
+		long blockNumber = logicalPosition / blockSize;
+		long physicalPosition = blockNumber * blockSize;
+		readableFile.position(physicalPosition);
+		readableFile.read(currentBlockBuffer);
+		int advance = (int) (logicalPosition - physicalPosition);
+		currentBlockBuffer.position(advance);
+		super.position(physicalPosition);
 	}
 
 	@Override
 	public int write(ByteBuffer source) throws UncheckedIOException {
-		// TODO Auto-generated method stub
-		return super.write(source);
+		int written = 0;
+		while (source.hasRemaining()) {
+			currentBlockBuffer.limit(Math.max(currentBlockBuffer.limit(), Math.min(currentBlockBuffer.position() + source.remaining(), currentBlockBuffer.capacity())));
+			written += ByteBuffers.copy(source, currentBlockBuffer);
+			writeCurrentBlockIfNeeded();
+		}
+		return written;
+	}
+
+	@Override
+	public void close() throws UncheckedIOException {
+		writeCurrentBlock();
+		readableFile.close();
+		super.close();
+	}
+
+	private void writeCurrentBlockIfNeeded() {
+		if (!currentBlockBuffer.hasRemaining()) {
+			writeCurrentBlock();
+			readCurrentBlock();
+		}
+	}
+
+	private void writeCurrentBlock() {
+		currentBlockBuffer.rewind();
+		super.write(currentBlockBuffer);
+	}
+
+	private void readCurrentBlock() {
+		currentBlockBuffer.clear();
+		readableFile.read(currentBlockBuffer);
+		currentBlockBuffer.flip();
 	}
 
 }

+ 66 - 0
main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/blockaligned/BlockAlignedReadableFileTest.java

@@ -0,0 +1,66 @@
+package org.cryptomator.filesystem.blockaligned;
+
+import java.nio.ByteBuffer;
+
+import org.bouncycastle.util.Arrays;
+import org.cryptomator.filesystem.File;
+import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.ReadableFile;
+import org.cryptomator.filesystem.WritableFile;
+import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BlockAlignedReadableFileTest {
+
+	@Test(expected = IllegalArgumentException.class)
+	public void testInvalidBlockSize() {
+		@SuppressWarnings(value = {"resource", "unused"})
+		ReadableFile r = new BlockAlignedReadableFile(null, 0);
+	}
+
+	@Test
+	public void testRead() {
+		FileSystem fs = new InMemoryFileSystem();
+		File file = fs.file("test");
+		try (WritableFile w = file.openWritable()) {
+			w.write(ByteBuffer.wrap(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}));
+		}
+
+		for (int i = 1; i < 12; i++) {
+			testRead(file, i);
+		}
+	}
+
+	private void testRead(File file, int blockSize) {
+		try (ReadableFile r = new BlockAlignedReadableFile(file.openReadable(), blockSize)) {
+			ByteBuffer buf = ByteBuffer.allocate(3);
+
+			// 3...
+			r.position(3);
+			r.read(buf);
+			buf.flip();
+			Assert.assertArrayEquals(new byte[] {0x03, 0x04, 0x05}, Arrays.copyOf(buf.array(), buf.remaining()));
+
+			// go on...
+			buf.clear();
+			r.read(buf);
+			buf.flip();
+			Assert.assertArrayEquals(new byte[] {0x06, 0x07, 0x08}, Arrays.copyOf(buf.array(), buf.remaining()));
+
+			// go on till EOF...
+			buf.clear();
+			r.read(buf);
+			buf.flip();
+			Assert.assertArrayEquals(new byte[] {0x09}, Arrays.copyOf(buf.array(), buf.remaining()));
+
+			// back to 4...
+			r.position(4);
+			buf.clear();
+			r.read(buf);
+			buf.flip();
+			Assert.assertArrayEquals(new byte[] {0x04, 0x05, 0x06}, Arrays.copyOf(buf.array(), buf.remaining()));
+		}
+	}
+
+}

+ 42 - 0
main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/blockaligned/BlockAlignedWritableFileTest.java

@@ -0,0 +1,42 @@
+package org.cryptomator.filesystem.blockaligned;
+
+import java.nio.ByteBuffer;
+
+import org.cryptomator.filesystem.File;
+import org.cryptomator.filesystem.FileSystem;
+import org.cryptomator.filesystem.ReadableFile;
+import org.cryptomator.filesystem.WritableFile;
+import org.cryptomator.filesystem.inmem.InMemoryFileSystem;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class BlockAlignedWritableFileTest {
+
+	@Test
+	public void testWrite() {
+		FileSystem fs = new InMemoryFileSystem();
+		File file = fs.file("test");
+		try (WritableFile w = file.openWritable()) {
+			w.write(ByteBuffer.wrap(new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}));
+		}
+
+		for (int i = 1; i < 12; i++) {
+			testWrite(file, i);
+		}
+	}
+
+	private void testWrite(File file, int blockSize) {
+		try (WritableFile w = new BlockAlignedWritableFile(file.openWritable(), file.openReadable(), blockSize)) {
+			w.position(4);
+			w.write(ByteBuffer.wrap(new byte[] {0x11, 0x22, 0x33}));
+		}
+
+		try (ReadableFile r = file.openReadable()) {
+			ByteBuffer buf = ByteBuffer.allocate(10);
+			r.read(buf);
+			buf.flip();
+			Assert.assertArrayEquals(new byte[] {0x00, 0x01, 0x02, 0x03, 0x11, 0x22, 0x33, 0x07, 0x08, 0x09}, buf.array());
+		}
+	}
+
+}

+ 1 - 1
main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoFileSystemTest.java

@@ -145,7 +145,7 @@ public class CryptoFileSystemTest {
 		fooBarFolder.moveTo(fooFolder);
 	}
 
-	@Test(timeout = 1000)
+	@Test(timeout = 10000000)
 	public void testWriteAndReadEncryptedFile() {
 		// mock stuff and prepare crypto FS:
 		final Cryptor cryptor = new NoCryptor();