Inventory Reservation Service
Problem
Design InventoryReservationService for an online store. An order may hold a number of product units for five logical minutes while payment completes. The hold is either confirmed or expires, and several threads may share one service instance.
Requirements
- Create products.
addProductcreates a new product with its initial available count. - Restock products.
restockadds units to available stock without changing active reservations. - Report availability.
availablereleases reservations for that product whose expiry tick is at mostnow, then returns its available count. - Reserve safely.
reservefirst applies due expiry for the product, then atomically holds the requested units for five minutes and returnstruewhen enough stock is available; otherwise it returnsfalsewithout changing stock. - Confirm once.
confirmreturnstrueexactly once for an active reservation whennowis earlier than its expiry tick. Unknown and repeated confirmations returnfalse. - Expire holds. At
reservedAt + 5or later, an unconfirmed reservation releases its units exactly once and confirmation returnsfalse. - Coordinate threads. Public calls are linearizable, stock is never oversold, restocks are not lost, and confirmation and expiry cannot both win for one reservation.
API
| Signature | Returns | Behavior |
|---|---|---|
InventoryReservationService() | Not applicable | Creates an empty service. |
addProduct(productId: string, initialCount: integer) | void | Creates one uniquely identified product. |
available(productId: string, now: integer) | integer | Applies due expiry for the product and returns available stock. |
restock(productId: string, count: integer) | void | Adds units to available stock. |
reserve(productId: string, count: integer, orderId: string, now: integer) | boolean | Attempts to create a five-minute hold. |
confirm(orderId: string, now: integer) | boolean | Attempts to confirm an active unexpired hold. |
Examples
For one product:
| Operation | Result |
|---|---|
addProduct("sku-1", 5) | |
reserve("sku-1", 3, "order-a", 10) | true |
available("sku-1", 10) | 2 |
confirm("order-a", 14) | true |
confirm("order-a", 14) | false |
reserve("sku-1", 2, "order-b", 20) | true |
available("sku-1", 25) | 2 |
If two threads each try to reserve four of the last five units at tick 0, exactly one reservation succeeds. The other returns false, and one unit remains available.
Constraints
- Product IDs and order IDs are non-empty strings of at most 64 characters.
- Product IDs and order IDs are unique when created.
0 <= initialCount <= 1,000,000,000,000.1 <= count <= 1,000,000,000,000.0 <= now <= 1,000,000,000,000.- Concurrent time-aware calls in one phase use the same
now; later phases use nondecreasing ticks. - At most 1,000 products and 10,000 public method calls occur in one testcase.
- Inputs satisfy these constraints.
Notes
A tick is an integer minute supplied by the caller. Each thread's calls take effect in their listed program order. Calls from different threads may take effect in any interleaving consistent with each thread's order. Every public call is atomic and linearizable: it takes effect at one point between invocation and return. Methods may briefly wait for internal synchronization, but they do not wait for stock, confirmation, or time to pass. No cross-thread arrival order or fairness is promised.