Systems

Systems & Concurrency

36 techniques · 24 tradeoffs · 32 big-O entries across concurrency, distributed systems, database internals, and networking & OS.

Practice the quiz

Concurrency

24
Big O
Time complexity of a single `AtomicLong.incrementAndGet()` under no contention.
O(1)

One CAS (Compare-And-Swap) instruction succeeds on the first try; the loop runs exactly once. The hardware `LOCK CMPXCHG` is constant time.

Expected time for a single `AtomicLong.incrementAndGet()` when n threads are hammering the same counter simultaneously.
O(n)

Each contender retries the CAS until it wins. With n threads racing, the expected number of retries per successful increment scales with n — the cache line ping-pongs between cores.

Time complexity of acquiring a mutex when no other thread currently holds it.
O(1)

Uncontended acquire is one CAS on the lock word — constant time. No syscall, no context switch.

Expected time of `ConcurrentHashMap.get(key)` in Java 8+ with n entries.
O(1)

Same as a regular hash map: hash to a bucket, scan the (usually tiny) bucket. Reads in Java 8's `ConcurrentHashMap` are entirely lock-free; the only synchronization is `volatile` reads of bucket heads.

Time complexity of `ArrayBlockingQueue.offer(item)` (enqueue) when the queue is not full.
O(1)

Array-backed ring buffer: take the lock, write at the tail index, advance the index, release. Each step is constant time. The blocking on full is separate from the algorithmic complexity.

Expected time of `ConcurrentSkipListMap.get(key)` for a map of n entries.
O(log n)

Skip list lookup expects O(log n) levels with O(1) work per level. The 'concurrent' part is about lock-free traversal via CAS — it doesn't change the asymptotic complexity.

Total work to recursively fork+join a divide-and-conquer task of size n that does O(n) merge work (like parallel mergesort) on a work-stealing scheduler.
O(n log n)

Same as serial mergesort total work — work stealing changes wall-clock (span) by a factor of the worker count, not total work. The scheduler adds O(1) per fork/join on average via per-thread deques.

Time complexity of `CopyOnWriteArrayList.add(item)` on a list of size n.
O(n)

Each write allocates a fresh array and copies all n existing elements, then atomically swaps the reference. That's why copy-on-write is for read-mostly state — writes are linear.

Distributed Systems

24
Techniques
Raft Consensus

Leader-based consensus protocol: one elected leader replicates an append-only log to followers; entries commit once a majority quorum acknowledges.

Quorum Reads/Writes (R + W > N)

Tune per-operation consistency by requiring W replicas to ack writes and R replicas to answer reads. If R + W > N, every read overlaps the latest write.

Vector Clocks / Version Vectors

Each replica tags writes with a per-node counter map. Comparing two versions reveals causal order, concurrency, or strict dominance.

Gossip Protocol

Each node periodically picks a random peer and exchanges state. Information spreads epidemically in O(log n) rounds with bounded per-node bandwidth.

Leader Election via Leases

A would-be leader acquires a time-bounded lease in a consensus store; it must renew before expiry or lose leadership. Bounds split-brain to one lease window.

Merkle Tree Anti-Entropy

Replicas build a tree of hashes over their key ranges; comparing root then children lets them find divergent ranges in O(log n) hops instead of full scans.

CRDT (Conflict-Free Replicated Data Type)

Data types whose merge function is commutative, associative, and idempotent, so any two replicas converge to the same value without coordination.

Two-Phase Commit (2PC)

Coordinator asks all participants to PREPARE; if all vote yes it sends COMMIT, otherwise ABORT. Blocks if the coordinator crashes between phases.

Hinted Handoff

If a target replica is down, a healthy node stores the write locally with a 'hint' and forwards it once the target recovers. Keeps write availability high.

Chain Replication

Replicas arranged in a chain: writes enter at the head, flow through every link, commit at the tail. Reads served by tail give linearizable results with simple logic.

Big O
Messages sent per Raft commit in a cluster of n nodes (leader-to-followers, ignoring batching).
O(n)

Leader sends one AppendEntries to each of n - 1 followers and receives n - 1 acks. That's 2(n - 1) = O(n) messages per commit round.

Rounds for a piece of state to reach all n nodes under uniform random gossip.
O(log n)

Each round, the number of informed nodes roughly doubles (push gossip), so full coverage happens in ~log2(n) rounds with high probability.

Comparisons needed to find a single divergent key between two replicas using a Merkle tree over n keys.
O(log n)

Compare roots; descend only into the mismatched child at each level. Tree depth is log n, so one mismatch is found in log n hash comparisons.

Network round trips for a quorum read in a leaderless system with R replicas contacted in parallel.
O(1)

The coordinator fires R reads in parallel and waits for the first R acks. That's one round-trip regardless of R, modulo tail latency.

Messages exchanged in a two-phase commit with n participants and one coordinator (happy path).
O(n)

Prepare to n participants + n votes back + Commit to n + n acks = 4n = O(n). Plus log-force fsyncs at coordinator and each participant.

Cost to look up which of n nodes owns a given key on a consistent-hash ring with sorted virtual nodes.
O(log n)

Binary search the sorted ring of virtual-node positions for the first one >= hash(key). With v virtual nodes per real node, that's O(log(n * v)).

Comparing two vector clocks over k writer nodes to determine causal order.
O(n)

You must inspect every entry in both clocks (treat n as the number of distinct writer ids in the union) to decide dominates / concurrent. Linear in the size of the clock.

End-to-end latency of a write in chain replication with n replicas (in hops).
O(n)

The write must traverse head -> middle -> tail sequentially, so latency is proportional to chain length n in network hops.

Database Internals

22
Big O
Point lookup in a B+tree index of n keys.
O(log n)

Descend from root to leaf following the key. Each node holds many keys, so a billion-row index is typically only 3-4 levels deep, but the asymptotic cost is O(log n).

Point read in an LSM tree with L levels and n total keys (no bloom filter).
O(log n)

Each level is roughly k times larger than the one above. A read probes the memtable, then potentially one SSTable per level. With L = O(log n) levels, the work is O(log n).

Point lookup in a hash index (in-memory, well-tuned).
O(1)

Hash the key, jump to the bucket, walk a short collision chain (or use open addressing). No order, so no range scans.

Sequential scan of a table with n rows and no usable index.
O(n)

Read every page, evaluate the filter, emit matches. Cost model is roughly n / pages_per_second; parallelism lowers the wall clock but not the asymptotic work.

Membership test in a bloom filter with k hash functions.
O(1)

Hash the key k times, check k bits. No false negatives; false positives are tunable via bits-per-key and k.

Range scan over a B+tree returning k results from a table of n rows.
O(n + m)

B+tree leaves are doubly-linked, so once you find the start key the scan is a linear walk through k entries. This is exactly why B+trees beat hash indexes for ranges.

Checking whether a row version is visible to a given MVCC snapshot.
O(1)

Look at the tuple's xmin (creating txn) and xmax (deleting txn). Compare against the snapshot. The active-xid list is small in healthy systems.

Building a B+tree index from scratch on n existing rows.
O(n log n)

Index builds typically sort the key column (O(n log n)), then bulk-load sorted leaves and walk up to build internal pages. Online builds (CONCURRENTLY) add a second pass to catch concurrent writes.

Networking & OS

22
Techniques
TCP Congestion Control (Reno / Cubic / BBR)

Algorithms that decide how fast TCP (Transmission Control Protocol) sends. Loss-based (Reno, Cubic) treat packet loss as congestion; model-based (BBR) measures bottleneck bandwidth and round-trip time (RTT) directly.

TLS Handshake (1.2 vs 1.3)

TLS (Transport Layer Security) 1.2 needs 2 round trips before app data flows. TLS 1.3 collapses that to 1 round trip (1-RTT) for new sessions and 0 round trips (0-RTT) for resumed ones using pre-shared keys (PSK).

HTTP/2 Multiplexing

Many concurrent streams over a single TCP (Transmission Control Protocol) connection, each with its own flow control. Fixes HTTP (Hypertext Transfer Protocol) 1.1 head-of-line blocking at the HTTP layer but not at TCP.

HTTP/3 over QUIC

HTTP (Hypertext Transfer Protocol) 3 runs over QUIC, a UDP (User Datagram Protocol) based transport with built-in TLS (Transport Layer Security) 1.3, per-stream flow control, and connection migration across IP changes.

Connection Pooling and Keepalive

Reuse TCP (Transmission Control Protocol) and TLS (Transport Layer Security) connections across requests instead of opening a new one each time. Avoids the 3-way handshake plus TLS handshake on every call.

TCP_NODELAY (disable Nagle)

Nagle's algorithm coalesces small writes to reduce tinygrams. Combined with delayed-ACK on the receiver, it can stall small request/response pairs for ~40ms waiting for the next ack.

Event-driven I/O (epoll / kqueue / io_uring)

Readiness-based (epoll, kqueue) or completion-based (io_uring, IOCP) APIs that let one thread watch tens of thousands of file descriptors without a thread per connection.

Zero-copy (sendfile / splice)

Move bytes from disk to socket without copying through user space. The kernel hands page-cache pages directly to the NIC's DMA engine.

Big O
Cost to resolve a fully-qualified domain name with a cold cache, in terms of the depth d of the DNS hierarchy (root -> TLD -> authoritative -> ...). Treat depth as log of the total namespace.
O(log n)

Each level narrows the namespace by a large branching factor, so depth is logarithmic in the number of possible names. In practice it is 2-4 hops, and TTL caching collapses most lookups to O(1).

TCP slow-start doubles the congestion window each RTT until it hits ssthresh. Rounds to reach a window of n segments?
O(log n)

Doubling each RTT means n = 2^k after k rounds, so k = log2(n). This is why short connections never reach full bandwidth: by the time slow-start ramps, the flow is done.

Cost of one wait() call in epoll (edge-triggered, ready list) when there are n watched file descriptors and k are ready?
O(1)

epoll keeps a kernel-side ready list updated as events arrive. wait() just hands you the ready entries. poll/select rescan all n fds every call, which is what kills them at large n.

Cost of a virtual-to-physical address translation on x86-64 with a 4-level page table and a TLB miss?
O(log n)

Each page-table level indexes 9 bits of the virtual address, so the number of levels is logarithmic in the virtual address space size. On TLB hit, the translation is free (cached); on miss, the MMU walks all 4 levels.

Cost in CPU time of a single kernel-mediated context switch between two threads on the same core?
O(1)

Constant work per switch: save registers, swap kernel stack, restore registers, maybe swap address space (TLB flush). The constant is small (~1-5 microseconds) but multiplied across millions of switches per second it dominates.

Bytes and round trips for a TLS 1.3 handshake on a new connection, ignoring certificate size?
O(1)

Fixed message exchange independent of payload size. TLS 1.2 was 2-RTT for new sessions; 1.3 cut that to 1 by sending key share in ClientHello.

Cost in CPU time of copying an n-byte buffer between user space and kernel space (e.g., read/write syscall)?
O(n)

Bytes have to be physically copied (or at least mapped) one by one. This is what zero-copy (sendfile, splice, MSG_ZEROCOPY, io_uring fixed buffers) eliminates by handing pages to the device directly.

Hops to route a packet to its destination in a structured network with hierarchical addressing (IP prefix routing), in terms of n total nodes?
O(log n)

Each routing decision narrows the address space by a prefix, so depth grows logarithmically with the size of the address space. Real internet paths are usually 10-20 hops regardless of destination because of CIDR aggregation.