LockUpgrade

mill.internal.LockUpgrade
object LockUpgrade

Helpers for the common "check under a read lock, then optionally re-run under a write lock" pattern.

Attributes

Source
LockUpgrade.scala
Graph
Supertypes
class Object
trait Matchable
class Any
Self type

Members list

Type members

Classlikes

enum Decision[+T]

Attributes

Source
LockUpgrade.scala
Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
class Scope

Attributes

Source
LockUpgrade.scala
Supertypes
class Object
trait Matchable
class Any

Value members

Concrete methods

def readThenWrite[T](acquireRead: => Lease, tryAcquireWrite: () => Either[String, Lease], awaitStateChange: Long => Unit, waitReporter: WaitReporter, awaitTimeoutMs: Long = ...)(readBody: Scope => Decision[T])(writeBody: Scope => T): T

Retryable read-then-write upgrade.

Retryable read-then-write upgrade.

  1. Acquire Read, run readBody. If Decision.Complete, return.
  2. If Decision.Escalate, release Read and try Write non-blocking (tryAcquireWrite). If that succeeds, run writeBody under the Write lease and return.
  3. If tryAcquireWrite returns scala.Left (lock contended), awaitStateChange for a bounded interval, then loop back to step 1.

Non-blocking try-Write turns long bounded waits into fast cache-hit re-probes: when launcher A is publishing under Write and B wants to compute the same task, B's blocking-Write would wait for A's publish AND for A's downgraded Read (retained for A's downstreams). With try-Write + retry, B fails its Write attempt, then re-acquires Read (which shares with A's Read), and readBody sees the just-published cache and returns Decision.Complete — no Write needed. The bounded awaitStateChange keeps the retry cheap: the lock notifyAlls on every close/downgrade, so retries fire exactly when a re-probe might newly succeed.

tryAcquireWrite MUST NOT register the caller as a queued writer (i.e., must not increment any waiter counter that gates Read acquisition); otherwise the caller's own next Read attempt would trip writer-priority and the retry loop would stall.

Attributes

Source
LockUpgrade.scala