From d9cfe07e53fe5c8f80f10135c17f65abbf2cb4f9 Mon Sep 17 00:00:00 2001 From: crschnick Date: Sat, 18 Jan 2025 12:17:42 +0000 Subject: [PATCH] Small save improvements --- .../xpipe/app/storage/DataStoreCategory.java | 6 +++- .../io/xpipe/app/storage/StandardStorage.java | 31 +++++++++---------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java b/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java index 0754fdf5c..e765dbf78 100644 --- a/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java +++ b/app/src/main/java/io/xpipe/app/storage/DataStoreCategory.java @@ -191,6 +191,11 @@ public class DataStoreCategory extends StorageElement { return; } + // Reset the dirty state early + // That way, if any other changes are made during this save operation, + // the dirty bit can be set to true again + dirty = false; + ObjectMapper mapper = JacksonMapper.getDefault(); ObjectNode obj = JsonNodeFactory.instance.objectNode(); ObjectNode stateObj = JsonNodeFactory.instance.objectNode(); @@ -209,6 +214,5 @@ public class DataStoreCategory extends StorageElement { FileUtils.forceMkdir(directory.toFile()); Files.writeString(directory.resolve("category.json"), entryString); Files.writeString(directory.resolve("state.json"), stateString); - dirty = false; } } diff --git a/app/src/main/java/io/xpipe/app/storage/StandardStorage.java b/app/src/main/java/io/xpipe/app/storage/StandardStorage.java index 2fd2dbcfd..0d2dff588 100644 --- a/app/src/main/java/io/xpipe/app/storage/StandardStorage.java +++ b/app/src/main/java/io/xpipe/app/storage/StandardStorage.java @@ -327,13 +327,16 @@ public class StandardStorage extends DataStorage { public void saveAsync() { // If we are already loading or saving, don't queue up another operation. // This could otherwise lead to thread starvation with virtual threads + // Technically the load and save operations also return instantly if locked, but let's not even create new // threads here - synchronized (busyIo) { - if (busyIo.isLocked()) { - saveQueued = true; - return; - } + + // Technically we would have to synchronize the saveQueued update to avoid a rare lost update + // but in practice it doesn't really matter as the save queueing is optional + // The last dispose save will save everything anyway, it's about optimizing before that + if (busyIo.isLocked()) { + saveQueued = true; + return; } ThreadHelper.runAsync(() -> { @@ -353,11 +356,9 @@ public class StandardStorage extends DataStorage { } // We don't need to wait on normal saves though - synchronized (busyIo) { - if (!dispose && !busyIo.tryLock()) { - saveQueued = true; - return; - } + if (!dispose && !busyIo.tryLock()) { + saveQueued = true; + return; } if (!loaded || disposed) { @@ -424,12 +425,10 @@ public class StandardStorage extends DataStorage { disposed = true; } - synchronized (busyIo) { - busyIo.unlock(); - if (!dispose && saveQueued) { - // Avoid stack overflow by doing it async - saveAsync(); - } + busyIo.unlock(); + if (!dispose && saveQueued) { + // Avoid stack overflow by doing it async + saveAsync(); } }