Added block-aligned read/write

This commit is contained in:
Sebastian Stenzel
2015-12-29 22:05:19 +01:00
parent c86068d7bb
commit 634f176cf9
6 changed files with 199 additions and 13 deletions

View File

@@ -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);
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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()));
}
}
}

View File

@@ -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());
}
}
}

View File

@@ -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();