dragonfly icon indicating copy to clipboard operation
dragonfly copied to clipboard

consistent expiration semantics

Open romange opened this issue 3 years ago • 2 comments

Currently, each thread updates its expiry clock independently from others and independently from the ongoing transactions.

  1. We should move expiration clock sampling to transaction. Transaction should have a constant number used through all its operations, otherwise we risk having inconsistent replies within a transaction for GET X...some delay GET X sequences.
  2. We should consider having a single atomic variable for the clock so that transactions clocks will have monotonic property. I do not think it's strictly necessary but we may consider it.

romange avatar Mar 07 '22 06:03 romange

See https://ably.com/blog/redis-keys-do-not-expire-atomically for motivation.

if we use transactions to set expiry or to access multiple possibly expired items, we should use a consistent clock value during the transaction execution.

current behavior: we use real clock to set expiry and to test it.

romange avatar May 11 '22 05:05 romange

high level design

We can use lamport clock mixed with the wall clock.

  1. When we start a transaction we sample the wall clock, and bind its value to that transaction.
  2. When we perform the operations on DbSlice we should use the clock value from that transaction. For that we should replace all DbSlice interfaces like FindExt(DbIndex db_ind, std::string_view key) const; to FindExt(const Context& cntx, std::string_view key) const; and pass the clock via Context. In fact, I will probably adapt the interfaces ASAP.
  3. DbSlice::now_ms_ should disappear.
  4. We do delete items outside of transactions (active/bakground expiry) and this is why we need the lamport clock semantics. We will provide a shard level now_ms_ clock updated transparently by incoming transactions based on max(old, new) logic. This won't require any walltime sampling - just a simple integer update. Background processes will use this clock and it will be guaranteed that this clock won't delete items that the ongoing transaction does not consider expired. We can transparently update shard clock clock inside EngineShard::RunInShard method .

Some notes:

  • sampling high-resolution clock is relatively expensive (~100ns CPU time) - but absl::GetCurrentTimeNanos() is probably faster. I use it in EngineShard::Heartbeat. We should add the explicit benchmarks to dragonfly_test

  • (copy them from https://github.com/romange/gaia/blob/master/base/walltime_test.cc#L155)

  • Once we get rid of UpdateExpireClock calls in heartbit, we can decrease the frequency of heartbit and get rid of hz flag because today hz=1000 is only because we must update expire clock every ms.

romange avatar Sep 09 '22 07:09 romange

was fixed in 1.0

romange avatar Apr 29 '23 13:04 romange