Jelajahi Sumber

I/O statistics filesystem layer

Sebastian Stenzel 9 tahun lalu
induk
melakukan
6af4ee08f7

+ 1 - 0
main/filesystem-stats/.gitignore

@@ -0,0 +1 @@
+/target/

+ 49 - 0
main/filesystem-stats/pom.xml

@@ -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>

+ 49 - 0
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<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;
+			}
+		};
+	}
+
+}

+ 39 - 0
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();
+	}
+
+}

+ 30 - 0
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<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);
+	}
+
+}

+ 50 - 0
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());
+	}
+
+}

+ 50 - 0
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<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);
+	}
+
+}

+ 1 - 0
main/pom.xml

@@ -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>