FastPrepKey-Value Locks with Waiting Queues

Key-Value Locks with Waiting Queues

Klaviyo logoKlaviyo● MediumFULLTIMEOA
Learn

Problem statement

Process a sequence of operations on a key-value store. Each existing key has a value, at most one lock owner, and a first-in, first-out queue of waiting users. Only its current owner may update or delete it.

For this exercise, use the following sequential operation contract. Process one complete operation before starting the next; you do not need to create operating-system threads.

Operations

  • ["CREATE", key, value]: create an unlocked record when the key is absent and return "true". If it exists, leave all state unchanged and return "false".
  • ["GET", key]: return its current value, or "null" if absent. Reading does not require a lock.
  • ["LOCK", key, user]: return "missing" if the record is absent. Return "already_owned" if this user owns it, or "already_queued" if the user is already waiting. Otherwise, acquire an unlocked record and return "acquired", or append the user to the waiting queue and return "queued".
  • ["UPDATE", key, user, value]: replace the value and return "true" only if the user is the current owner. Otherwise return "false".
  • ["DELETE", key, user]: remove the record, owner, and entire waiting queue and return "true" only if the user is the current owner. Otherwise return "false".
  • ["UNLOCK", key, user]: return "false" unless the user currently owns the existing record. Otherwise return "true" and give ownership immediately to the earliest waiting user. Remove that user from the queue. If nobody is waiting, leave the record unlocked.

An unlocked record cannot be updated or deleted until a user acquires its lock. A user may independently own or wait for multiple keys. Deleting and recreating a key starts a new record with no inherited lock or waiting users. Return one string per operation, in input order.

Function

processLockOperations(operations: String[][]) → String[]

Examples

Example 1

operations = [["CREATE","k","old"],["LOCK","k","alice"],["LOCK","k","bob"],["UPDATE","k","bob","new"],["UNLOCK","k","alice"],["UPDATE","k","bob","new"],["GET","k"]]return = ["true","acquired","queued","false","true","true","new"]

Bob waits while Alice owns k. Alice releases it, so Bob receives ownership before the next operation and can update the value.

Example 2

operations = [["CREATE","x","v"],["LOCK","x","a"],["LOCK","x","b"],["LOCK","x","b"],["DELETE","x","a"],["CREATE","x","fresh"],["UPDATE","x","b","bad"],["LOCK","x","b"]]return = ["true","acquired","queued","already_queued","true","true","false","acquired"]

A repeated request does not add another queue entry. Deleting the record clears its owner and queue. The recreated record starts unlocked.

Constraints

  • 1 <= operations.length <= 100000.
  • Each row has exactly the fields of one valid operation listed above.
  • Keys, values, and user names contain 1 to 50 ASCII letters, digits, or underscores.

More Klaviyo problems

See Klaviyo hiring insights
public String[] processLockOperations(String[][] operations) {
    // Write your code here
}
operations[["CREATE","k","old"],["LOCK","k","alice"],["LOCK","k","bob"],["UPDATE","k","bob","new"],["UNLOCK","k","alice"],["UPDATE","k","bob","new"],["GET","k"]]
expected["true", "acquired", "queued", "false", "true", "true", "new"]
Checking account…