fix threading issue in notification manager

Signed-off-by: Armin Schrenk <armin.schrenk@skymatic.de>
This commit is contained in:
Armin Schrenk
2025-12-05 11:53:43 +01:00
parent 83199eb1de
commit 9d464e3a4f
2 changed files with 29 additions and 24 deletions

View File

@@ -266,7 +266,7 @@ public class Vault {
private void consumeVaultEvent(FilesystemEvent e) {
fileSystemEventAggregator.put(this, e);
notificationManager.tryAddEvent(this, e);
notificationManager.offer(this, e);
}
// ******************************************************************************

View File

@@ -3,26 +3,24 @@ package org.cryptomator.event;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.nio.file.Path;
import java.time.Duration;
import java.util.ArrayDeque;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Manager for notifications.
* <p>
* To add (filesystem) events, use method {@link #tryAddEvent(Vault, FilesystemEvent)}. If the input event is eligible, it is added to an internal queue.
* To add (filesystem) events, use method {@link #offer(Vault, FilesystemEvent)}. If the input event is eligible, it is added to an internal queue.
* An event is eligible, if
* <li>
* <ul>the event should trigger a notification and</ul>
* <ul>it is not added within the last {@value DEBOUNCE_THRESHOLD_SECONDS} seconds</ul>
* </li>
* <ul>
* <li>the event should trigger a notification and</li>
* <li>it is not added within the last {@value DEBOUNCE_THRESHOLD_SECONDS} seconds</li>
* </ul>
*
*/
@Singleton
@@ -30,31 +28,38 @@ public class NotificationManager {
private static final int DEBOUNCE_THRESHOLD_SECONDS = 5;
Cache<Path, FilesystemEvent> eventCache;
Queue<VaultEvent> eventsRequiringNotification;
Cache<FSEventBucket, FilesystemEvent> eventCache;
ConcurrentLinkedQueue<VaultEvent> eventsRequiringNotification;
@Inject
public NotificationManager() {
eventCache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(DEBOUNCE_THRESHOLD_SECONDS)).build();
eventsRequiringNotification = new ArrayDeque<>();
eventsRequiringNotification = new ConcurrentLinkedQueue<>();
}
public boolean tryAddEvent(Vault v, FilesystemEvent e) {
var notRecentlyAdded = switch (e) {
case BrokenFileNodeEvent bfne -> isRecent(bfne.ciphertextPath(), bfne);
/**
* Offers the given filesystem event to the notification manager.
*
* @param v The vault where the filesystem event happened
* @param e the actual filesystem event
* @return {@code true} if the filesystem event is accepted, otherwise {@code false}.
*/
public boolean offer(Vault v, FilesystemEvent e) {
return switch (e) {
//example: case BrokenFileNodeEvent bfne -> addEvent(v, bfne.ciphertextPath(), bfne);
default -> false;
};
if (notRecentlyAdded) {
}
boolean addEvent(Vault v, Path keyPath, FilesystemEvent e) {
var key = new FSEventBucket(v, keyPath, e.getClass());
var cachedElement = eventCache.get(key, _ -> {
synchronized (this) {
eventsRequiringNotification.add(new VaultEvent(v, e));
}
}
return notRecentlyAdded;
}
boolean isRecent(Path key, FilesystemEvent e) {
var cacheElement = eventCache.get(key, _ -> e);
return cacheElement == e;
return e;
});
return cachedElement != e;
}
/**