- Added optional
CancellationTokenparameters to ArrowDb async APIs, including factory initialization,SerializeAsync,RollbackAsync,GetOrAddAsync, andBeginTransaction. - Updated
GetOrAddAsyncfactory delegates to receive the activeCancellationToken. - Added
ArrowDb.DependencyInjectionwithIArrowDbProvider, the public genericArrowDbProvider<TSerializer>, and an optional hosted-service primer for eager startup initialization. ArrowDb.CreateCustom(...)now has an overload that acceptsdisposeSerializerso serializer ownership can be explicitly assigned;ArrowDbProvider<TSerializer>defaults to external serializer ownership and can opt into owning disposal.- Updated the public
IDbSerializercontract to receive an optionalCancellationTokenfor serialization and deserialization, trackIsDisposed, and implement bothIDisposableandIAsyncDisposable. - Transaction scopes can now carry a cancellation token into the outermost implicit serialize during disposal.
- This is a breaking release for callers implementing
IDbSerializeror callingGetOrAddAsyncwith the old delegate shapes. - Built-in file-backed serializers now use single-owner writable semantics and fail fast with
ArrowDbOwnershipExceptionif another process already owns the same database path. - Removed the previous cross-process writable safety claim from the built-in file serializer path; the persisted file remains a snapshot of the owning process state.
- Built-in file-backed serializers now perform true async file and JSON I/O internally instead of synchronous work behind async signatures.
- This is also a breaking release for custom types inheriting
BaseFileSerializer, which must implement the new async protected override surface. - Removed the previous sync-over-async dependency injection guidance from the docs; hosted DI is now documented through
ArrowDb.DependencyInjectionusing explicit serializer registration plusArrowDbProvider<TSerializer>.
- Improve correctness of internal change counting to ensure that changes that happened during serialization are still tracked.
TryGetValuewill now return true forvalue typesthat have a default value since it is a valid value for them.Upsertcan returnfalseif aRollbackAsyncoccurred concurrently, indicating the write was not reliable relative to the rollback (retry after rollback completes if needed).TryRemoveandTryClearcan returnfalseif aRollbackAsyncoccurred concurrently, indicating the operation was not reliable relative to the rollback.Clearis now obsolete; useTryClearto detect rollback races.
- File based serializers
FileSerializerandAesFileSerializernow use a new base class implementation and have gained the ability tojournal(maintain durability through crashes and otherIOException, and ensure successful atomic write or complete rejection of changes), and cross-process isolation, preventing race condition that could be caused when multiple processes try to access the sameArrowDbfile.- If you had a class implementing
FileSerializerthis change may or may not break functionality and you should run tests to ensure everything still works as expected (With that said, my tests were not broken and did not require any adjusting).
- If you had a class implementing
- Thread-safe counters types were changed from
inttolong, this includesPendingChangesandRunningInstances. ArrowDbTransactionScopewas updated to allow nested transactions, and prevent corruption that can be caused by multiple transactions running concurrently on the sameArrowDbinstance. In addition, it was madepublicand also implements the regularIDisposableinterface to allow usage in synchronous context. However, it is still your responsibility to ensure the contexts match.Upsertand all its overloads will now reject (returnfalse) whenever the value to be upserted is anullreference type. This is to enforce a nonullpolicy that will simplify development by eliminatingnullchecks on retrieved values.
- Random queued (Non serialized) operations are up to 20% faster due to improvement in cross-threaded state management.
- Serialization allocates up to 250% less memory 🔥 across all benchmarks.
GetOrAddAsyncandUpsert(which has theupdateConditionargument) now both have overloads that accept aTArgparameter as well as a modified factory function that can use it, in order to avoid closures.
- Added overloads of
Upsertthat accept astringkey, while theReadOnlySpan<char>overloads are amazing in specific cases where its use can prevent a string allocation for the lookup, in other places where the input was originally astringthat was implicitly converted to aReadOnlySpan<char>for the parameter, this would've caused a copy to be allocated for the key when the key did not exist. The same scenario will now use thestringoverload and use it for the key directly, avoiding the intermediate copy. - Added a
ValueTaskbasedGetOrAddAsyncmethod, commonly used in caching scenarios.
- An overload to
UpsertwithoutupdateConditionwas added and would now act as default path in caseupdateConditionwasn't specified, this should further optimize such cases by removing condition checks and another reference from the stack during runtime. - Internal methods which are rather small and frequently invoked will now be prioritized for inlining by JIT, this should slightly improve perf, especially in NativeAot.
- Added a new factory initializer
CreateFromFileWithAesthat received anAesinstance as parameter. It will then use it to encrypt and decrypt the output and input during serialization and deserialization respectively.
- Fixed issue with
FileSerializerwhere serialization would write over existing file data which could create invalid tokens, causing deserialization to fail. - Added static
ArrowDb.GenerateTypedKey<T>method that accepts the type of the value, specific key (identifier) and a buffer, it returns aReadOnlySpan<char>key that prefixes the type to the specific key.
- Initial Release