Qubit DCL
A standalone crate for double-checked locking over generic lock handles. It packages the usual “test outside the lock, lock, test again, run the task” sequence into a reusable DoubleCheckedLockExecutor, with an optional prepare / rollback / commit pipeline and structured results.
The crate re-exports ArcMutex and the Lock trait from qubit-lock so a typical app can depend on qubit-dcl alone.
Features
DoubleCheckedLockExecutor: one builder-built executor, many invocations; integrates with thequbit-functionTesterand runnable traits.DoubleCheckedLock: one-shot convenience entry foron(...).when(...).call*style execution without keeping an executor variable.- Double-checked flow: first condition check without the lock, optional pre-lock prepare, write lock, second check, then task; after the lock is released, optional prepare commit or rollback.
- Execution API:
call/execute(no direct&mut Tin the closure) andcall_with/execute_with(mutable access to protected data). - Typed outcomes:
ExecutionContextandExecutionResultdistinguish success, “condition not met,” task failure, and prepare finalization failures (ExecutorError). - Logging hooks via
logand configurableExecutionLoggeron the builder for unmet conditions and prepare-step failures; each event can also be disabled from the builder chain.
How it works
- The condition tester runs twice (outside the lock, then again under the write lock). Anything the first read relies on must remain safe without this executor’s lock (for example atomics with appropriate orderings).
- If the first test passes, an optional prepare runnable may run; then the lock is taken, the second test runs, and the user task runs with
&mut Tif applicable. - If prepare ran successfully, after releasing the lock the executor may run commit on full success, or rollback when the inner check or task did not succeed.
Panics from the tester, prepare callbacks, or task are not caught by default. Enable capture with .catch_panics(), or use .with_panic_capture(flag) when the setting comes from a boolean. Built executors also support .with_panic_capture(flag) and return a reconfigured executor. Tester and task panics become ExecutorError::Panic; prepare lifecycle panics become PrepareFailed, PrepareCommitFailed, or PrepareRollbackFailed. When prepare already succeeded, rollback can still run for captured task or second-check panics. When cloned executors run concurrently, several calls may complete prepare before one call wins the second condition check; losing calls run prepare rollback if it is configured.
Installation
[]
= "0.9"
qubit-dcl already depends on qubit-lock and re-exports ArcMutex and Lock; add a direct qubit-lock dependency only if you use types beyond those re-exports.
Public API paths
Import the lock trait from the crate root:
use Lock;
The old compatibility path qubit_dcl::lock::Lock is no longer provided. Use the root re-export above, or import qubit_lock::Lock directly when your code intentionally depends on qubit-lock.
Quick start
use ;
use ;
Side-effect–only run (finish)
For execute or call with no meaningful return value, you can use ExecutionContext::finish on ExecutionContext<(), E> to get a bool success:
use ;
let data = new;
let ok = builder
.on
.when
.build
.execute
.finish;
assert!;
finish() is intentionally lossy: both condition-not-met and execution failure
return false. Use try_finish() when you need to preserve task or prepare
errors:
use ;
let data = new;
let ok = builder
.on
.when
.build
.execute
.try_finish
.expect;
assert!;
One-shot convenience (DoubleCheckedLock)
When you do not need to keep a reusable executor, use DoubleCheckedLock for a shorter chain:
use ;
use ;
let data = new;
let skip = new;
let updated = on
.when
.call_with
.get_result;
assert!;
assert_eq!;
Example program
A runnable sample is under examples/double_checked_lock_executor_demo.rs:
Builder API (summary)
- Start with
DoubleCheckedLockExecutor::builder(). - Attach a lock:
.on(lock)whereL: Lock<T>. - Set the double-checked condition:
.when(tester). - Configure panic capture with
.catch_panics(),.with_panic_capture(flag), or.disable_catch_panics(). - Optionally:
.prepare,.rollback_prepare,.commit_preparefor the prepare pipeline. - Configure diagnostics with
.log_unmet_condition,.log_prepare_failure,.log_prepare_commit_failure,.log_prepare_rollback_failure; disable them with the matching.disable_*_loggingmethods. - Finish with
.build().
Project layout
src/double_checked: executor, builders,ExecutionContext,ExecutionResult, errors, and logging.tests/double_checkedandtests/docs: unit and README consistency tests.
Quality checks
RUSTDOCFLAGS="-D warnings"
License
Apache-2.0