Hybrid Logical Clock
Hybrid Logical Clock (HLC) is a distributed-systems clock construction that combines the physical wall-clock time of an operation with a logical Lamport-style counter to produce timestamps that are simultaneously close-to-real-time and causally consistent. Each timestamp is a pair
(l, c)wherelis the largest physical-clock reading observed at this node so far (its own clock or a peer’s clock learned from a message), andcis a small logical counter used to order events that happen “at the same physical millisecond.” The protocol is three rules: on a local event, the node reads its physical clockpt, sets the newltomax(pt, l_old)and incrementscifldid not advance (else resetscto 0); on send, the node attaches its current(l, c)to the message; on receive with incoming(l_m, c_m), the node sets the newltomax(l_old, l_m, pt)and computescbased on which of the three was maximum (taking the existingcplus 1 ifl_oldwon, takingc_mplus 1 ifl_mwon, resetting to 0 ifptwon, breaking ties withmax(c_old, c_m) + 1). Two HLC timestamps(l_a, c_a) < (l_b, c_b)lexicographically iffa → b(causally before), giving the samehappens-beforedecidability as scalar Lamport clocks but with timestamps that track real time within bounded skew. HLC was published by Sandeep Kulkarni, Murat Demirbas, and colleagues at SUNY Buffalo at OPODIS 2014 (Logical Physical Clocks). It was designed to give Spanner-class external consistency (causal + physical-time-aware ordering) without Spanner’s hardware dependency on atomic clocks and GPS receivers (Google’s TrueTime, see Distributed SQL Database System Design). Production adopters include CockroachDB (explicitly built on HLC), YugabyteDB, and MongoDB (which uses an HLC-style cluster-time mechanism for causal consistency). HLC is now a foundational primitive of modern distributed SQL databases: any database wanting to provide snapshot reads, serializable transactions, and consistent backups across geographic distribution without paying for atomic-clock hardware uses HLC or a close variant.
1. Plain-Language Definition
A clock in a distributed system has two jobs that pull in opposite directions.
It must capture causality — if event a caused event b, the timestamp of
a should be strictly less than the timestamp of b — and it should
approximate physical time — the timestamp should be close to the wall-clock
time when the event occurred, so that humans can interpret it, log lines from
different machines can be merged sensibly, and time-based queries (“show me
everything from 14:00–14:05”) return the right rows.
Lamport’s scalar logical clock (1978) solves causality but ignores physical
time: it is just a
monotonically-increasing integer that bears no relationship to wall-clock time.
A Lamport timestamp of 12345 doesn’t mean anything in seconds; you can’t
compare it to 2026-05-09 14:00:00.000.
Vector Clocks also solve causality but produce timestamps of size O(N) for
N nodes, growing without bound as the cluster scales. They also ignore
physical time.
Physical wall-clock timestamps (just now()) approximate physical time but
violate causality because clocks are not perfectly synchronized — a message
can be sent at 14:00:00.100 from a node whose clock is fast and arrive at a node
with a slow clock at “14:00:00.050” (50 ms in the past), making the receive look
like it happened before the send. Pure physical timestamps cannot be trusted
to order causally-related events.
Hybrid Logical Clock (HLC) is the engineering compromise that gets both. It is a clock that:
- Looks like a physical timestamp to within a small bounded error (typically a few milliseconds, bounded by the Network Time Protocol sync error).
- Strictly captures the
happens-beforerelation:a → b ⟹ HLC(a) < HLC(b)lexicographically. - Costs only
O(1)storage per timestamp (constant, regardless of cluster size, unlike vector clocks’O(N)). - Requires no special hardware (no atomic clocks, no GPS receivers — software-only, runs on any commodity server with NTP).
That combination is what makes HLC interesting: it gives the causal correctness of Lamport, the size efficiency that vector clocks lack, and the human-interpretable physical-time alignment that pure logical clocks lack. The cost is a small bounded error from real time.
2. Mechanism — The Three Rules
Every node i maintains a local HLC state consisting of two numbers:
l_i— the largest “logical-physical” timestamp this node has observed (either its own physical clock or a peer’s, whichever was larger).c_i— a small logical counter used to break ties within the samel.
Define pt_i to be the current reading of node i’s wall-clock (e.g.,
time.Now() in Go, gettimeofday() in C, System.currentTimeMillis() in
Java).
Rule 1 — Local event (or send) at node i. The node generates a fresh HLC timestamp:
l_old := l_i
l_i := max(l_old, pt_i)
if l_i == l_old:
c_i := c_i + 1 # physical clock didn't advance; bump logical counter
else:
c_i := 0 # physical clock advanced; reset logical counter
return (l_i, c_i)
The intuition: if the physical clock has moved forward since the last HLC
reading, use the new physical value and reset the logical counter to 0. If the
physical clock hasn’t moved (because two events happen within the same clock
tick, which is very common at high event rates), keep the old l and increment
the logical counter to give this event a strictly-larger HLC than the previous
one.
Rule 2 — Send. Send is just Rule 1 followed by attaching the resulting (l, c) to the outgoing message.
Rule 3 — Receive at node i of message with timestamp (l_m, c_m). The node
reconciles its own (l_i, c_i) with the sender’s (l_m, c_m):
l_old := l_i
l_i := max(l_old, l_m, pt_i)
if l_i == l_old and l_i == l_m:
c_i := max(c_i, c_m) + 1 # all three matched; combined logical counter
elif l_i == l_old:
c_i := c_i + 1 # local was the largest
elif l_i == l_m:
c_i := c_m + 1 # remote was the largest
else:
c_i := 0 # physical clock won; reset logical counter
return (l_i, c_i)
The key invariant: after Rule 3, the new (l_i, c_i) is strictly greater than
both (l_old, c_old) (the receiver’s previous state) and (l_m, c_m) (the
sender’s state) under lexicographic ordering. This is the property that gives
HLC its causal correctness.
sequenceDiagram participant A as Node A (clock: 100) participant B as Node B (clock: 102, 2ms ahead) Note over A: pt=100, send msg<br/>HLC = (100, 0) A->>B: msg with (100, 0) Note over B: receive: pt=102<br/>l = max(l_B_old, 100, 102) = 102<br/>c = 0 (physical won)<br/>HLC = (102, 0) Note over B: local event<br/>pt=102, l unchanged<br/>c = 1<br/>HLC = (102, 1) B->>A: msg with (102, 1) Note over A: receive: pt=101<br/>l = max(101, 102, 101) = 102<br/>c = c_m + 1 = 2<br/>HLC = (102, 2)
The diagram traces a 3-event sequence: A sends to B, B has a local event, B
sends to A. Even though A’s wall clock (100, then 101) lags B’s wall clock (102)
by 1–2 ms, the HLC produces a strictly-monotonic, causally-correct sequence:
(100,0) < (102,0) < (102,1) < (102,2). The l component tracks the larger of
the two clocks and is bounded above by the maximum across the cluster; the c
component handles the within-millisecond ties that physical time cannot resolve.
3. Origins — Kulkarni et al. 2014
HLC was published by Sandeep Kulkarni, Murat Demirbas, Deepak Madappa, Bharadwaj Avva, and Marcelo Leone at SUNY Buffalo, in the OPODIS 2014 paper Logical Physical Clocks and Consistent Snapshots in Globally Distributed Databases. The paper’s framing is explicit: HLC is designed for the use case where you need both causality (like Lamport / vector clocks) and a relationship to wall-clock time (like Spanner’s TrueTime), but you cannot afford TrueTime’s hardware dependency.
The paper’s contributions are: (1) the algorithm above, including the proof that
the HLC’s l component is bounded above by max_i pt_i + ε where ε is the
maximum clock skew across the cluster (i.e., HLC stays close to wall time); (2)
the proof that HLC strictly captures happens-before; (3) the proof that HLC is
O(1) per timestamp; (4) demonstration of how HLC enables consistent snapshot
reads and serializable transactions in a globally-distributed database without
requiring atomic-clock hardware.
The intellectual lineage runs from Lamport 1978 (scalar logical clocks for
causality, no physical time) → Mattern 1989 / Fidge 1988 (vector clocks for
full partial-order reconstruction, no physical time, O(N) size) → Spanner
2012 (Corbett et al., TrueTime
API
using atomic clocks and GPS to bound clock uncertainty, expensive hardware) →
HLC 2014 (Kulkarni et al., software-only approximation of TrueTime’s
properties using NTP-synchronized clocks plus Lamport-style counters). The HLC
paper explicitly positions itself as the answer to “can we build a
globally-distributed transactional database without TrueTime?“
4. Comparison with Vector Clocks
Vector Clocks capture the full happens-before partial order: given two
vector timestamps, you can determine whether a → b, b → a, or a ∥ b
(concurrent). This requires O(N) storage per timestamp for N nodes — every
timestamp carries one integer per node. Vector clocks cannot be compressed; the
size grows with cluster size, which becomes prohibitive at scales of thousands
of nodes.
HLC sacrifices the full partial-order reconstruction for O(1) size. With HLC
you can determine a → b ⟹ HLC(a) < HLC(b), but the converse is not guaranteed:
HLC(a) < HLC(b) does not imply a → b — the events might be concurrent but
happen to have been ordered by HLC’s lexicographic tiebreaker. This is the same
limitation as Lamport scalars: HLC gives a total order consistent with
causality, not the full causal partial order. For most use cases (especially
database transactions), the total order is exactly what you want — a transaction
needs a single commit timestamp, not a list of vector components.
The choice between HLC and vector clocks is therefore: do you need to detect concurrency (Dynamo-style sibling reconciliation, OR-Set CRDTs)? If yes, vector clocks. Do you need a causal total order with physical-time alignment for transaction commit ordering? If yes, HLC. Most modern transactional systems pick HLC; most CRDT-heavy systems pick vector clocks (or a refinement like dotted version vectors).
5. Comparison with Spanner’s TrueTime
Google Spanner (Corbett et al. OSDI
‘12)
achieves external consistency — the property that if transaction T1
commits before transaction T2 starts in real time, then T1’s commit
timestamp is less than T2’s commit timestamp — using the TrueTime API.
TrueTime exposes now() not as a single timestamp but as an interval
[earliest, latest] representing the bounded uncertainty in physical time.
Spanner machines are equipped with atomic clocks and GPS receivers that keep
the uncertainty interval narrow (typically 1–7 ms). Spanner’s commit protocol
enforces external consistency by waiting out the uncertainty: after
assigning a commit timestamp, the coordinator waits until TT.now().earliest > commit_ts, ensuring that any later transaction will see a strictly-later
timestamp.
HLC achieves a weaker but operationally similar property using only
NTP-synchronized clocks (no atomic clocks, no GPS). The HLC l component plays
the role of TrueTime’s “current time” reading, and the c component handles the
within-tick ordering that TrueTime would handle by waiting out uncertainty. The
trade-off is:
- TrueTime gives bounded uncertainty (the interval is small and known) and external consistency (real-time order respected).
- HLC gives causally consistent timestamps that are close to wall time but cannot be guaranteed to respect real-time order between non-causally-related transactions on machines with skewed clocks.
In practice, HLC’s weaker guarantee is sufficient for many use cases (snapshot reads, serializable transactions when paired with consensus like Raft) and dramatically cheaper. Spanner’s external consistency is needed when the database is the authoritative source of truth for real-world time-ordered events (e.g., financial trades, regulatory audit logs); HLC suffices when the database itself defines the order.
6. Worked Example — 3-Node Database with Skewed Clocks
Consider a 3-node distributed key-value database (nodes A, B, C) with the following clock skew:
- A’s wall clock is correct.
- B’s wall clock is 2 seconds ahead of true time.
- C’s wall clock is 1 second behind true time.
This is significant skew — modern NTP keeps clocks within tens of milliseconds — but illustrates the algorithm clearly. Suppose:
- True-time 100.000s: client writes
x=1to A. A’s clock reads 100.000. A’s HLC:(100.000, 0). - True-time 100.001s: A asynchronously replicates
x=1to B. B’s clock reads 102.001 (2s ahead). On receive, B computesl = max(l_B_old, 100.000, 102.001) = 102.001— B’s local clock is the maximum because B is fast.c = 0(physical won). B’s HLC:(102.001, 0). B writesx=1durably with this timestamp. - True-time 100.002s: a different client reads
xfrom C. C’s clock reads 99.002 (1s behind). C does not yet have the replicatedx=1. C returns the old valuex=0(or “not found”). - True-time 100.003s: A asynchronously replicates
x=1to C. C’s clock reads 99.003. On receive, C computesl = max(l_C_old, 100.000, 99.003) = 100.000— A’s HLC value wins because both C’s local HLC and C’s wall clock are smaller.c = 1(l matched l_m, increment c_m). C’s HLC:(100.000, 1). C writesx=1durably with this timestamp. - True-time 100.004s: a client now reads
xfrom B. The read carries no HLC (this is a fresh client). B returnsx=1with HLC(102.001, 0). - True-time 100.005s: the same client reads
xfrom C. The client passes the previously-seen HLC(102.001, 0)(this is causal consistency: the client says “I already saw timestamp ≥ (102.001, 0), don’t return anything older”). C compares its current HLC(100.000, 1)to the requested(102.001, 0). C’s HLC is less than what the client requires. C must either wait until its HLC catches up to(102.001, 0), fetch the requested key from a peer at the required HLC, or return an error. This is how HLC enables causal consistency for clients.
Two observations from this example:
First, despite B being 2 seconds ahead of true time, the HLC correctly preserves
the causal order: A’s write happened before B replicated it, and HLC’s l
component records this fact (the value passed from A to B was 100.000; B’s HLC
becomes 102.001 only because B’s local clock is the maximum, not because of
any replication ordering). The causal relationship A's write → B's replication
is preserved: (100.000, 0) < (102.001, 0) lexicographically.
Second, the HLC’s l value at B (102.001) is bounded by max-cluster-clock,
not by an unbounded counter. If B’s clock were to go backward (NTP step
adjustment or operator intervention), the HLC l would not decrease — it would
stay at 102.001 (because of the max in Rule 1) and c would increment for
subsequent events until B’s wall clock caught up again. This is the source of
one of HLC’s key practical properties: HLC is monotonic even when wall clocks
regress, which is critical for transaction-ordering correctness.
7. Variants and Implementations
CockroachDB. Uses HLC as its primary clock, documented explicitly in Living without atomic clocks. CockroachDB reads NTP-synchronized clocks and configures a maximum acceptable clock-offset bound (default 500 ms in production, configurable). If a node’s clock offset from peers exceeds the bound, the node self-terminates — it is unsafe to participate in HLC-coordinated transactions when the assumption of bounded skew is violated. This self-termination is a critical safety property; without it, a node with a runaway clock would issue HLC values far in the future, polluting the cluster’s HLC state.
YugabyteDB. Also uses HLC, derived from the same paper. YugabyteDB’s transactions overview documents the integration of HLC with Raft-replicated tablets to achieve serializable cross-shard transactions.
MongoDB. Implements an HLC-style mechanism called cluster_time for causal consistency (Causal Consistency Spec). The cluster_time is signed (HMAC-SHA1) to prevent clients from injecting fabricated timestamps that would manipulate snapshot reads. The signing detail is an important production hardening that the original HLC paper does not discuss.
Antidote / RedisGraph / etc. A number of research and production systems have adopted HLC or close variants for their snapshot-read implementations. The pattern has become a default for transactional distributed databases that don’t have access to TrueTime hardware.
Bounded HLC. One common practical variant caps the size of c (e.g., c < 2^16) and refuses to advance the HLC beyond the bound. This protects against a
degenerate case where the physical clock stalls for a very long time and c
grows arbitrarily; in production, a clock that has stalled for that long is
itself an incident that should be detected and addressed, so refusing to advance
is the right behavior.
HLC + bounded uncertainty (HLC-U). Recent research (post-2014) has explored adding an uncertainty interval to HLC to recover some of TrueTime’s properties without atomic clocks, by using NTP’s reported uncertainty instead. This is a topic of ongoing work; production systems generally use plain HLC.
8. Real-World Examples
CockroachDB transactions. When a CockroachDB transaction begins, it acquires
an HLC-derived read timestamp (the snapshot it will read from). Reads at that
timestamp see a consistent snapshot — every committed transaction with HLC less
than the read timestamp is visible; every later one is not. Writes happen at a
commit timestamp, also HLC-derived, and Raft groups serialize the writes
within a range. The combination of HLC + Raft achieves serializable isolation
across the cluster, with HLC providing the inter-shard ordering and Raft
providing the intra-shard linearizability. See Distributed SQL Database System
Design for the full architecture.
YugabyteDB DocDB. Same pattern: HLC for inter-shard ordering, Raft for intra-shard. YugabyteDB documentation calls out HLC by name and notes that consistent backups depend on HLC’s bounded-skew property.
MongoDB causal consistency. MongoDB clients can specify readConcern: {level: "majority"} with a clusterTime to get causal consistency: subsequent
reads will see at least the writes corresponding to the requested cluster_time.
This is exactly the “C reads with previously-seen HLC” pattern from the worked
example above. MongoDB’s clusterTime is HMAC-signed to prevent forgery.
MongoDB sessions and operationTime. MongoDB sessions track an
operationTime (the HLC of the most recent operation in the session);
subsequent operations in the session can causally chain via this value. This
enables “read your writes” consistency without forcing all reads through the
primary.
9. Tradeoffs
Bounded skew dependency. HLC’s correctness depends on the assumption that
wall clocks across the cluster stay within some bounded skew ε. If ε is
violated (e.g., NTP is broken on some node), the HLC l value can run far ahead
of physical time, and the protocol’s monotonicity guarantees still hold — but
the HLC stops being close to wall time, which breaks the property that makes HLC
useful for human-interpretable timestamps and time-based queries. CockroachDB’s
self-termination on out-of-bound clocks is the correct response to skew-bound
violations; systems that don’t enforce this are vulnerable to clock-runaway
scenarios.
O(1) but not full partial order. HLC compresses causality into a scalar (well, a pair), losing the ability to detect concurrency. For systems that need to detect concurrent updates and reconcile (Dynamo-style sibling resolution, OR-Set CRDTs, Git-style merge), vector clocks remain necessary. HLC is for systems that want a single global commit order, not for systems that need to track parallel branches of history.
Linearizability requires consensus. HLC does not provide linearizability across nodes — it provides causal-consistent ordering of events that have flowed through the system. To get linearizability (e.g., serializable transactions across multiple shards), HLC must be combined with a consensus protocol like Raft (within each shard) plus an inter-shard coordination mechanism. CockroachDB and YugabyteDB both do this. HLC alone is the clock; the transaction system is HLC + Raft + a transactional protocol.
Logical counter c growth. If the physical clock stalls (e.g., the host is
suspended or NTP regresses), c will grow with each event. In well-behaved
production environments, this is bounded — physical time advances continuously,
so c resets to 0 frequently. In pathological cases, c can grow without
bound; production implementations cap c and treat overflow as an incident. The
cap is typically set high enough (e.g., 2^16) that overflow signals real abuse
rather than normal operation.
10. Pitfalls
Unbounded clock skew breaks HLC. HLC’s safety properties (lexicographic
ordering captures causality) hold regardless of skew; HLC’s liveness
properties (timestamps stay near wall time) require bounded skew. A common
production failure: NTP is misconfigured on a single node, that node’s clock
drifts hours into the future, the node generates HLC values hours ahead of its
peers, those values propagate via replication, and now the entire cluster’s HLC
is hours ahead of wall time. Until the offending node’s clock is corrected (and
the cluster’s HLC waits for wall time to catch up), the cluster cannot accept
new writes that would correctly order with respect to wall time. The cure:
monitor NTP sync status across all nodes (Network Time Protocol integration
is mandatory), self-terminate nodes whose skew exceeds the configured bound,
alert on any HLC l value running materially ahead of wall time.
Logical counter overflow. If the physical clock stalls (suspend-resume on a
VM, NTP step adjustment that pushes the clock backward), c can grow unbounded
as events accumulate at the same l. Production caps c and rejects further
events when the cap is hit. The cap is typically large enough (e.g., 2^16 or
2^32) that hitting it requires a pathological scenario (tens of thousands of
events within a single physical millisecond), but the cap must be there.
Hitting the cap should trigger an alert; the response is typically to reset the
affected node’s clock and let HLC re-synchronize.
HLC alone does not give linearizability. A common interview misconception: “We’re using HLC, so our transactions are linearizable.” HLC only orders events that have flowed through the system; it does not coordinate concurrent transactions on different nodes. Two concurrent writes to the same key on two different shards may be assigned HLC values that order them, but the question of which write wins is decided by the consensus protocol layered on top. Without consensus (typically Raft or Paxos), HLC gives only causal consistency, not strong consistency. The full stack is HLC + Raft + transactional protocol, not HLC alone.
Treating HLC timestamps as wall time. Because HLC’s l component is close
to wall time, engineers sometimes use HLC values directly as if they were
wall-clock timestamps for time-based queries, log filtering, billing periods,
etc. This usually works but can fail subtly in two cases: (1) when a node’s
clock is briefly skewed forward, the HLC l jumps and stays elevated even after
the clock recovers, so a “between 14:00 and 14:05” query may include events
whose actual wall time was earlier; (2) when c is non-zero, two events with
the same l are ordered by c rather than by their actual wall-clock
micro-difference. For most uses this is fine; for forensic or regulatory
time-ordering, use a separate physical-time field.
Persisting HLC across restarts. A node restart that doesn’t persist its HLC
state will start with l = 0, then the first incoming message or local event
will set l to either the incoming peer’s l or pt, whichever is larger.
This is usually fine — the node will catch up to the cluster’s HLC on its
first interaction. But there is a brief window between restart and first
interaction in which the node’s HLC is artificially behind; if the node starts
serving reads in that window, it could return data older than its previous
state’s reads. Cure: persist the HLC l (and optionally c) on every commit,
restore on restart. CockroachDB and YugabyteDB both do this.
Forgetting to sign HLC values in adversarial environments. A client that fabricates an HLC value can manipulate snapshot reads (claim “I saw timestamp T”, forcing the database to wait for or reject the read). MongoDB’s HMAC-signed cluster_time is the production answer: only the database can issue cluster_time values, and clients must echo them back unforged. Systems that pass HLC to untrusted clients without signing are vulnerable to this attack; the fix is to sign or to wrap HLC in a session-local opaque token.
11. Interview Discussion
In a system-design interview, HLC comes up when discussing distributed
databases, snapshot isolation, causal consistency, or “how do we order events
without a global clock and without TrueTime.” A strong answer starts: “I’d use
Hybrid Logical Clocks. Each node combines its NTP-synchronized wall-clock
reading with a small logical counter. On every event, you take max(local, peer, wall) for the physical part and bump the counter for tiebreaking. This gives
you O(1) timestamps that are causally correct and close to wall time.”
Naming Kulkarni 2014 as the source (Logical Physical
Clocks)
is a strong signal.
Common follow-ups: “Why not use vector clocks?” — vector clocks are O(N) and
grow with cluster size; HLC is O(1). Vector clocks detect concurrency; HLC
gives a total order. Most transactional databases want the total order. “Why
not use TrueTime like Spanner?” — TrueTime requires atomic clocks and GPS
receivers; HLC is software-only. The trade is weaker (HLC doesn’t provide
external consistency without consensus on top), but it’s free. “What if a
node’s clock is way off?” — HLC’s safety holds regardless of skew, but liveness
and “close-to-wall-time” properties require bounded skew. CockroachDB
self-terminates nodes whose skew exceeds a configured bound (e.g., 500 ms);
other implementations alert and quarantine. “Does HLC give linearizability?” —
no, it gives causal consistency. Linearizability requires combining HLC with a
consensus protocol like Raft.
A weak candidate confuses HLC with TrueTime, claims “HLC is just a logical clock” without distinguishing it from Lamport, or proposes HLC as a substitute for consensus. The interview is testing whether the candidate can place HLC correctly in the stack: it is the clock, not the transaction system; the transaction system needs HLC plus consensus plus a protocol.
Cross-references: HLC’s predecessors are Vector Clocks (which it improves on for size) and Lamport scalars (which it improves on for time alignment); its dependency is Network Time Protocol (which provides the bounded-skew assumption); its consumer is Distributed SQL Database System Design (which uses HLC for snapshot isolation); its complement is Raft (which provides linearizability where HLC provides causality). For the broader story of why distributed clocks are hard, see the Vector Clocks note.
12. See Also
- Vector Clocks — the
O(N)causality-tracking primitive HLC compresses toO(1) - Network Time Protocol — the wall-clock synchronization mechanism HLC depends on for bounded skew
- Raft — the consensus protocol layered above HLC to provide linearizability for transactions
- Distributed SQL Database System Design — the architectural pattern that combines HLC + Raft + transactional protocols (CockroachDB, YugabyteDB)
- Service Level Objectives — clocks indirectly affect availability SLOs (clock failures cause real outages)
- Recovery Objectives — synchronous replication for tight RPO depends on consistent clocks
- SWE Interview Preparation MOC
- Major System Designs MOC