FastPrepDurable String Key-Value Store
Problem · Design

Durable String Key-Value Store

Learn this problem
MediumOpenAI logoOpenAIFULLTIMEPHONE SCREEN

Problem statement

Implement a durable string key-value store by processing an ordered array of commands. The store starts with an empty in-memory map and an empty durable log file.

Each command produces exactly one string result:

  • ["PUT", key, value]: atomically store value under key, overwriting any earlier value, and append one durable log record for this write. Return OK.
  • ["GET", key]: return VALUE: followed by the current value, or NOT_FOUND when the key is absent.
  • ["SERIALIZE"]: return one deterministic snapshot of the current map.
  • ["DESERIALIZE", snapshot]: replace the current map with snapshot, rewrite the durable log to represent exactly that loaded state, and return OK.
  • ["RECOVER"]: discard the in-memory map, replay the complete durable log in order, and return OK.

Record and Snapshot Format

Encode one key/value pair as <keyLength>:<key><valueLength>:<value>, where each length is a base-10 integer and the key and value follow their lengths without extra separators. For example, key user with value bob becomes 4:user3:bob. Length prefixes allow keys and values to contain digits and colons.

Every PUT appends one record in that format to the log. Recovery replays records from first to last, so later records for the same key win. A snapshot concatenates one record for each current key in lexicographic key order; the empty map serializes to the empty string. Every DESERIALIZE input is a valid snapshot produced by this format. Deserialization replaces both memory and the log, recording the decoded pairs in snapshot order so a later recovery reconstructs the loaded state.

Return the result of every command in the same order as operations.

Function

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

Examples

Example 1

operations = [["PUT","user","alice"],["GET","user"],["PUT","user","bob"],["RECOVER"],["GET","user"],["SERIALIZE"]]return = ["OK","VALUE:alice","OK","OK","VALUE:bob","4:user3:bob"]

The second PUT overwrites the in-memory value and appends a later log record. Recovery replays both records, so the later value bob wins. The final snapshot contains the one current pair.

Example 2

operations = [["PUT","b","two"],["PUT","a","one"],["SERIALIZE"],["DESERIALIZE","1:a3:one1:c5:three"],["GET","b"],["GET","c"],["RECOVER"],["SERIALIZE"]]return = ["OK","OK","1:a3:one1:b3:two","OK","NOT_FOUND","VALUE:three","OK","1:a3:one1:c5:three"]

Serialization sorts keys, so a precedes b. Deserialization replaces the old state, making b absent, and rewrites the log so recovery preserves exactly the loaded a and c pairs.

Example 3

operations = [["PUT","x:y",""],["SERIALIZE"],["RECOVER"],["GET","x:y"],["GET","missing"]]return = ["OK","3:x:y0:","OK","VALUE:","NOT_FOUND"]

The length-prefixed format safely stores a colon in the key and an empty value. The tagged VALUE: result distinguishes that stored empty value from a missing key.

Constraints

  • 1 <= operations.length <= 2000
  • Each command has exactly the fields described above.
  • 1 <= key.length <= 100.
  • 0 <= value.length <= 1000.
  • Keys and values contain printable ASCII characters.
  • Every snapshot passed to DESERIALIZE is a valid output of the specified snapshot format.
  • The total number of characters across all commands is at most 2 * 10^5.

More OpenAI problems

drafts saved locally
public String[] processStore(String[][] operations) {
    // Write your code here.
}
operations[["PUT","user","alice"],["GET","user"],["PUT","user","bob"],["RECOVER"],["GET","user"],["SERIALIZE"]]
expected["OK", "VALUE:alice", "OK", "OK", "VALUE:bob", "4:user3:bob"]
checking account