Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* FIXED: Retry JSON parse on read to tolerate concurrent partial-file writes
* FIXED: A failing commit action no longer hangs other callers in the same batch
* FIXED: Collection key in file not matching configured case is now matched case-insensitively, instead of reading empty and duplicating the key on save
* FIXED: Run DataStore's commit handler on its own background thread, so writes are not delayed when the application's thread pool is busy

### [2.4.2] - 2023-06-25
* FIXED: Duplicate collection data to JSON on save when configured case was not used with collection name
Expand Down
44 changes: 30 additions & 14 deletions JsonFlatFileDataStore/DataStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,39 @@ public DataStore(string path, bool useLowerCamelCase = true, string keyProperty

_jsonData = GetJsonObjectFromFile();

// Run updates on a background thread and use BlockingCollection to prevent multiple updates to run simultaneously
Task.Run(() =>
// Run updates on a dedicated background thread and use BlockingCollection to prevent multiple updates to run simultaneously.
// The handler blocks on Take() for the whole lifetime of the store, so it must not sit on a thread pool thread: a process
// holding several stores would then permanently occupy that many pool threads and starve every other continuation.
var commitHandlerThread = new Thread(() =>
{
CommitActionHandler.HandleStoreCommitActions(_cts.Token,
_updates,
executionState => _executingJsonUpdate = executionState,
jsonText =>
{
lock (_jsonData)
try
{
CommitActionHandler.HandleStoreCommitActions(_cts.Token,
_updates,
executionState => _executingJsonUpdate = executionState,
jsonText =>
{
_jsonData = JObject.Parse(jsonText);
}
lock (_jsonData)
{
_jsonData = JObject.Parse(jsonText);
}

return FileAccess.WriteJsonToFile(_filePath, _encryptJson, jsonText);
},
GetJsonTextFromFile);
}
catch
{
// Keeps the previous Task.Run semantics, where an exception escaping the handler
// ended the loop as an unobserved task exception instead of tearing down the process.
}
Comment thread
ttu marked this conversation as resolved.
})
{
IsBackground = true,
Name = "JsonFlatFileDataStore commit handler"
};

return FileAccess.WriteJsonToFile(_filePath, _encryptJson, jsonText);
},
GetJsonTextFromFile);
});
commitHandlerThread.Start();
}

public void Dispose()
Expand Down
Loading