| Crates.io | whale |
| lib.rs | whale |
| version | 0.1.0 |
| created_at | 2025-02-19 15:07:53.158839+00 |
| updated_at | 2025-02-19 15:07:53.158839+00 |
| description | A lock-free, dependency-tracking primitive for incremental computation. |
| homepage | https://github.com/ryo33/whale |
| repository | https://github.com/ryo33/whale |
| max_upload_size | |
| id | 1561509 |
| size | 55,083 |
A lock-free, dependency-tracking primitive for incremental computation.
[!WARNING] This is WIP, and any API is not working yet.
Whale is designed to be a low-level primitive for building a high-level incremental computing systems. So it does not provide,
If you need those, you can:
The system seamlessly supports a mixture of:
The main API functionalities are:
Get a node: runtime.get(query_id: QueryId)
Returns the node of the query. And you can get the version, dependencies, dependents, and invalidation states from the returned node.
Iterate over all nodes: runtime.keys()
Returns all query IDs in the runtime.
Registering Dependencies: runtime.register(query_id: QueryId, dependencies: Vec<Pointer>)
Registers a new version of a query with its dependencies. This effectively manages pairs of query_id and version, and invalidates the dependents of the previous version. This returns both the new and old nodes, and also all invalidations that transitively invalidated by this registration.
Updating Dependencies: runtime.update_dependencies(query_id: QueryId, dependencies: Vec<Pointer>)
Almost same as register, but this does not invalidate the dependents of the previous version by this update.
Typically, this is used when a query is invalidated and recalculated and it does produce the same result as the previous version. If dependencies are the same, prefer the uninvalidate instead.
Uninvalidating a node: runtime.uninvalidate(revision_pointer: RevisionPointer)
Mark a specific revision state of a node as not invalidated. This is typically used when a query is recalculated and it does produce the same result as the previous version. If dependencies are changed, use update_dependencies instead.
Removing an invalidator: runtime.remove_invalidator(pointer: Pointer, revision_pointer: RevisionPointer)
Removes an invalidation reason from a revision state. This method is used when a query has marked as invalidated by a depended query had invalidated it, and confirmed that the query actually does not need to be re-computed.
Removing a node: runtime.remove(query_id: QueryId)
Removes a node from the runtime. If the node is returned and has dependents, they will be marked as invalidated, and the full list is returned within the result.
Detecting a cycle: runtime.has_cycle(query_id: QueryId)
Detects a cycle in the dependency graph. Even while a graph has cycles, the whole system should work correctly and methods should not hang in infinite loops.
Freeing a unused node: runtime.remove_if_unused(query_id: QueryId)
Removes a node from the runtime if it is not depended by any other queries. This is useful for manual garbage collection when combined with keys() to iterate over all nodes.
Whale is built around a lock-free dependency graph where nodes represent computations and edges represent their dependencies. The core components work together to provide efficient dependency tracking:
Runtime: The central coordinator that manages the dependency graph. It's lock-free and safe to clone, making it easy to share across threads.
Node: A vertex in the dependency graph representing a computation. Each node maintains:
Pointer: A reference to a specific version of a computation, consisting of:
RevisionPointer: An extended pointer that includes invalidation state, used to:
The system uses atomic operations and immutable data structures to achieve thread safety without locks:
This design allows multiple threads to concurrently:
Whale maintains consistency through several key mechanisms:
Version Monotonicity: For each query (not a Runtime-wide), its version number only increases, ensuring a clear timeline of changes.
Cyclic safety: The system is consistent while there are cycles in the dependency graph. Also, it does not hang in infinite loops even if there are cycles in the dependency graph.
Invalidation Guarantees: The system provides guarantees about invalidation:
No Guarantees About:
Licensed under either of
at your option.