speedboost 3000

This commit is contained in:
Sebastian Stenzel
2016-08-24 17:27:36 +02:00
parent 66faa13f40
commit e90880ac9a
25 changed files with 104 additions and 120 deletions

View File

@@ -17,6 +17,13 @@ public interface File extends Node, Comparable<File> {
static final int EOF = -1;
/**
* @return The current size of the file. This value is a snapshot and might have been changed by concurrent modifications.
* @throws UncheckedIOException
* if an {@link IOException} occurs
*/
long size() throws UncheckedIOException;
/**
* <p>
* Opens this file for reading.
@@ -39,7 +46,6 @@ public interface File extends Node, Comparable<File> {
* if an {@link IOException} occurs while opening the file, the
* file does not exist or is a directory
*/
ReadableFile openReadable() throws UncheckedIOException;
/**

View File

@@ -30,13 +30,6 @@ public interface ReadableFile extends ReadableByteChannel {
@Override
int read(ByteBuffer target) throws UncheckedIOException;
/**
* @return The current size of the file. This value is a snapshot and might have been changed by concurrent modifications.
* @throws UncheckedIOException
* if an {@link IOException} occurs
*/
long size() throws UncheckedIOException;
/**
* <p>
* Fast-forwards or rewinds the file to the specified position.

View File

@@ -15,7 +15,7 @@ import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.WritableFile;
public abstract class DelegatingFile<D extends DelegatingFolder<D, ?>> extends DelegatingNode<File>implements File {
public abstract class DelegatingFile<D extends DelegatingFolder<D, ?>> extends DelegatingNode<File> implements File {
private final D parent;
@@ -29,6 +29,11 @@ public abstract class DelegatingFile<D extends DelegatingFolder<D, ?>> extends D
return Optional.of(parent);
}
@Override
public long size() throws UncheckedIOException {
return delegate.size();
}
@Override
public ReadableFile openReadable() throws UncheckedIOException {
return delegate.openReadable();

View File

@@ -31,11 +31,6 @@ public class DelegatingReadableFile implements ReadableFile {
return delegate.read(target);
}
@Override
public long size() throws UncheckedIOException {
return delegate.size();
}
@Override
public void position(long position) throws UncheckedIOException {
delegate.position(position);

View File

@@ -30,6 +30,16 @@ public class DelegatingFileTest {
Assert.assertEquals(mockFile.name(), delegatingFile.name());
}
@Test
public void testSize() {
File mockFile = Mockito.mock(File.class);
DelegatingFile<?> delegatingFile = new TestDelegatingFile(null, mockFile);
Mockito.when(mockFile.size()).thenReturn(42l);
Assert.assertEquals(42l, delegatingFile.size());
Mockito.verify(mockFile).size();
}
@Test
public void testParent() {
Folder mockFolder = Mockito.mock(Folder.class);

View File

@@ -42,17 +42,6 @@ public class DelegatingReadableFileTest {
Mockito.verify(mockReadableFile).read(buf);
}
@Test
public void testSize() {
ReadableFile mockReadableFile = Mockito.mock(ReadableFile.class);
@SuppressWarnings("resource")
DelegatingReadableFile delegatingReadableFile = new DelegatingReadableFile(mockReadableFile);
Mockito.when(mockReadableFile.size()).thenReturn(42l);
Assert.assertEquals(42l, delegatingReadableFile.size());
Mockito.verify(mockReadableFile).size();
}
@Test
public void testPosition() {
ReadableFile mockReadableFile = Mockito.mock(ReadableFile.class);

View File

@@ -130,7 +130,7 @@ public class CryptoFileSystemIntegrationTest {
// toggle last bit
try (WritableFile writable = physicalFile.openWritable(); ReadableFile readable = physicalFile.openReadable()) {
ByteBuffer buf = ByteBuffer.allocate((int) readable.size());
ByteBuffer buf = ByteBuffer.allocate((int) physicalFile.size());
readable.read(buf);
buf.array()[buf.limit() - 1] ^= 0x01;
buf.flip();

View File

@@ -100,11 +100,6 @@ class BlockAlignedReadableFile implements ReadableFile {
return delegate.isOpen();
}
@Override
public long size() throws UncheckedIOException {
return delegate.size();
}
@Override
public void close() throws UncheckedIOException {
delegate.close();

View File

@@ -79,10 +79,10 @@ final class ConflictResolver {
}
private boolean isSameFileBasedOnSample(File file1, File file2, int sampleSize) {
try (ReadableFile r1 = file1.openReadable(); ReadableFile r2 = file2.openReadable()) {
if (r1.size() != r2.size()) {
return false;
} else {
if (file1.size() != file2.size()) {
return false;
} else {
try (ReadableFile r1 = file1.openReadable(); ReadableFile r2 = file2.openReadable()) {
ByteBuffer beginOfFile1 = ByteBuffer.allocate(sampleSize);
ByteBuffer beginOfFile2 = ByteBuffer.allocate(sampleSize);
int bytesRead1 = r1.read(beginOfFile1);

View File

@@ -8,6 +8,9 @@
*******************************************************************************/
package org.cryptomator.filesystem.crypto;
import static org.cryptomator.crypto.engine.impl.Constants.CHUNK_SIZE;
import static org.cryptomator.crypto.engine.impl.Constants.PAYLOAD_SIZE;
import java.io.UncheckedIOException;
import java.nio.file.FileAlreadyExistsException;
import java.util.Optional;
@@ -28,6 +31,25 @@ class CryptoFile extends CryptoNode implements File {
return parent().get().encryptChildName(name());
}
@Override
public long size() throws UncheckedIOException {
if (!physicalFile().isPresent()) {
return -1l;
} else {
File file = physicalFile().get();
long ciphertextSize = file.size() - cryptor.getFileContentCryptor().getHeaderSize();
long overheadPerChunk = CHUNK_SIZE - PAYLOAD_SIZE;
long numFullChunks = ciphertextSize / CHUNK_SIZE; // floor by int-truncation
long additionalCiphertextBytes = ciphertextSize % CHUNK_SIZE;
if (additionalCiphertextBytes > 0 && additionalCiphertextBytes <= overheadPerChunk) {
throw new IllegalArgumentException("Method not defined for input value " + ciphertextSize);
}
long additionalCleartextBytes = (additionalCiphertextBytes == 0) ? 0 : additionalCiphertextBytes - overheadPerChunk;
assert additionalCleartextBytes >= 0;
return PAYLOAD_SIZE * numFullChunks + additionalCleartextBytes;
}
}
@Override
public ReadableFile openReadable() {
boolean authenticate = !fileSystem().delegate().shouldSkipAuthentication(toString());

View File

@@ -8,9 +8,6 @@
*******************************************************************************/
package org.cryptomator.filesystem.crypto;
import static org.cryptomator.crypto.engine.impl.Constants.CHUNK_SIZE;
import static org.cryptomator.crypto.engine.impl.Constants.PAYLOAD_SIZE;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UncheckedIOException;
@@ -73,20 +70,6 @@ class CryptoReadableFile implements ReadableFile {
}
}
@Override
public long size() throws UncheckedIOException {
long ciphertextSize = file.size() - cryptor.getHeaderSize();
long overheadPerChunk = CHUNK_SIZE - PAYLOAD_SIZE;
long numFullChunks = ciphertextSize / CHUNK_SIZE; // floor by int-truncation
long additionalCiphertextBytes = ciphertextSize % CHUNK_SIZE;
if (additionalCiphertextBytes > 0 && additionalCiphertextBytes <= overheadPerChunk) {
throw new IllegalArgumentException("Method not defined for input value " + ciphertextSize);
}
long additionalCleartextBytes = (additionalCiphertextBytes == 0) ? 0 : additionalCiphertextBytes - overheadPerChunk;
assert additionalCleartextBytes >= 0;
return PAYLOAD_SIZE * numFullChunks + additionalCleartextBytes;
}
@Override
public void position(long position) throws UncheckedIOException {
if (readAheadTask != null) {

View File

@@ -43,20 +43,6 @@ public class FileContentCryptorImplTest {
};
private static final SecureRandom RANDOM_MOCK_2 = new SecureRandom() {
@Override
public int nextInt(int bound) {
return 500;
}
@Override
public void nextBytes(byte[] bytes) {
Arrays.fill(bytes, (byte) 0x00);
}
};
@Test(expected = IllegalArgumentException.class)
public void testShortHeaderInDecryptor() throws InterruptedException {
final byte[] keyBytes = new byte[32];

View File

@@ -35,20 +35,6 @@ public class FileContentEncryptorImplTest {
};
private static final SecureRandom RANDOM_MOCK_2 = new SecureRandom() {
@Override
public int nextInt(int bound) {
return 42;
}
@Override
public void nextBytes(byte[] bytes) {
Arrays.fill(bytes, (byte) 0x00);
}
};
@Test
public void testEncryption() throws InterruptedException {
final byte[] keyBytes = new byte[32];

View File

@@ -43,6 +43,11 @@ class InMemoryFile extends InMemoryNode implements File {
return buf;
}
@Override
public long size() throws UncheckedIOException {
return content.get().limit();
}
@Override
public void moveTo(File destination) throws UncheckedIOException {
if (destination instanceof InMemoryFile) {
@@ -103,7 +108,7 @@ class InMemoryFile extends InMemoryNode implements File {
throw new UncheckedIOException(new FileAlreadyExistsException(k));
} else {
if (v == null) {
assert!content.get().hasRemaining();
assert !content.get().hasRemaining();
this.creationTime = Instant.now();
}
this.lastModified = Instant.now();
@@ -120,7 +125,7 @@ class InMemoryFile extends InMemoryNode implements File {
// returning null removes the entry.
return null;
});
assert!this.exists();
assert !this.exists();
}
@Override

View File

@@ -51,11 +51,6 @@ class InMemoryReadableFile implements ReadableFile {
}
}
@Override
public long size() throws UncheckedIOException {
return contentGetter.get().limit();
}
@Override
public void position(long position) throws UncheckedIOException {
assert position < Integer.MAX_VALUE : "Can not use that big in-memory files.";

View File

@@ -104,9 +104,7 @@ public class InMemoryFileSystemTest {
Assert.assertTrue(fooFile.exists());
// check if size = 11 bytes
try (ReadableFile readable = fooFile.openReadable()) {
Assert.assertEquals(11, readable.size());
}
Assert.assertEquals(11, fooFile.size());
// copy foo to bar
File barFile = fs.file("bar.txt");

View File

@@ -17,6 +17,11 @@ import java.util.stream.Stream;
class DefaultNioAccess implements NioAccess {
@Override
public long size(Path path) throws IOException {
return Files.size(path);
}
@Override
public AsynchronousFileChannel open(Path path, OpenOption... options) throws IOException {
return AsynchronousFileChannel.open(path, options);
@@ -59,7 +64,8 @@ class DefaultNioAccess implements NioAccess {
} catch (AccessDeniedException e) {
// workaround for https://github.com/cryptomator/cryptomator/issues/317
try {
if (path.toFile().delete()) return;
if (path.toFile().delete())
return;
} catch (UnsupportedOperationException e2) {
// ignore
}

View File

@@ -16,6 +16,8 @@ interface NioAccess {
public static final Holder<NioAccess> DEFAULT = new Holder<>(new DefaultNioAccess());
long size(Path path) throws IOException;
AsynchronousFileChannel open(Path path, OpenOption... options) throws IOException;
boolean isRegularFile(Path path, LinkOption... options);

View File

@@ -27,6 +27,15 @@ class NioFile extends NioNode implements File {
sharedChannel = instanceFactory.sharedFileChannel(path, nioAccess);
}
@Override
public long size() throws UncheckedIOException {
try {
return nioAccess.size(path);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public ReadableFile openReadable() throws UncheckedIOException {
if (lock.getWriteHoldCount() > 0) {

View File

@@ -41,11 +41,6 @@ class ReadableNioFile implements ReadableFile {
return open;
}
@Override
public long size() throws UncheckedIOException {
return channel.size();
}
@Override
public void position(long position) throws UncheckedIOException {
assertOpen();

View File

@@ -16,6 +16,7 @@ import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
@@ -85,6 +86,27 @@ public class NioFileTest {
}
public class Size {
@Test
public void testSizeReturnsSizeOfRegularFile() throws IOException {
when(nioAccess.size(path)).thenReturn(42l);
assertThat(inTest.size(), is(42l));
}
@Test
public void testSizeThrowsExceptionIfRegularFileThrowsException() throws IOException {
Throwable t = new NoSuchFileException("foo");
when(nioAccess.size(path)).thenThrow(t);
thrown.expect(UncheckedIOException.class);
thrown.expectCause(org.hamcrest.Matchers.sameInstance(t));
inTest.size();
}
}
public class Open {
@Test

View File

@@ -83,16 +83,6 @@ public class ReadableNioFileTest {
inTest.position(-1);
}
@Test
public void testSizeReturnsSizeOfChannel() {
long expectedSize = 85472;
when(channel.size()).thenReturn(expectedSize);
long actualSize = inTest.size();
assertThat(actualSize, is(expectedSize));
}
@Test
public void testReadDelegatesToChannelReadFullyWithZeroPositionIfNotSet() {
ByteBuffer buffer = mock(ByteBuffer.class);

View File

@@ -32,14 +32,11 @@ import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.ReadableFile;
import org.cryptomator.filesystem.jackrabbit.FileLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.io.ByteStreams;
class DavFile extends DavNode<FileLocator> {
private static final Logger LOG = LoggerFactory.getLogger(DavFile.class);
protected static final String CONTENT_TYPE_VALUE = "application/octet-stream";
protected static final String CONTENT_DISPOSITION_HEADER = "Content-Disposition";
protected static final String CONTENT_DISPOSITION_VALUE = "attachment";
@@ -64,8 +61,8 @@ class DavFile extends DavNode<FileLocator> {
outputContext.setContentType(CONTENT_TYPE_VALUE);
outputContext.setProperty(CONTENT_DISPOSITION_HEADER, CONTENT_DISPOSITION_VALUE);
outputContext.setProperty(X_CONTENT_TYPE_OPTIONS_HEADER, X_CONTENT_TYPE_OPTIONS_VALUE);
outputContext.setContentLength(node.size());
try (ReadableFile src = node.openReadable(); WritableByteChannel dst = Channels.newChannel(outputContext.getOutputStream())) {
outputContext.setContentLength(src.size());
ByteStreams.copy(src, dst);
}
}
@@ -157,12 +154,7 @@ class DavFile extends DavNode<FileLocator> {
private Optional<DavProperty<?>> sizeProperty() {
if (node.exists()) {
try (ReadableFile src = node.openReadable()) {
return Optional.of(new DefaultDavProperty<Long>(DavPropertyName.GETCONTENTLENGTH, src.size()));
} catch (RuntimeException e) {
LOG.warn("Could not determine file size of " + getResourcePath(), e);
return Optional.empty();
}
return Optional.of(new DefaultDavProperty<Long>(DavPropertyName.GETCONTENTLENGTH, node.size()));
} else {
return Optional.empty();
}

View File

@@ -47,8 +47,8 @@ class DavFileWithRange extends DavFile {
if (!outputContext.hasStream()) {
return;
}
final long contentLength = node.size();
try (ReadableFile src = node.openReadable(); OutputStream out = outputContext.getOutputStream()) {
final long contentLength = src.size();
final Pair<Long, Long> range = getEffectiveRange(contentLength);
if (range.getLeft() < 0 || range.getLeft() > range.getRight() || range.getRight() > contentLength) {
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + contentLength);

View File

@@ -39,10 +39,10 @@ class DavFileWithUnsatisfiableRange extends DavFile {
if (!outputContext.hasStream()) {
return;
}
final long contentLength = node.size();
outputContext.setContentLength(contentLength);
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + contentLength);
try (ReadableFile src = node.openReadable(); OutputStream out = outputContext.getOutputStream()) {
final long contentLength = src.size();
outputContext.setContentLength(contentLength);
outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), "bytes */" + contentLength);
ByteStreams.copy(src, Channels.newChannel(out));
}
}