Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Contributing to FoundationDB

“The best way to learn a database is to fix a bug in it.”

This chapter is the runway from “I read the book” to “I have a merged PR on apple/foundationdb.” It is opinionated and concrete. The official CONTRIBUTING.md is the canonical source; this chapter is the operational walkthrough.


10.1 Building FoundationDB from Source

The build is the gate that filters most would-be contributors. Block off an afternoon the first time. Once it works, it works forever.

Prerequisites

You need:

  • A Linux machine (or a Linux VM / container on macOS). The macOS build is partially supported but most maintainers test on Linux. Use Linux.
  • 16 GB RAM minimum, 32 GB recommended. The build is large.
  • 40 GB free disk space.
  • Docker (the official build uses a containerized toolchain).

The official path: build_run.sh

git clone https://github.com/apple/foundationdb.git
cd foundationdb

# Builds inside the official Docker toolchain image; output in build/
./contrib/Joshua/scripts/local_correctness.sh   # one-shot, prints a sim test result

For interactive development:

docker run -it --rm \
  -v $PWD:/foundationdb \
  -w /foundationdb \
  foundationdb/build:centos7-latest \
  bash

# Inside the container:
mkdir -p build && cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ..
ninja -j$(nproc)

First build takes ~20 min on a fast laptop; incremental builds are usually < 1 min.

What gets built

BinaryPurpose
bin/fdbserverThe server daemon — every cluster role runs this binary
bin/fdbcliInteractive cluster admin client
bin/fdbbackup, fdbrestoreBackup tooling
lib/libfdb_c.soThe client library — what Go/Java/Python bindings load
bin/joshua_agentDistributed simulation test runner
bin/makoLoad generator

Sanity check: run a simulation

./bin/fdbserver -r simulation -f ../tests/fast/CycleTest.toml

A successful run prints SimulatedFDBD: simulation finished successfully after 30 s to a few minutes. If you get an ASSERT failure, write down the seed — you may have already found a regression.


10.2 Finding a First Bug to Fix

Three reliable sources of approachable issues:

Source 1: The issue tracker, labeled appropriately

Documentation issues are the most under-served. The official docs at apple.github.io/foundationdb are maintained from documentation/sphinx/source/. A clear, well-tested documentation PR is almost always merged quickly and is excellent practice for the contribution workflow.

Source 2: Run the simulator until something breaks

The simulator is designed to find bugs that humans missed. Run it for hours:

for seed in $(seq 1 200); do
  ./bin/fdbserver -r simulation \
    -f tests/fast/RandomReadWriteTest.toml \
    --random-seed $seed \
    > /tmp/sim-$seed.log 2>&1 || echo "FAIL seed=$seed" 
done

If you find a reproducible failure on main that doesn’t appear on the most recent stable release, you’ve found a regression. File it with the seed; if you can also localize it via git bisect, you’re 80% to a merged PR.

Source 3: Performance investigation

The performance hotspots change with every release. Use perf against an fdbserver running a mako workload:

mako --mode build --rows 10000000 ...
perf record -g -p $(pgrep -f 'fdbserver.*storage') -- sleep 30
perf report --stdio | head -100

Anything taking > 5% of CPU in a place that doesn’t make architectural sense is a candidate for optimization. The storageserver.actor.cpp hot loop is a perennial source of incremental wins.


10.3 The Contribution Workflow

  1. Open an issue first for anything non-trivial. The maintainers will tell you if (a) someone is already on it, (b) the approach is wrong, or (c) they’d prefer a different scope. Saves rework.
  2. Sign the CLA. The bot will prompt on your first PR. Individual CLA is fine; corporate CLA needed if your employer holds your IP.
  3. Branch from main. Topic branches like fix-storage-leak-12345.
  4. One logical change per PR. Refactors stay separate from bug fixes. Maintainers reject mixed PRs quickly.
  5. Add a simulation test for behavior changes. This is non-negotiable. The reviewer will ask. If you can’t write one, ask for help in the issue or on the forum — but the test must land in the same PR.
  6. Run the relevant simulation tests locally before pushing:
    ctest -L fast -j$(nproc)         # ~15 min, runs the "fast" test suite
    
  7. CI will run Joshua (the distributed sim runner) against your PR. Failures with seeds are surfaced in the PR comment. Reproduce locally with the printed seed.

Style and conventions

  • C++17, formatted by clang-format using the repo’s .clang-format. Run ./contrib/clang-format-hook.sh or set up the pre-commit hook.
  • No std::unordered_map, no raw gettimeofday, no std::thread. The determinism rules from Chapter 4 are enforced in review.
  • Knobs go in Knobs.h with a sensible default; don’t add config flags unless absolutely necessary.
  • Public Flow APIs (touched by the client library) need binding tests in bindings/c/test/ and equivalents for at least Python and Java.

10.4 Where to Hang Out

The FDB community is small but active.

VenueUse for
forums.foundationdb.orgDesign discussion, “how does X work” questions
#foundationdb on Apache SlackQuick chat (request invite via forum)
GitHub DiscussionsFeature proposals
FoundationDB Summit (annual)Talks from Apple, Snowflake, Tigris, Stark+Wayne

Read at least one forum thread per week for a month before posting; you’ll absorb the team’s writing style and avoid asking already-answered questions.


10.5 First-PR Idea Catalog

If you want a concrete starting point, here are the kinds of contributions that historically have been merged from new contributors:

  1. Documentation: clarify a confusing section. Pick a doc page that confused you while reading this book. Improve it. Submit it.
  2. Add an example to the binding tests. Each language binding has a test/ subdirectory; many corner cases are under-tested. Add a test for tr.GetEstimatedRangeSize from your favorite binding.
  3. Improve an error message. Run a test that hits an FDB error code, read what FDB tells you, and rewrite a confusing message in fdbclient/FDBTypes.h to be actionable.
  4. Add a knob. Find a hardcoded constant in fdbserver/ that looks like it should be tunable (search for magic numbers in .actor.cpp files). Move it to Knobs.h, give it a default, and add a release note.
  5. Write a workload. New simulation workloads live in fdbserver/workloads/. Pick a real-world pattern your job uses (e.g., a producer-consumer queue) and write a workload that exercises it under chaos. The simulator will probably find a bug for you.
  6. Port a binding. There are unofficial bindings for Rust, Zig, Elixir. If your favorite language is missing, the C client API is small (~50 functions); a from-scratch binding is a great multi-month project.
  7. Improve Redwood’s cold-start time. A known issue: opening a large Redwood store on cold startup can take minutes because the page metadata index is walked sequentially. Various heuristics (parallel walk, mmap, prefetch) have been proposed. Pick one, prototype it, benchmark it.

Even before contributing, reading the source is the best self-education in distributed systems available outside graduate school. A recommended sequence:

  1. flow/ — internalize the actor model.
    • flow.h, flow.cpp — Future, Promise, SAV.
    • Net2.actor.cpp — the event loop.
    • genericactors.actor.h — Flow’s “standard library.”
  2. fdbrpc/ — RPC framework on top of Flow.
    • FlowTransport.actor.cpp — sending/receiving requests.
    • sim2.actor.cpp — the simulation backend.
  3. fdbserver/ — read in this order:
    • MasterServer.actor.cpp (or SequencerServer.actor.cpp in newer versions) — version assignment, the heart of MVCC.
    • CommitProxyServer.actor.cpp — the commit pipeline.
    • Resolver.actor.cpp — conflict resolution.
    • TLogServer.actor.cpp — the distributed WAL.
    • storageserver.actor.cpp — the read/apply loop.
    • DataDistribution.actor.cpp — shard movement.
    • VersionedBTree.actor.cpp — Redwood, then DeltaTree.h.
    • ClusterController.actor.cpp — the role manager (last; it’s complex).
  4. fdbclient/ — how clients see the cluster.
    • NativeAPI.actor.cpp — transaction lifecycle.
    • MultiVersionTransaction.actor.cpp — the client-version compatibility dance.
  5. bindings/c/ — the C API your CGO Go binding actually calls.

If you give yourself one file per evening, you’ll read the whole essential codebase in a month — and you will be one of perhaps a few hundred people in the world who have.


10.7 Beyond the Core: Layers and Tooling

Contributing to the core engine is one path. Equally valuable:

These projects are smaller, faster-moving, and often very grateful for help. The patterns they use are the exact patterns this book covers.


10.8 The Long Game

The FoundationDB team is small. The maintainers know everyone who has landed more than a few patches. After 5–10 merged PRs you will be on a first-name basis with people whose names you originally saw in citations. After 50, you’ll be invited to design discussions and given commit privileges.

The path is real. The bar is high but not arcane: write correct C++, write deterministic Flow, run the simulator, follow the conventions, be patient in review. Every senior contributor started exactly where you are now.

“So long, and thanks for all the fish.”

Now go build something on FoundationDB — and then go fix something in it.