Class LeaderLease

java.lang.Object
com.loomcache.server.consensus.LeaderLease

public class LeaderLease extends Object
Leader lease with clock skew protection for safe linearizable reads.

The leader lease allows a leader to safely serve linearizable reads from its local state without a quorum round-trip, as long as:

  • A majority of followers have acknowledged recent heartbeats
  • The lease has not expired (with clock skew safety margin applied)

Clock Skew Protection:

The lease validity check includes a safety margin (maxClockSkewNanos) to account for clock drift between the leader and followers:

  isValid = currentTime + maxClockSkew invalid input: '<' leaseStart + leaseDuration

This asymmetry ensures that when the leader's lease appears valid locally, it is GUARANTEED to still be valid on all followers (even if their clocks are ahead by up to maxClockSkew). Conversely, when the leader's lease expires locally, followers cannot yet claim they elected a new leader.

Lease Renewal:

The leader renews the lease each time a majority of followers acknowledge heartbeats. The lease is extended from the current time by leaseDuration.

Safety Invariants:

  • If leader's lease is valid, no follower can have elected a new leader
  • If leader's lease is expired, followers may have elected a new leader
  • The gap between leader's view and follower's view is bounded by maxClockSkew
  • Constructor Details

    • LeaderLease

      public LeaderLease(LeaseConfig config, Clock clock)
      Create a leader lease with the given configuration.
      Parameters:
      config - lease configuration
      clock - clock source for timing
  • Method Details

    • create

      public static LeaderLease create()
      Create a leader lease with default config and system clock.
      Returns:
      new LeaderLease with defaults
    • renew

      public void renew()
      Renew the lease to expire in leaseDurationNanos from now.

      This should be called whenever a majority of followers acknowledge a heartbeat. The lease is extended from the current time.

    • isValid

      public boolean isValid()
      Check if the lease is currently valid.

      The lease is valid if the current time (plus the clock skew safety margin) is still less than the lease expiration time.

      Important: The clock skew margin is applied to the current time, not the expiration time. This ensures the leader's local check is pessimistic: we assume our clock could be slow by up to maxClockSkew, so we expire the lease earlier to guarantee followers haven't elected a new leader.

      Returns:
      true if the lease is valid (considering clock skew), false otherwise
    • canServeRead

      public boolean canServeRead()
      Check if the lease is valid and track rejections if not.

      This is a convenience method for read operations that should be rejected if the lease is invalid.

      Returns:
      true if lease is valid, false otherwise
    • expiresAt

      public long expiresAt()
      Get the current lease expiration time in nanoseconds.
      Returns:
      System.nanoTime() when the lease expires, or Long.MIN_VALUE if lease is invalid
    • remainingNanos

      public long remainingNanos()
      Get the remaining lease duration in nanoseconds.

      Returns 0 or negative value if the lease has expired.

      Returns:
      nanoseconds until lease expiration
    • remainingMs

      public long remainingMs()
      Get the remaining lease duration in milliseconds.

      Returns 0 or negative value if the lease has expired.

      Returns:
      milliseconds until lease expiration
    • renewalCount

      public long renewalCount()
      Get lease renewal count.
      Returns:
      number of times the lease has been renewed
    • expirationCount

      public long expirationCount()
      Get lease expiration count.
      Returns:
      number of times the lease has expired
    • rejectionCount

      public long rejectionCount()
      Get read rejection count due to expired lease.
      Returns:
      number of read operations rejected due to lease expiration
    • resetStats

      public void resetStats()
      Reset all statistics.
    • invalidate

      public void invalidate()
      Invalidate the lease immediately.

      This is used when the leader steps down or loses quorum.

    • leaseStartNanos

      public long leaseStartNanos()
      Get the lease start time in nanoseconds.

      For testing and diagnostics only.

      Returns:
      System.nanoTime() when the lease was started
    • leaseDurationNanos

      public long leaseDurationNanos()
      Get the configured lease duration in nanoseconds.

      For testing and diagnostics only.

      Returns:
      lease duration in nanoseconds
    • maxClockSkewNanos

      public long maxClockSkewNanos()
      Get the configured maximum clock skew in nanoseconds.

      For testing and diagnostics only.

      Returns:
      maximum clock skew in nanoseconds