Skip to content
This repository was archived by the owner on Mar 14, 2025. It is now read-only.

Commit 638a134

Browse files
committed
Merge branch 'develop' into release/1.1.0
2 parents 8830244 + 387a45b commit 638a134

File tree

2 files changed

+79
-77
lines changed

2 files changed

+79
-77
lines changed

src/main/java/org/cryptomator/cloudaccess/MetadataCachingProviderDecorator.java

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.google.common.cache.CacheBuilder;
55
import org.cryptomator.cloudaccess.api.CloudItemList;
66
import org.cryptomator.cloudaccess.api.CloudItemMetadata;
7+
import org.cryptomator.cloudaccess.api.CloudItemType;
78
import org.cryptomator.cloudaccess.api.CloudPath;
89
import org.cryptomator.cloudaccess.api.CloudProvider;
910
import org.cryptomator.cloudaccess.api.ProgressListener;
@@ -17,18 +18,19 @@
1718
import java.util.Optional;
1819
import java.util.concurrent.CompletableFuture;
1920
import java.util.concurrent.CompletionStage;
21+
import java.util.concurrent.ExecutionException;
2022

2123
public class MetadataCachingProviderDecorator implements CloudProvider {
2224

2325
private final static int DEFAULT_CACHE_TIMEOUT_SECONDS = 10;
2426

25-
final Cache<CloudPath, Optional<CloudItemMetadata>> itemMetadataCache;
26-
final Cache<CloudPath, Optional<Quota>> quotaCache;
27+
final Cache<CloudPath, CompletionStage<CloudItemMetadata>> itemMetadataCache;
28+
final Cache<CloudPath, CompletionStage<Quota>> quotaCache;
2729
private final CloudProvider delegate;
2830

2931
public MetadataCachingProviderDecorator(CloudProvider delegate) {
3032
this(delegate, Duration.ofSeconds( //
31-
Integer.getInteger("org.cryptomator.cloudaccess.metadatacachingprovider.timeoutSeconds", DEFAULT_CACHE_TIMEOUT_SECONDS)
33+
Integer.getInteger("org.cryptomator.cloudaccess.metadatacachingprovider.timeoutSeconds", DEFAULT_CACHE_TIMEOUT_SECONDS) //
3234
));
3335
}
3436

@@ -40,45 +42,29 @@ public MetadataCachingProviderDecorator(CloudProvider delegate, Duration cacheEn
4042

4143
@Override
4244
public CompletionStage<CloudItemMetadata> itemMetadata(CloudPath node) {
43-
var cachedMetadata = itemMetadataCache.getIfPresent(node);
44-
if (cachedMetadata != null) {
45-
return cachedMetadata //
46-
.map(CompletableFuture::completedFuture) //
47-
.orElseGet(() -> CompletableFuture.failedFuture(new NotFoundException()));
48-
} else {
49-
return delegate.itemMetadata(node) //
50-
.whenComplete((metadata, exception) -> {
51-
if (exception == null) {
52-
assert metadata != null;
53-
itemMetadataCache.put(node, Optional.of(metadata));
54-
} else if (exception instanceof NotFoundException) {
55-
itemMetadataCache.put(node, Optional.empty());
56-
} else {
57-
itemMetadataCache.invalidate(node);
58-
}
59-
});
45+
try {
46+
return itemMetadataCache.get(node, () -> delegate.itemMetadata(node).whenComplete((metadata, throwable) -> {
47+
// immediately invalidate cache in case of exceptions (except for NOT FOUND):
48+
if (throwable != null && !(throwable instanceof NotFoundException)) {
49+
itemMetadataCache.invalidate(node);
50+
}
51+
}));
52+
} catch (ExecutionException e) {
53+
return CompletableFuture.failedFuture(e);
6054
}
6155
}
6256

6357
@Override
6458
public CompletionStage<Quota> quota(CloudPath folder) {
65-
var cachedMetadata = quotaCache.getIfPresent(folder);
66-
if (cachedMetadata != null) {
67-
return cachedMetadata //
68-
.map(CompletableFuture::completedFuture) //
69-
.orElseGet(() -> CompletableFuture.failedFuture(new QuotaNotAvailableException()));
70-
} else {
71-
return delegate.quota(folder) //
72-
.whenComplete((quota, exception) -> {
73-
if (exception == null) {
74-
assert quota != null;
75-
quotaCache.put(folder, Optional.of(quota));
76-
} else if (exception instanceof NotFoundException || exception instanceof QuotaNotAvailableException) {
77-
quotaCache.put(folder, Optional.empty());
78-
} else {
79-
quotaCache.invalidate(folder);
80-
}
81-
});
59+
try {
60+
return quotaCache.get(folder, () -> delegate.quota(folder).whenComplete((metadata, throwable) -> {
61+
// immediately invalidate cache in case of exceptions (except for NOT FOUND and QUOTA NOT AVAILABLE):
62+
if (throwable != null && !(throwable instanceof NotFoundException) && !(throwable instanceof QuotaNotAvailableException)) {
63+
quotaCache.invalidate(folder);
64+
}
65+
}));
66+
} catch (ExecutionException e) {
67+
return CompletableFuture.failedFuture(e);
8268
}
8369
}
8470

@@ -89,7 +75,7 @@ public CompletionStage<CloudItemList> list(CloudPath folder, Optional<String> pa
8975
evictIncludingDescendants(folder);
9076
if (exception == null) {
9177
assert cloudItemList != null;
92-
cloudItemList.getItems().forEach(metadata -> itemMetadataCache.put(metadata.getPath(), Optional.of(metadata)));
78+
cloudItemList.getItems().forEach(metadata -> itemMetadataCache.put(metadata.getPath(), CompletableFuture.completedFuture(metadata)));
9379
}
9480
});
9581
}
@@ -118,9 +104,11 @@ public CompletionStage<InputStream> read(CloudPath file, long offset, long count
118104
public CompletionStage<Void> write(CloudPath file, boolean replace, InputStream data, long size, Optional<Instant> lastModified, ProgressListener progressListener) {
119105
return delegate.write(file, replace, data, size, lastModified, progressListener) //
120106
.whenComplete((nullReturn, exception) -> {
121-
if (exception != null) {
122-
itemMetadataCache.invalidate(file);
107+
if (exception == null) {
108+
itemMetadataCache.put(file, CompletableFuture.completedFuture(new CloudItemMetadata(file.getFileName().toString(), file, CloudItemType.FILE, lastModified, Optional.of(size))));
123109
quotaCache.invalidateAll();
110+
} else {
111+
itemMetadataCache.invalidate(file);
124112
}
125113
});
126114
}
@@ -130,14 +118,16 @@ public CompletionStage<CloudPath> createFolder(CloudPath folder) {
130118
return delegate.createFolder(folder) //
131119
.whenComplete((metadata, exception) -> {
132120
itemMetadataCache.invalidate(folder);
121+
quotaCache.invalidateAll();
133122
});
134123
}
135124

136125
@Override
137126
public CompletionStage<Void> deleteFile(CloudPath file) {
138127
return delegate.deleteFile(file) //
139128
.whenComplete((nullReturn, exception) -> {
140-
itemMetadataCache.put(file, Optional.empty());
129+
CompletionStage<CloudItemMetadata> future = CompletableFuture.failedFuture(new NotFoundException());
130+
itemMetadataCache.put(file, future);
141131
quotaCache.invalidateAll();
142132
});
143133
}
@@ -147,7 +137,8 @@ public CompletionStage<Void> deleteFolder(CloudPath folder) {
147137
return delegate.deleteFolder(folder) //
148138
.whenComplete((nullReturn, exception) -> {
149139
evictIncludingDescendants(folder);
150-
itemMetadataCache.put(folder, Optional.empty());
140+
CompletionStage<CloudItemMetadata> future = CompletableFuture.failedFuture(new NotFoundException());
141+
itemMetadataCache.put(folder, future);
151142
quotaCache.invalidateAll();
152143
});
153144
}
@@ -156,8 +147,8 @@ public CompletionStage<Void> deleteFolder(CloudPath folder) {
156147
public CompletionStage<CloudPath> move(CloudPath source, CloudPath target, boolean replace) {
157148
return delegate.move(source, target, replace) //
158149
.whenComplete((path, exception) -> {
159-
itemMetadataCache.invalidate(source);
160-
itemMetadataCache.invalidate(target);
150+
evictIncludingDescendants(source);
151+
evictIncludingDescendants(target);
161152
quotaCache.invalidateAll();
162153
});
163154
}

0 commit comments

Comments
 (0)