Timestamped Parcel Attribute Store With Compare-and-Set, Prefix Listing and TTL
AirbnbSoftware Engineer · Online AssessmentLast updated
Implement a timestamped in-memory store of parcel attributes with overwriting set, get and a compare-and-set update, then list attributes as name(value) sorted by name with an optional prefix filter, and finally add per-attribute TTLs that hide expired values. It tests precise operation semantics, expiry rules and incremental class design.
Implement an in-memory store of parcels. Each parcel is identified by a parcel ID and can hold many attributes with different names, each attribute being a name with a value. Every operation is called with a timestamp. The exercise is a timed, level-based coding assessment checked by automated tests, with four levels in 90 minutes, and each level extends the same class. The three reported levels are below.
Constraints and Clarifications
- An attribute holds exactly one value. Writing it again replaces the value; no history of earlier values is kept.
- Every method takes a timestamp, including at the first two levels, where the timestamp affects no result.
- The method names and argument orders below are one consistent reconstruction of the reported operations; return values for missing data are to be confirmed (see the questions).
- Correctness is what is scored: a straightforward, brute-force implementation that passes the tests is acceptable.
Clarifying Questions
- What does
getreturn for an unknown parcel or attribute:None, an empty string, or something else? What dosetand the conditional update return? - Are values strings, and is a "match" exact, case-sensitive equality?
- Can the conditional update create an attribute that does not exist yet?
- Do timestamps increase from call to call?
Part 1 — Set, get and conditional update
Implement:
set(timestamp, parcel_id, attribute, value): storevalueunderattributefor the parcel, overwriting any existing value.get(timestamp, parcel_id, attribute): return the attribute's current value.update_if_match(timestamp, parcel_id, attribute, expected, new_value): set the attribute tonew_valueonly if its current value equalsexpectedexactly; otherwise change nothing.
What This Part Should Cover
- A nested store keyed by parcel ID and attribute name
- Overwrite semantics, without unnecessary history or time ordering
- Compare-then-write behavior that changes nothing on a mismatch or a missing attribute
Part 2 — Listing attributes
Add:
list_attributes(timestamp, parcel_id): return every attribute of the parcel formatted asname(value), ordered lexicographically by attribute name.list_attributes_with_prefix(timestamp, parcel_id, prefix): the same, restricted to attributes whose names start withprefix.
Clarifying Questions for this Part
- Is the result a list of strings or a single joined string, and with what separator?
- What is returned for an unknown parcel, or for a parcel with no matching attributes?
- Is the order plain, case-sensitive string comparison of the names?
What This Part Should Cover
- Ordering by attribute name and the exact
name(value)output format - A prefix filter on the attribute name that reuses the unfiltered listing's logic
- Empty and unknown-parcel results
Part 3 — Time-to-live
Each attribute now has a time-to-live. set and update_if_match gain a ttl argument. A ttl of 0 means the attribute never expires; otherwise it expires ttl time units after it is written. get and both listing operations must ignore expired attributes. update_if_match must not update an expired attribute, but it can update an unexpired one, including setting its ttl to 0 so that it never expires.
Clarifying Questions for this Part
- Is an attribute written at time
wwith ttldstill visible at exactlyw + d? - Does a successful write restart the lifetime from its own timestamp, using the ttl passed in that call?
- What ttl applies when a call omits it, for example the level 1 calls that existing tests still make?
What This Part Should Cover
- What each stored value records so that expiry can be decided
- One liveness rule (ttl 0, the boundary, restart on write) applied to
get, both listings and the conditional update - Whether expired entries are hidden or removed
Hints
Hint 1
Shape of the store: A parcel ID leads to a set of named attributes with one value each. Choose the nesting that makes "does this parcel have this attribute" a single lookup.
Hint 2
Match means exact: Decide what the conditional update does when the attribute is missing, and make sure a failed match leaves the store untouched.
Hint 3
One listing, two callers: The two operations differ only in a filter on the name. Share the filtering, sorting and formatting so they can never disagree.
Hint 4
What a stored value must carry: Expiry should be decidable from the stored entry and the query timestamp alone. Work out what the entry must record at write time for that to hold.
Hint 5
One liveness test: The get, both listings and the conditional update all need the same "is this attribute alive at this timestamp" check. Put it in one place.
Follow-up questions
- How would you reclaim the memory held by expired attributes without slowing down reads?
- How would you support reading an attribute's value as of a past timestamp?
- If parcels have many attributes and prefix listings are frequent, what structure avoids sorting on every call?
- How would you keep `update_if_match` correct if several threads used the store at once?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.