-
Notifications
You must be signed in to change notification settings - Fork 35
Feature: Invalidate dir cache correctly #253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
84e7167
invalidate/move also all cleartext path cache entries starting with t…
infeo 3515794
refactor dir cache to own inner static class
infeo eb06489
extend refactoring by moving inner CryptoPathMapper classes to own cl…
infeo 325c13f
add unit tests for dir cache
infeo bffacaf
removed TODOs and renamed a function
infeo 17b0e0a
add integrate-like-tests in cryptoPathMapper
infeo 0cd494c
doc doc doc
infeo eda73ff
reduce diff by reverting renames
infeo ec01bb6
apply suggestions
infeo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
82 changes: 82 additions & 0 deletions
82
src/main/java/org/cryptomator/cryptofs/CiphertextDirCache.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| package org.cryptomator.cryptofs; | ||
|
|
||
| import com.github.benmanes.caffeine.cache.AsyncCache; | ||
| import com.github.benmanes.caffeine.cache.Caffeine; | ||
|
|
||
| import java.io.IOException; | ||
| import java.time.Duration; | ||
| import java.util.ArrayList; | ||
| import java.util.concurrent.CompletableFuture; | ||
|
|
||
| /** | ||
| * Caches for the cleartext path of a directory its ciphertext path to the content directory. | ||
| */ | ||
| public class CiphertextDirCache { | ||
|
|
||
| private static final int MAX_CACHED_PATHS = 5000; | ||
| private static final Duration MAX_CACHE_AGE = Duration.ofSeconds(20); | ||
|
|
||
| private final AsyncCache<CryptoPath, CiphertextDirectory> ciphertextDirectories = Caffeine.newBuilder() // | ||
| .maximumSize(MAX_CACHED_PATHS) // | ||
| .expireAfterWrite(MAX_CACHE_AGE) // | ||
| .buildAsync(); | ||
|
|
||
| /** | ||
| * Removes all (key,value) entries, where {@code key.startsWith(oldPrefix) == true}. | ||
| * | ||
| * @param basePrefix The prefix key which the keys are checked against | ||
| */ | ||
| void removeAllKeysWithPrefix(CryptoPath basePrefix) { | ||
| ciphertextDirectories.asMap().keySet().removeIf(p -> p.startsWith(basePrefix)); | ||
| } | ||
|
|
||
| /** | ||
| * Remaps all (key,value) entries, where {@code key.startsWith(oldPrefix) == true}. | ||
| * The new key is computed by replacing the oldPrefix with the newPrefix. | ||
| * | ||
| * @param oldPrefix the prefix key which the keys are checked against | ||
| * @param newPrefix the prefix key which replaces {@code oldPrefix} | ||
| */ | ||
| void recomputeAllKeysWithPrefix(CryptoPath oldPrefix, CryptoPath newPrefix) { | ||
| var remappedEntries = new ArrayList<CacheEntry>(); | ||
| ciphertextDirectories.asMap().entrySet().removeIf(e -> { | ||
| if (e.getKey().startsWith(oldPrefix)) { | ||
| var remappedPath = newPrefix.resolve(oldPrefix.relativize(e.getKey())); | ||
| return remappedEntries.add(new CacheEntry(remappedPath, e.getValue())); | ||
| } else { | ||
| return false; | ||
| } | ||
| }); | ||
| remappedEntries.forEach(e -> ciphertextDirectories.put(e.clearPath(), e.cipherDir())); | ||
| } | ||
|
|
||
|
|
||
| /** | ||
| * Gets the cipher directory for the given cleartext path. If a cache miss occurs, the mapping is loaded with the {@code ifAbsent} function. | ||
| * @param cleartextPath Cleartext path key | ||
| * @param ifAbsent Function to compute the (cleartextPath, cipherDir) mapping on a cache miss. | ||
| * @return a {@link CiphertextDirectory}, containing the dirId and the ciphertext content directory path | ||
| * @throws IOException if the loading function throws an IOException | ||
| */ | ||
| CiphertextDirectory get(CryptoPath cleartextPath, CipherDirLoader ifAbsent) throws IOException { | ||
| var futureMapping = new CompletableFuture<CiphertextDirectory>(); | ||
| var currentMapping = ciphertextDirectories.asMap().putIfAbsent(cleartextPath, futureMapping); | ||
| if (currentMapping != null) { | ||
| return currentMapping.join(); | ||
| } else { | ||
| futureMapping.complete(ifAbsent.load()); | ||
| return futureMapping.join(); | ||
| } | ||
| } | ||
|
|
||
| @FunctionalInterface | ||
| interface CipherDirLoader { | ||
|
|
||
| CiphertextDirectory load() throws IOException; | ||
| } | ||
|
|
||
| private record CacheEntry(CryptoPath clearPath, CompletableFuture<CiphertextDirectory> cipherDir) { | ||
|
|
||
| } | ||
infeo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| } | ||
21 changes: 21 additions & 0 deletions
21
src/main/java/org/cryptomator/cryptofs/CiphertextDirectory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package org.cryptomator.cryptofs; | ||
|
|
||
| import java.nio.file.Path; | ||
| import java.util.Objects; | ||
|
|
||
| //own file due to dagger | ||
|
|
||
| /** | ||
| * Represents a ciphertext directory without it's mount point in the virtual filesystem. | ||
| * | ||
| * @param dirId The (ciphertext) dir id (not encrypted, just a uuid) | ||
| * @param path The path to content directory (which contains the actual encrypted files and links to subdirectories) | ||
| */ | ||
| public record CiphertextDirectory(String dirId, Path path) { | ||
|
|
||
| public CiphertextDirectory(String dirId, Path path) { | ||
| this.dirId = Objects.requireNonNull(dirId); | ||
| this.path = Objects.requireNonNull(path); | ||
| } | ||
|
|
||
|
Comment on lines
+14
to
+20
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider adding format validation for dirId. While null checks are good, consider adding validation for the Here's a suggested implementation: public record CiphertextDirectory(String dirId, Path path) {
+ private static final Pattern UUID_PATTERN =
+ Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
public CiphertextDirectory(String dirId, Path path) {
this.dirId = Objects.requireNonNull(dirId);
+ if (!UUID_PATTERN.matcher(dirId).matches()) {
+ throw new IllegalArgumentException("dirId must be a valid UUID");
+ }
this.path = Objects.requireNonNull(path);
}
}Don't forget to add the import: import java.util.regex.Pattern; |
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package org.cryptomator.cryptofs; | ||
|
|
||
| import java.util.Objects; | ||
|
|
||
| //own file due to dagger | ||
|
|
||
| /** | ||
| * Helper object to store the dir id of a directory along with its cleartext name (aka, the last element in the cleartext path) | ||
| * @param dirId | ||
| * @param clearNodeName | ||
| */ | ||
| record DirIdAndName(String dirId, String clearNodeName) { | ||
|
|
||
| public DirIdAndName(String dirId, String clearNodeName) { | ||
| this.dirId = Objects.requireNonNull(dirId); | ||
| this.clearNodeName = Objects.requireNonNull(clearNodeName); | ||
| } | ||
|
|
||
infeo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.