eden/mononoke/docs/5.2-mercurial-sapling-support.md
This document explains how Mononoke supports Mercurial and Sapling clients. Mononoke was originally designed as a scalable Mercurial backend and retains extensive support for Mercurial protocols and data formats. As Mercurial evolved into Sapling, Mononoke evolved alongside it, and now primarily only support Sapling clients.
Mononoke originated as a scalable backend for Mercurial, which served as Meta's primary version control system. The initial design focused on supporting Mercurial clients while introducing Bonsai as an internal canonical format. This approach allowed Mononoke to scale beyond traditional Mercurial server implementations while preserving client compatibility.
As Mercurial development transitioned to the Sapling project, Mononoke continued serving clients through protocol evolution rather than architectural changes. The server maintained support for legacy Mercurial wire protocols while adding support for EdenAPI (now called SLAPI), an HTTP-based protocol that replaced older SSH-based communication.
Today, Mononoke serves primarily Sapling clients, and Mercurial wireproto support is being removed. For clarity, this document uses "Mercurial" to refer to the version control system and its data model, and "Sapling" to refer to the current client implementation. In the future we may evolve the data model as well, in which case we will likely refer to the new data model as the "Sapling" data model.
Mercurial uses a content-addressed data model based on nodes. Each node—whether a changeset, manifest, or file—is identified by a hash computed from its parents and content. This section describes the key Mercurial types that Mononoke handles.
Mercurial types are defined in mercurial/types/. The primary identifier types are:
HgChangesetId (mercurial/types/src/nodehash.rs)
HgManifestId (mercurial/types/src/nodehash.rs)
HgFileNodeId (mercurial/types/src/nodehash.rs)
Mercurial node hashes follow a consistent pattern:
node_hash = SHA1(p1_hash || p2_hash || content)
Where:
p1_hash is the first parent (null hash if no parent)p2_hash is the second parent (null hash if fewer than two parents)content is the serialized content specific to the node typeThis computation creates content-addressed Merkle DAGs for changesets, manifests, and files. The same content with different parents produces different hashes, embedding history in the identity.
Changesets (mercurial/types/src/blobs/changeset/)
Manifests (mercurial/types/src/blobs/manifest.rs)
Filenodes (mercurial/types/src/blobs/file.rs)
Mercurial wire protocols use several serialization formats:
Revlog Format (mercurial/revlog/)
Bundle2 Format (mercurial/bundles/)
Wirepack Format (mercurial/bundles/src/wirepack/)
Mononoke stores commits internally as Bonsai changesets and converts to Mercurial format when serving clients. The BonsaiHgMapping facet maintains bidirectional mappings between these representations.
The BonsaiHgMapping facet (repo_attributes/bonsai_hg_mapping/) provides mapping operations:
Core Operations:
get_hg_from_bonsai - Convert Bonsai changeset ID to Mercurial changeset IDget_bonsai_from_hg - Convert Mercurial changeset ID to Bonsai changeset IDadd - Store a new mapping entryget - Batch lookup supporting both directionsStorage:
CachingBonsaiHgMapping)When a Mercurial client pushes commits:
When a client requests data:
The conversion between Bonsai and Mercurial has the following characteristics:
Not Bijective - Multiple Bonsai changesets can map to the same Mercurial changeset ID if they differ only in metadata not represented in Mercurial format. In practice, mappings are effectively one-to-one due to compatibility constraints.
Deterministic - Given a Bonsai changeset, the derived Mercurial changeset ID is deterministic. This allows regeneration and verification.
Async Derivation - Mercurial representations can be derived asynchronously after Bonsai commits are stored. See the Derived Data section below.
Several derived data types exist specifically to support Mercurial and Sapling clients. These types provide data in formats expected by Mercurial protocols.
MappedHgChangesetId (derived_data/mercurial_derivation/)
This derived data type generates a Mercurial changeset from a Bonsai changeset. The derivation:
BonsaiHgMappingThis type is required for serving Mercurial clients and is typically derived on-demand or by background workers.
RootHgAugmentedManifestId (derived_data/mercurial_derivation/)
Augmented manifests are content-addressed directory trees in Mercurial format with additional metadata. Unlike traditional Mercurial manifests, augmented manifests include:
Augmented manifests enable efficient serving of tree data to Sapling clients without requiring full manifest computation. The derivation constructs Mercurial-compatible tree structures from Bonsai file changes.
Augmented manifests are stored in the blobstore using sharded storage for large directories. See mercurial/types/src/sharded_augmented_manifest.rs for the data structure.
Filenodes (derived_data/filenodes_derivation/)
Filenodes represent Mercurial's per-file history tracking. Each filenode records:
Filenodes are required for Mercurial wire protocol compatibility, particularly for operations like getfiles and getpackv1. The filenode derivation:
Legacy filenode implementation is in repo_attributes/filenodes/, while the derived data implementation is in derived_data/filenodes_derivation/.
Mercurial-specific derived data types have dependencies:
These dependencies ensure that Mercurial data can be derived consistently from Bonsai commits.
Mononoke supports multiple protocols for Mercurial and Sapling clients, reflecting the evolution of client-server communication.
EdenAPI, now called SLAPI (Sapling Remote API), is an HTTP-based protocol that replaced older Mercurial wire protocols. The implementation is in servers/slapi/slapi_service/.
Protocol Characteristics:
Major Endpoints (servers/slapi/slapi_service/src/handlers/):
files.rs) - Fetch file contents by content hash or pathtrees.rs) - Fetch directory manifestscommit.rs) - Upload commits and push operationshistory.rs) - Fetch file or directory historybookmarks.rs) - Fetch bookmark valueslookup.rs) - Resolve commit hashes and bookmarksblame.rs) - Fetch blame annotationsland.rs) - Landing (merge) operationscommit_cloud.rs) - Sync uncommitted work across machinesServing Process:
mononoke_api layerEdenAPI/SLAPI is the primary protocol used by modern Sapling clients and EdenFS.
The legacy Mercurial wire protocol (servers/slapi/wireproto_handler/) supports older Mercurial clients using SSH-based communication. This protocol:
The wire protocol handler converts between bundle2 format and Mononoke's internal operations. While still supported, most clients have migrated to EdenAPI/SLAPI.
Remotefilelog is a Mercurial extension that avoids downloading full file history by fetching file contents on-demand. Mononoke supports remotefilelog through:
Getpack Endpoint - Fetches file contents in wirepack format Getcommitdata - Fetches commit metadata without manifests Gettreepack - Fetches tree manifests without file contents
Remotefilelog support is integrated into both the wire protocol handler and EdenAPI. File data is served from the blobstore, with Mercurial file node IDs resolved via filenodes derived data.
Mercurial uses bundle formats to transfer data between client and server. Mononoke supports reading and writing these formats for protocol compatibility.
Bundle2 (mercurial/bundles/) is the primary wire protocol format. A bundle2 stream consists of:
Header - Protocol version and capabilities Parts - Typed chunks of data (changesets, manifests, files) Parameters - Metadata about each part
Common Parts:
Bundle2 parsing (mercurial/bundles/src/bundle2_encode.rs) handles:
Changegroups (mercurial/bundles/src/changegroup/) are sequences of deltas for changesets, manifests, and files. Each entry contains:
Changegroup unpacking (unpacker.rs) reconstructs full content from deltas, while packing (packer.rs) generates efficient delta sequences for transmission.
Wirepack (mercurial/bundles/src/wirepack/) is an alternative to changegroups used primarily for file data. Wirepack format:
Mononoke maintains compatibility with both legacy Mercurial clients and modern Sapling clients through careful protocol support and data format handling.
Mononoke servers negotiate capabilities with clients:
Capability negotiation allows servers to advertise supported features while clients can fall back to compatible operation modes.
The server identifies client type through:
This allows serving different clients from the same server infrastructure.
Mononoke ensures Mercurial data format compatibility by:
Preserving Hashes - Derived Mercurial changeset IDs match what a native Mercurial server would produce for the same commits. This ensures clients can verify data integrity.
Supporting Legacy Formats - Bundle2, changegroup, and wirepack formats are fully supported for clients that require them.
Maintaining Mapping Consistency - The BonsaiHgMapping provides stable Bonsai ↔ Mercurial ID mappings across server restarts and derivation operations.
The transition from Mercurial to Sapling occurred gradually, with Mononoke adapting to serve both client types:
Protocol Migration - The shift from SSH-based wire protocol to HTTP-based EdenAPI improved performance and simplified deployment. Mononoke added EdenAPI support while maintaining wire protocol compatibility.
Client Rebranding - As Mercurial clients were rebranded to Sapling, the server continued serving the same protocols with updated client-agent strings.
Feature Additions - New features like Commit Cloud and suffix query were added to EdenAPI without breaking compatibility with older clients.
Deprecation Path - Legacy wire protocol support remains for compatibility but is not actively developed. New features are added to SLAPI.
Mercurial and Sapling support is distributed across several directories:
Core Types and Formats:
mercurial/types/ - Mercurial type definitionsmercurial/bundles/ - Bundle2 and wire format handlingmercurial/revlog/ - Revlog format supportmercurial/mutation/ - Mutation (history editing) trackingMappings:
repo_attributes/bonsai_hg_mapping/ - Bonsai ↔ Mercurial mapping facetDerived Data:
derived_data/mercurial_derivation/ - Mercurial changeset and manifest derivationderived_data/filenodes_derivation/ - Filenode derivationrepo_attributes/filenodes/ - Legacy filenode storageProtocols:
servers/slapi/slapi_service/ - EdenAPI/SLAPI HTTP serverservers/slapi/wireproto_handler/ - Legacy wire protocol handlerServer:
servers/slapi/slapi_server/ - Main Mononoke server (serves SLAPI)Component-specific documentation for Mercurial types, protocols, and derived data lives in the respective directories.