diff --git a/main/filesystem-stats/pom.xml b/main/filesystem-stats/pom.xml index 8cf146c7d..b3f3daceb 100644 --- a/main/filesystem-stats/pom.xml +++ b/main/filesystem-stats/pom.xml @@ -22,10 +22,6 @@ org.cryptomator filesystem-api - - org.cryptomator - commons - 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 index 71b445192..d295f9abe 100644 --- 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 @@ -20,20 +20,12 @@ public class StatsFileSystem extends StatsFolder implements FileSystem { this.written = written; } - public long getBytesRead() { - return read.sum(); + public long getThenResetBytesRead() { + return read.sumThenReset(); } - public void resetBytesRead() { - read.reset(); - } - - public long getBytesWritten() { - return written.sum(); - } - - public void resetBytesWritten() { - written.reset(); + public long getThenResetBytesWritten() { + return written.sumThenReset(); } } 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 index 7952cdcd2..dfcfb378f 100644 --- 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 @@ -19,32 +19,24 @@ public class StatsFileSystemTest { statsFs.folder("foo").create(); File testFile = statsFs.folder("foo").file("bar"); - Assert.assertEquals(0l, statsFs.getBytesRead()); - Assert.assertEquals(0l, statsFs.getBytesWritten()); + Assert.assertEquals(0l, statsFs.getThenResetBytesRead()); + Assert.assertEquals(0l, statsFs.getThenResetBytesWritten()); 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()); + Assert.assertEquals(0l, statsFs.getThenResetBytesRead()); + Assert.assertEquals(15l, statsFs.getThenResetBytesWritten()); + Assert.assertEquals(0l, statsFs.getThenResetBytesWritten()); 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()); + Assert.assertEquals(3l, statsFs.getThenResetBytesRead()); + Assert.assertEquals(0l, statsFs.getThenResetBytesRead()); + Assert.assertEquals(0l, statsFs.getThenResetBytesWritten()); } } diff --git a/main/pom.xml b/main/pom.xml index db5ecf041..5b8fc0b41 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -90,6 +90,11 @@ filesystem-crypto ${project.version} + + org.cryptomator + filesystem-stats + ${project.version} + org.cryptomator diff --git a/main/ui/pom.xml b/main/ui/pom.xml index 6cf2d334a..faae1e994 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -34,6 +34,10 @@ org.cryptomator filesystem-crypto + + org.cryptomator + filesystem-stats + org.cryptomator frontend-api diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java index 86f25c331..fdb7507c5 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockedController.java @@ -29,6 +29,7 @@ import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; +import javafx.scene.chart.XYChart.Data; import javafx.scene.chart.XYChart.Series; import javafx.scene.control.Label; import javafx.stage.Stage; @@ -126,7 +127,7 @@ public class UnlockedController extends AbstractFXMLViewController { // IO Graph // **************************************** - private void startIoSampling(final Object sampler) { + private void startIoSampling() { final Series decryptedBytes = new Series<>(); decryptedBytes.setName("decrypted"); final Series encryptedBytes = new Series<>(); @@ -136,7 +137,7 @@ public class UnlockedController extends AbstractFXMLViewController { ioGraph.getData().add(encryptedBytes); ioAnimation = new Timeline(); - ioAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(IO_SAMPLING_INTERVAL), new IoSamplingAnimationHandler(sampler, decryptedBytes, encryptedBytes))); + ioAnimation.getKeyFrames().add(new KeyFrame(Duration.seconds(IO_SAMPLING_INTERVAL), new IoSamplingAnimationHandler(decryptedBytes, encryptedBytes))); ioAnimation.setCycleCount(Animation.INDEFINITE); ioAnimation.play(); } @@ -153,45 +154,41 @@ public class UnlockedController extends AbstractFXMLViewController { private static final double BYTES_TO_MEGABYTES_FACTOR = 1.0 / IO_SAMPLING_INTERVAL / 1024.0 / 1024.0; private static final double SMOOTHING_FACTOR = 0.3; private static final long EFFECTIVELY_ZERO = 100000; // 100kb - private final Object sampler; private final Series decryptedBytes; private final Series encryptedBytes; - private final int step = 0; - private final long oldDecBytes = 0; - private final long oldEncBytes = 0; + private int step = 0; + private long oldDecBytes = 0; + private long oldEncBytes = 0; - public IoSamplingAnimationHandler(Object sampler, Series decryptedBytes, Series encryptedBytes) { - this.sampler = sampler; + public IoSamplingAnimationHandler(Series decryptedBytes, Series encryptedBytes) { this.decryptedBytes = decryptedBytes; this.encryptedBytes = encryptedBytes; } @Override public void handle(ActionEvent event) { - /* - * step++; - * - * final long decBytes = sampler.pollDecryptedBytes(true); - * final double smoothedDecBytes = oldDecBytes + SMOOTHING_FACTOR * (decBytes - oldDecBytes); - * final double smoothedDecMb = smoothedDecBytes * BYTES_TO_MEGABYTES_FACTOR; - * oldDecBytes = smoothedDecBytes > EFFECTIVELY_ZERO ? (long) smoothedDecBytes : 0l; - * decryptedBytes.getData().add(new Data(step, smoothedDecMb)); - * if (decryptedBytes.getData().size() > IO_SAMPLING_STEPS) { - * decryptedBytes.getData().remove(0); - * } - * - * final long encBytes = sampler.pollEncryptedBytes(true); - * final double smoothedEncBytes = oldEncBytes + SMOOTHING_FACTOR * (encBytes - oldEncBytes); - * final double smoothedEncMb = smoothedEncBytes * BYTES_TO_MEGABYTES_FACTOR; - * oldEncBytes = smoothedEncBytes > EFFECTIVELY_ZERO ? (long) smoothedEncBytes : 0l; - * encryptedBytes.getData().add(new Data(step, smoothedEncMb)); - * if (encryptedBytes.getData().size() > IO_SAMPLING_STEPS) { - * encryptedBytes.getData().remove(0); - * } - * - * xAxis.setLowerBound(step - IO_SAMPLING_STEPS); - * xAxis.setUpperBound(step); - */ + step++; + + final long decBytes = vault.pollBytesRead(); + final double smoothedDecBytes = oldDecBytes + SMOOTHING_FACTOR * (decBytes - oldDecBytes); + final double smoothedDecMb = smoothedDecBytes * BYTES_TO_MEGABYTES_FACTOR; + oldDecBytes = smoothedDecBytes > EFFECTIVELY_ZERO ? (long) smoothedDecBytes : 0l; + decryptedBytes.getData().add(new Data(step, smoothedDecMb)); + if (decryptedBytes.getData().size() > IO_SAMPLING_STEPS) { + decryptedBytes.getData().remove(0); + } + + final long encBytes = vault.pollBytesWritten(); + final double smoothedEncBytes = oldEncBytes + SMOOTHING_FACTOR * (encBytes - oldEncBytes); + final double smoothedEncMb = smoothedEncBytes * BYTES_TO_MEGABYTES_FACTOR; + oldEncBytes = smoothedEncBytes > EFFECTIVELY_ZERO ? (long) smoothedEncBytes : 0l; + encryptedBytes.getData().add(new Data(step, smoothedEncMb)); + if (encryptedBytes.getData().size() > IO_SAMPLING_STEPS) { + encryptedBytes.getData().remove(0); + } + + xAxis.setLowerBound(step - IO_SAMPLING_STEPS); + xAxis.setUpperBound(step); } } @@ -214,15 +211,9 @@ public class UnlockedController extends AbstractFXMLViewController { } }); - // sample crypto-throughput: - /* - * stopIoSampling(); - * if (vault.getCryptor() instanceof CryptorIOSampling) { - * startIoSampling((CryptorIOSampling) vault.getCryptor()); - * } else { - * ioGraph.setVisible(false); - * } - */ + // (re)start throughput statistics: + stopIoSampling(); + startIoSampling(); } public LockListener getListener() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 8b7984fe3..8c555737b 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -21,6 +21,7 @@ import org.cryptomator.filesystem.FileSystem; import org.cryptomator.filesystem.crypto.CryptoFileSystemDelegate; import org.cryptomator.filesystem.crypto.CryptoFileSystemFactory; import org.cryptomator.filesystem.nio.NioFileSystem; +import org.cryptomator.filesystem.stats.StatsFileSystem; import org.cryptomator.frontend.CommandFailedException; import org.cryptomator.frontend.Frontend; import org.cryptomator.frontend.Frontend.MountParam; @@ -42,7 +43,6 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { private static final long serialVersionUID = 3754487289683599469L; - @Deprecated public static final String VAULT_FILE_EXTENSION = ".cryptomator"; @Deprecated @@ -58,6 +58,7 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { private String mountName; private Character winDriveLetter; + private Optional statsFileSystem = Optional.empty(); private DeferredClosable filesystemFrontend = DeferredClosable.empty(); /** @@ -76,14 +77,10 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { } } - public boolean isValidVaultDirectory() { - return Files.isDirectory(path) && path.getFileName().toString().endsWith(VAULT_FILE_EXTENSION); - } - - public boolean containsMasterKey() throws IOException { - final Path masterKeyPath = path.resolve(VAULT_MASTERKEY_FILE); - return Files.isRegularFile(masterKeyPath); - } + /* + * ****************************************************************************** + * Commands + ********************************************************************************/ public void create(CharSequence passphrase) throws IOException { try { @@ -110,10 +107,12 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { try { FileSystem fs = NioFileSystem.rootedAt(path); FileSystem cryptoFs = cryptoFileSystemFactory.unlockExisting(fs, passphrase, this); + StatsFileSystem statsFs = new StatsFileSystem(cryptoFs); + statsFileSystem = Optional.of(statsFs); String contextPath = StringUtils.prependIfMissing(mountName, "/"); - Frontend frontend = frontendFactory.get().create(cryptoFs, contextPath); + Frontend frontend = frontendFactory.get().create(statsFs, contextPath); filesystemFrontend = closer.closeLater(frontend); - setUnlocked(true); + unlocked.set(true); } catch (UncheckedIOException e) { throw new FrontendCreationFailedException(e); } @@ -121,7 +120,8 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { public synchronized void deactivateFrontend() { filesystemFrontend.close(); - setUnlocked(false); + statsFileSystem = Optional.empty(); + unlocked.set(false); } private Map> getMountParams() { @@ -150,7 +150,10 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { Optionals.ifPresent(filesystemFrontend.get(), Frontend::unmount); } - /* Delegate Methods */ + /* + * ****************************************************************************** + * Delegate methods + ********************************************************************************/ @Override public void authenticationFailed(String cleartextPath) { @@ -162,7 +165,10 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { return namesOfResourcesWithInvalidMac.contains(cleartextPath); } - /* Getter/Setter */ + /* + * ****************************************************************************** + * Getter/Setter + ********************************************************************************/ public Path getPath() { return path; @@ -175,6 +181,15 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { return StringUtils.removeEnd(path.getFileName().toString(), VAULT_FILE_EXTENSION); } + public boolean isValidVaultDirectory() { + return Files.isDirectory(path) && path.getFileName().toString().endsWith(VAULT_FILE_EXTENSION); + } + + public boolean containsMasterKey() throws IOException { + final Path masterKeyPath = path.resolve(VAULT_MASTERKEY_FILE); + return Files.isRegularFile(masterKeyPath); + } + public ObjectProperty unlockedProperty() { return unlocked; } @@ -183,10 +198,6 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { return unlocked.get(); } - public void setUnlocked(boolean unlocked) { - this.unlocked.set(unlocked); - } - public ObservableList getNamesOfResourcesWithInvalidMac() { return namesOfResourcesWithInvalidMac; } @@ -195,6 +206,14 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { return whitelistedResourcesWithInvalidMac; } + public long pollBytesRead() { + return statsFileSystem.map(StatsFileSystem::getThenResetBytesRead).orElse(0l); + } + + public long pollBytesWritten() { + return statsFileSystem.map(StatsFileSystem::getThenResetBytesWritten).orElse(0l); + } + /** * Tries to form a similar string using the regular latin alphabet. * @@ -247,7 +266,10 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { this.winDriveLetter = winDriveLetter; } - /* hashcode/equals */ + /* + * ****************************************************************************** + * Hashcode / Equals + ********************************************************************************/ @Override public int hashCode() {