Skip to content

Internals

Edit page

This page is for contributors: how the source tree is organized, the conventions you’ll see everywhere, and the invariants that look like implementation details but are actually structural. For the layered picture, start with the Architecture Overview; for the libraries, see Dependencies.

The authoritative, always-current version of this lives in the repository’s AGENTS.md and ARCHITECTURE.md.

src/ mixes Xapiand’s own code with a few bundled third-party libraries. The first rule of the tree: don’t refactor vendored code. The search core, src/xapian/, is special. It’s a fork (a pristine upstream snapshot plus a small stack of patches), not a plain bundle. Before touching anything under it, read XAPIAN_FORK.md.

Most of the small utilities that used to live in src/ have been extracted into standalone repositories and are pulled back in via FetchContent (see Dependencies). The entry point is src/main.cc, and the process is orchestrated by XapiandManager (src/manager.*).

You’re touching…Start in
On-disk format, durability, volumessrc/storage.h, src/database/{wal,data,shard}.{cc,h}
Schema handling, field typessrc/database/schema*.{cc,h}, src/reserved/
HTTP API / request handlingsrc/server/http*.{cc,h}, src/url_parser.*
Event loop / client lifecyclesrc/worker.{cc,h}, src/server/base_{client,server}.*
Clustering, discovery, replicationsrc/server/discovery.*, src/server/replication_protocol*, src/manager.*, src/node.*
Query languagessrc/query_dsl.* (JSON/MsgPack), src/booleanParser/ (string)
Aggregationssrc/aggregations/
Geospatialsrc/geospatial/, src/multivalue/geospatialrange.*
Value encodingsrc/sortable_serialise.*, src/serialise*.{cc,h}, src/length.*
Loggingsrc/logger.*, src/log.h (category switches)

Logging macros L_*. Logging is pervasive (~2,790 call sites). Most category macros (L_CALL, L_DATABASE, L_EV, …) compile to nothing by default and are switched on by editing the #defines near the top of src/log.h. To trace a subsystem, flip its category there and rebuild. Log arguments are evaluated lazily, so passing expensive expressions is fine.

The Worker tree. Anything that owns a socket or a timer is a Worker (src/worker.h), living in a shared-pointer parent/children tree. Never call another worker’s methods across threads directly. Use the async control watchers (shutdown, stop, destroy, detach), which run on the owning loop. Lifetime is by shared_ptr; clients keep themselves alive across the loop→pool hand-off with share_this().

MsgPack as the universal value. JSON, MessagePack, and internal objects are all MsgPack (src/msgpack.h), a copy-on-write wrapper over a shared, reference-counted buffer. This keeps copies cheap through the pipeline. Reserved keys are $/_-prefixed (src/reserved/).

Perfect-hash dispatch. Reserved-word handling (query DSL, aggregations) uses compile-time perfect-hash tables (phf::make_phf), not if-ladders. Adding a keyword means extending both the hash table and its switch.

Serialization is order-sensitive. Values stored for range/sort use sortable_serialise, where memcmp order equals numeric order. Change how a value is encoded and you change its sort/range semantics, so keep the encoding monotonic.

Copy-on-write values. MsgPack shares one reference-counted buffer and only copies on mutation, which minimizes copies through the request pipeline and makes serialization cheap.

Async-first replication. Replication is pull-based and asynchronous. A write commits locally first; replicas discover and pull when ready. This decouples commit latency from replica sync. A write is not on any replica when it commits.

Shared-nothing reactor pool. The network transport runs on N independent Asio reactors, each owning its own io_context and thread. No shared state and no locks between them.

These are not safe to “clean up”. Each one is load-bearing:

  • Trixel ids encode the quadtree path, 2 bits per level, big-endian. That’s why a geographic region maps to a contiguous integer range. Any change to id construction or endianness breaks geo indexing silently (src/geospatial/htm.cc, src/serialise.cc).
  • One primary shard per logical shard, elected via Raft (discovery.cc). Replication is asynchronous and pull-based. If you touch the commit path, preserve the DB_UPDATED multicast that triggers it.
  • The storage write cursor lives in the volume header. Bins are 8-byte aligned and a volume is capped near 34 GB. Don’t write a bin outside Storage::write / write_buffer (the double-buffer alignment dance).
  • WAL replay must be idempotent w.r.t. revisions (wal.cc checks revision == db_revision). Don’t add WAL ops that can’t be safely re-applied.
  • AGENTS.md — the full working guide, including known traps and gotchas.
  • ARCHITECTURE.md — the C++ codebase deep-dive.
  • XAPIAN_FORK.md — the fork model, why each patch exists, and the upgrade procedure.