mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-18 18:51:26 +00:00
I/O statistics filesystem layer
This commit is contained in:
1
main/filesystem-stats/.gitignore
vendored
Normal file
1
main/filesystem-stats/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target/
|
||||
49
main/filesystem-stats/pom.xml
Normal file
49
main/filesystem-stats/pom.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 2015 Sebastian Stenzel
|
||||
This file is licensed under the terms of the MIT license.
|
||||
See the LICENSE.txt file for more info.
|
||||
|
||||
Contributors:
|
||||
Sebastian Stenzel - initial API and implementation
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>0.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>filesystem-stats</artifactId>
|
||||
<name>Cryptomator filesystem: Throughput statistics</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>filesystem-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Tests -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons-test</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>filesystem-inmemory</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.cryptomator.filesystem.stats;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.cryptomator.filesystem.File;
|
||||
import org.cryptomator.filesystem.ReadableFile;
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
import org.cryptomator.filesystem.delegating.DelegatingFile;
|
||||
import org.cryptomator.filesystem.delegating.DelegatingReadableFile;
|
||||
import org.cryptomator.filesystem.delegating.DelegatingWritableFile;
|
||||
|
||||
public class StatsFile extends DelegatingFile<StatsFolder> {
|
||||
|
||||
private final Consumer<Long> readCounter;
|
||||
private final Consumer<Long> writeCounter;
|
||||
|
||||
public StatsFile(StatsFolder parent, File delegate, Consumer<Long> readCounter, Consumer<Long> writeCounter) {
|
||||
super(parent, delegate);
|
||||
this.readCounter = readCounter;
|
||||
this.writeCounter = writeCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadableFile openReadable() throws UncheckedIOException {
|
||||
return new DelegatingReadableFile(delegate.openReadable()) {
|
||||
@Override
|
||||
public int read(ByteBuffer target) throws UncheckedIOException {
|
||||
int num = super.read(target);
|
||||
readCounter.accept((long) num);
|
||||
return num;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public WritableFile openWritable() throws UncheckedIOException {
|
||||
return new DelegatingWritableFile(delegate.openWritable()) {
|
||||
@Override
|
||||
public int write(ByteBuffer source) throws UncheckedIOException {
|
||||
int num = super.write(source);
|
||||
writeCounter.accept((long) num);
|
||||
return num;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.cryptomator.filesystem.stats;
|
||||
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
import org.cryptomator.filesystem.FileSystem;
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
|
||||
public class StatsFileSystem extends StatsFolder implements FileSystem {
|
||||
|
||||
private final LongAdder read;
|
||||
private final LongAdder written;
|
||||
|
||||
public StatsFileSystem(Folder root) {
|
||||
this(root, new LongAdder(), new LongAdder());
|
||||
}
|
||||
|
||||
private StatsFileSystem(Folder root, LongAdder read, LongAdder written) {
|
||||
super(null, root, read::add, written::add);
|
||||
this.read = read;
|
||||
this.written = written;
|
||||
}
|
||||
|
||||
public long getBytesRead() {
|
||||
return read.sum();
|
||||
}
|
||||
|
||||
public void resetBytesRead() {
|
||||
read.reset();
|
||||
}
|
||||
|
||||
public long getBytesWritten() {
|
||||
return written.sum();
|
||||
}
|
||||
|
||||
public void resetBytesWritten() {
|
||||
written.reset();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.cryptomator.filesystem.stats;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.cryptomator.filesystem.File;
|
||||
import org.cryptomator.filesystem.Folder;
|
||||
import org.cryptomator.filesystem.delegating.DelegatingFolder;
|
||||
|
||||
public class StatsFolder extends DelegatingFolder<StatsFolder, StatsFile> {
|
||||
|
||||
private final Consumer<Long> readCounter;
|
||||
private final Consumer<Long> writeCounter;
|
||||
|
||||
public StatsFolder(StatsFolder parent, Folder delegate, Consumer<Long> readCounter, Consumer<Long> writeCounter) {
|
||||
super(parent, delegate);
|
||||
this.readCounter = readCounter;
|
||||
this.writeCounter = writeCounter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StatsFile newFile(File delegate) {
|
||||
return new StatsFile(this, delegate, readCounter, writeCounter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StatsFolder newFolder(Folder delegate) {
|
||||
return new StatsFolder(this, delegate, readCounter, writeCounter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.cryptomator.filesystem.stats;
|
||||
|
||||
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 StatsFileSystemTest {
|
||||
|
||||
@Test
|
||||
public void testReadAndWriteCounters() {
|
||||
FileSystem underlyingFs = new InMemoryFileSystem();
|
||||
StatsFileSystem statsFs = new StatsFileSystem(underlyingFs);
|
||||
statsFs.folder("foo").create();
|
||||
File testFile = statsFs.folder("foo").file("bar");
|
||||
|
||||
Assert.assertEquals(0l, statsFs.getBytesRead());
|
||||
Assert.assertEquals(0l, statsFs.getBytesWritten());
|
||||
|
||||
try (WritableFile w = testFile.openWritable()) {
|
||||
w.write(ByteBuffer.allocate(15));
|
||||
}
|
||||
|
||||
Assert.assertEquals(0l, statsFs.getBytesRead());
|
||||
Assert.assertEquals(15l, statsFs.getBytesWritten());
|
||||
|
||||
statsFs.resetBytesWritten();
|
||||
|
||||
Assert.assertEquals(0l, statsFs.getBytesRead());
|
||||
Assert.assertEquals(0l, statsFs.getBytesWritten());
|
||||
|
||||
try (ReadableFile r = testFile.openReadable()) {
|
||||
r.read(ByteBuffer.allocate(3));
|
||||
}
|
||||
|
||||
Assert.assertEquals(3l, statsFs.getBytesRead());
|
||||
Assert.assertEquals(0l, statsFs.getBytesWritten());
|
||||
|
||||
statsFs.resetBytesRead();
|
||||
|
||||
Assert.assertEquals(0l, statsFs.getBytesRead());
|
||||
Assert.assertEquals(0l, statsFs.getBytesWritten());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.cryptomator.filesystem.stats;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.cryptomator.filesystem.File;
|
||||
import org.cryptomator.filesystem.ReadableFile;
|
||||
import org.cryptomator.filesystem.WritableFile;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class StatsFileTest {
|
||||
|
||||
@Test
|
||||
public void testStatsDuringRead() {
|
||||
ReadableFile readable = Mockito.mock(ReadableFile.class);
|
||||
File file = Mockito.mock(File.class);
|
||||
Mockito.when(file.openReadable()).thenReturn(readable);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<Long> readCounter = Mockito.mock(Consumer.class);
|
||||
File statsFile = new StatsFile(null, file, readCounter, null);
|
||||
|
||||
Mockito.when(readable.read(Mockito.any())).thenReturn(123);
|
||||
try (ReadableFile r = statsFile.openReadable()) {
|
||||
r.read(ByteBuffer.allocate(0));
|
||||
}
|
||||
|
||||
Mockito.verify(readCounter).accept(123l);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatsDuringWrite() {
|
||||
WritableFile writable = Mockito.mock(WritableFile.class);
|
||||
File file = Mockito.mock(File.class);
|
||||
Mockito.when(file.openWritable()).thenReturn(writable);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Consumer<Long> writeCounter = Mockito.mock(Consumer.class);
|
||||
File statsFile = new StatsFile(null, file, null, writeCounter);
|
||||
|
||||
Mockito.when(writable.write(Mockito.any())).thenReturn(123);
|
||||
try (WritableFile w = statsFile.openWritable()) {
|
||||
w.write(ByteBuffer.allocate(0));
|
||||
}
|
||||
|
||||
Mockito.verify(writeCounter).accept(123l);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -253,6 +253,7 @@
|
||||
<module>filesystem-nio</module>
|
||||
<module>filesystem-nameshortening</module>
|
||||
<module>filesystem-crypto</module>
|
||||
<module>filesystem-stats</module>
|
||||
<module>filesystem-invariants-tests</module>
|
||||
<module>frontend-api</module>
|
||||
<module>frontend-webdav</module>
|
||||
|
||||
Reference in New Issue
Block a user