mirror of
https://github.com/ZoneTree/ZoneTree.git
synced 2026-10-29 13:37:47 +08:00
Merge pull request #156 from ZoneTree/update-updater-delegate-docs-and-comments
Update updater delegate docs and comments.
This commit is contained in:
@@ -75,7 +75,9 @@ Reference types are still valid for large or complex values. Prefer immutable cl
|
||||
|
||||
Atomic update delegates receive a local `TValue` variable by `ref`. They are the controlled place where a value can be transformed as part of a ZoneTree write.
|
||||
|
||||
For value types, this is direct. For mutable reference types, in-place mutation is valid when the delegate commits by returning `true`.
|
||||
For value types, this is direct. For mutable reference types, assigning a new object to the `ref` parameter is the safest pattern. In-place mutation can be acceptable when the change is idempotent, repeatable, and never cancelled after mutation.
|
||||
|
||||
Some atomic methods can retry before they finish. If a delegate mutates an existing reference-type value in place, the shared object changes immediately, before ZoneTree has necessarily accepted the write, assigned an operation index, and appended the WAL record.
|
||||
|
||||
The cancellation case is the trap. Returning `false` tells ZoneTree not to write the local value back. If the delegate mutates a shared reference object before returning `false`, the object may already have changed in memory.
|
||||
|
||||
@@ -92,18 +94,4 @@ zoneTree.TryAtomicGetAndUpdate(1, out var user, (ref UserSnapshot value) =>
|
||||
});
|
||||
```
|
||||
|
||||
In-place mutation is fine when the update is definitely committed:
|
||||
|
||||
```csharp
|
||||
zoneTree.TryAtomicGetAndUpdate(1, out var user, (ref User value) =>
|
||||
{
|
||||
if (!ShouldRename(value))
|
||||
return false;
|
||||
|
||||
value.Name = "Bob";
|
||||
return true;
|
||||
});
|
||||
```
|
||||
|
||||
Returning `false` should mean the delegate made no observable change.
|
||||
|
||||
|
||||
@@ -117,7 +117,9 @@ Return `true` to commit the local value. Return `false` to cancel the write.
|
||||
|
||||
Keep delegates and result callbacks short and deterministic. `TryAtomicAddOrUpdate` may retry when the mutable segment is frozen or full, so adder/updater delegates can be invoked more than once before the method finishes. Avoid external side effects inside those delegates unless repeating the side effect is acceptable.
|
||||
|
||||
For mutable reference types, decide before mutating. Returning `false` prevents ZoneTree from writing a new value, but it cannot undo in-place changes already made to a shared object reference.
|
||||
For mutable reference types, assigning a new object to the `ref` parameter is the safest pattern. In-place mutation can be acceptable when the change is idempotent, repeatable, and never cancelled after mutation. It still changes the shared object immediately, before ZoneTree has necessarily accepted the write, assigned an operation index, and appended the WAL record.
|
||||
|
||||
Returning `false` prevents ZoneTree from writing a new value, but it cannot undo in-place changes already made to a shared object reference.
|
||||
|
||||
```csharp
|
||||
zoneTree.TryAtomicGetAndUpdate(1, out var user, (ref UserSnapshot value) =>
|
||||
|
||||
@@ -116,7 +116,9 @@ public interface IZoneTree<TKey, TValue> : IDisposable
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add or update the specified key and value atomically across LSM-Tree segments and calls the result delegate atomically.
|
||||
/// valueUpdater can be called one or more times.
|
||||
/// valueUpdater can be called one or more times. Keep it deterministic and avoid side effects that cannot be repeated.
|
||||
/// When TValue is a mutable reference type, assigning a new object is the safest pattern.
|
||||
/// In-place mutation should be idempotent and must not be followed by cancellation.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the element to add.</param>
|
||||
/// <param name="valueToAdd">The value of the element to add. It can be null.</param>
|
||||
@@ -133,10 +135,12 @@ public interface IZoneTree<TKey, TValue> : IDisposable
|
||||
/// <summary>
|
||||
/// Attempts to add or update the specified key and value atomically across LSM-Tree segments and calls the result delegate atomically.
|
||||
/// valueAdder can be called one or more times.
|
||||
/// valueUpdater can be called one or more times.
|
||||
/// valueUpdater can be called one or more times. Keep delegates deterministic and avoid side effects that cannot be repeated.
|
||||
/// When TValue is a mutable reference type, assigning a new object is the safest pattern.
|
||||
/// In-place mutation should be idempotent and must not be followed by cancellation.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the element to add.</param>
|
||||
/// <param name="valueAdder">he delegate function that adds the value.</param>
|
||||
/// <param name="valueAdder">The delegate function that adds the value.</param>
|
||||
/// <param name="valueUpdater">The delegate function that updates the value.</param>
|
||||
/// <param name="result">The operation result delegate.</param>
|
||||
/// <returns>true if the key/value pair was added;
|
||||
|
||||
@@ -132,6 +132,8 @@ zoneTree.TryAtomicAddOrUpdate(
|
||||
});
|
||||
```
|
||||
|
||||
For mutable reference values, assigning a new object in the updater is the safest pattern. Add/update delegates may be retried, so in-place mutations should be idempotent and side effects should be repeatable.
|
||||
|
||||
Plain `Upsert` is the fastest write path. Atomic methods are synchronized with other atomic methods and are intended for operations that must read, decide, and write as one logical action.
|
||||
|
||||
For normal concurrent writes, use the regular write APIs. They are designed for high-throughput use. Choose atomic methods only when the new value depends on the existing value.
|
||||
|
||||
Reference in New Issue
Block a user