From 6af4ee08f709d4ddd327c538ad4a5c7fac042867 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 28 Jan 2016 20:49:32 +0100 Subject: [PATCH] I/O statistics filesystem layer --- main/filesystem-stats/.gitignore | 1 + main/filesystem-stats/pom.xml | 49 ++++++++++++++++++ .../filesystem/stats/StatsFile.java | 49 ++++++++++++++++++ .../filesystem/stats/StatsFileSystem.java | 39 +++++++++++++++ .../filesystem/stats/StatsFolder.java | 30 +++++++++++ .../filesystem/stats/StatsFileSystemTest.java | 50 +++++++++++++++++++ .../filesystem/stats/StatsFileTest.java | 50 +++++++++++++++++++ main/pom.xml | 1 + 8 files changed, 269 insertions(+) create mode 100644 main/filesystem-stats/.gitignore create mode 100644 main/filesystem-stats/pom.xml create mode 100644 main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFile.java create mode 100644 main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFileSystem.java create mode 100644 main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFolder.java create mode 100644 main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileSystemTest.java create mode 100644 main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileTest.java diff --git a/main/filesystem-stats/.gitignore b/main/filesystem-stats/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/main/filesystem-stats/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/main/filesystem-stats/pom.xml b/main/filesystem-stats/pom.xml new file mode 100644 index 000000000..8cf146c7d --- /dev/null +++ b/main/filesystem-stats/pom.xml @@ -0,0 +1,49 @@ + + + + 4.0.0 + + org.cryptomator + main + 0.11.0-SNAPSHOT + + filesystem-stats + Cryptomator filesystem: Throughput statistics + + + + org.cryptomator + filesystem-api + + + org.cryptomator + commons + + + + + org.cryptomator + commons-test + + + org.cryptomator + filesystem-inmemory + + + + + + + org.jacoco + jacoco-maven-plugin + + + + \ No newline at end of file diff --git a/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFile.java b/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFile.java new file mode 100644 index 000000000..4f334ea5c --- /dev/null +++ b/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFile.java @@ -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 { + + private final Consumer readCounter; + private final Consumer writeCounter; + + public StatsFile(StatsFolder parent, File delegate, Consumer readCounter, Consumer 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; + } + }; + } + +} diff --git a/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFileSystem.java b/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFileSystem.java new file mode 100644 index 000000000..71b445192 --- /dev/null +++ b/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFileSystem.java @@ -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(); + } + +} diff --git a/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFolder.java b/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFolder.java new file mode 100644 index 000000000..f04de3322 --- /dev/null +++ b/main/filesystem-stats/src/main/java/org/cryptomator/filesystem/stats/StatsFolder.java @@ -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 { + + private final Consumer readCounter; + private final Consumer writeCounter; + + public StatsFolder(StatsFolder parent, Folder delegate, Consumer readCounter, Consumer 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); + } + +} diff --git a/main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileSystemTest.java b/main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileSystemTest.java new file mode 100644 index 000000000..7952cdcd2 --- /dev/null +++ b/main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileSystemTest.java @@ -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()); + } + +} diff --git a/main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileTest.java b/main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileTest.java new file mode 100644 index 000000000..df3ee5573 --- /dev/null +++ b/main/filesystem-stats/src/test/java/org/cryptomator/filesystem/stats/StatsFileTest.java @@ -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 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 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); + } + +} diff --git a/main/pom.xml b/main/pom.xml index 217b825b5..db5ecf041 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -253,6 +253,7 @@ filesystem-nio filesystem-nameshortening filesystem-crypto + filesystem-stats filesystem-invariants-tests frontend-api frontend-webdav