Browse by type
A distributed file system. For a high-level description of TernFS, see the TernFS blog post on the XTX Markets Tech Blog. This document provides a more bare-bones overview and an introduction to the codebase.
The target use case for TernFS is the kind of machine learning we do at XTX: reading and writing large immutable files. By "immutable" we mean files that do not need modifying after they are first created. By "large" we mean that most of the storage space will be taken up by files bigger than a few MBs.
We don't expect new directories to be created often, and files (or directories) to be moved between directories often. In terms of numbers, we expect the upper bound for TernFS to roughly be the upper bound for the data we're planning for a single data center:
We want to drive the filesystem with commodity hardware and Ethernet networking.
We want the system to be robust in various ways:
We also want to be able to restore deleted files or directories, using a configurable "permanent deletion" policy.
Finally, we want to have the option to replicate TernFS to multiple regions, to be able to scale up compute across multiple data centres, and to remove any single data centre as a point of failure.
TernFS is actively used in production, but the project is still evolving quickly. All releases are currently in the 0.X.Y range and should be considered pre-1.0, with the following meaning:
0.4.5 → 0.5.0) may remove or change internal APIs. Upgrading across minor versions should not be skipped; read the changelog.0.5.3 → 0.5.4) adds new functionality or small configuration changes, and may contain bug fixes. A ──► B means "A sends requests to B"
┌────────────────┐
│ Metadata Shard ◄─────────┐
└─┬────▲─────────┘ │
│ │ │
│ │ │
│ ┌──┴──┐ │
│ │ CDC ◄──────────┐ │
│ └──┬──┘ │ │
│ │ │ ┌───┴────┐
│ │ └─┤ │
┌─▼────▼────┐ │ Client │
│ Registry ◄──────────┤ │
└──────▲────┘ └─┬──────┘
│ │
│ │
┌──────┴────────┐ │
│ Block Service ◄────────┘
└───────────────┘
ternregistry, C++ binaryternshard, C++ binaryterncdc, C++ binaryternblocks, Go binary (for now, might become C++ in the future if performance requires it)ternweb, go binaryterncli, Go binaryterncli migrate)terncli defrag, currently WIP, see #50)ternfs.ko, C Linux kernel modulemount -t eggsfs ...ternfuse, Go FUSE implementation of a TernFS client-close-tracker-object flag)terns3, Go implementation of the S3 APIxtx/ternfs/clientterngcternrun, a tool to quickly spin up a TernFS instanceterntests, runs some integration tests% ./build.sh alpine
Will build all the artifacts apart from the Kernel module. The output binaries will be in build/alpine. Things will be built in an Alpine Linux container, so that everything will be fully statically linked.
There's also ./build.sh ubuntu which will do the same but in a Ubuntu container, and ./build.sh release which will build outside docker, which means that you'll have to install some dependencies in the host machine. Both of these build options will have glibc as the only dynamically linked dependency.
./ci.py --build --functional --integration --short --docker
Will run the integration tests as CI would (inside the Ubuntu docker image). You can also run the tests outside docker by removing the --docker flag, but you might have to install some dependencies of the build process. These tests take roughly 30 minutes on our build server.
To work with the qemu kmod tests you'll first need to download the base Ubuntu image we use for testing:
% wget -P kmod 'https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img'
Then you can run the CI tests in kmod like so:
% ./ci.py --kmod --short --prepare-image=kmod/focal-server-cloudimg-amd64.img --leader-only
The tests redirect dmesg output to kmod/dmesg, event tracing output to kmod/trace, and the full test log to kmod/test-out.
You can also ssh into the qemu which is running the tests with
% ssh -p 2223 -i kmod/image-key fmazzol@localhost
Note that the kmod tests are very long (~1hr). Usually when developing the kernel module it's best to use ./kmod/restartsession.sh to be dropped into qemu, and then run specific tests using terntests.
However when merging code modifying TernFS internals it's very important for the kmod tests to pass as well as the normal integration tests. This is due to the fact that the qemu environment is generally very different from the non-qemu env, which means that sometimes it'll surface issues that the non-qemu environment won't.
% ./build.sh alpine
% ./build/alpine/ternrun -binaries-dir build/alpine -data-dir <data-dir>
For less resource intensive local instance consider running with -leader-only. This will start only leader replica without replication for registry, cdc and shards.
The above will run all the processes needed to run TernFS. This includes:
-flash-block-services, -hdd-block-services, and -failure-domains flags)A multitude of directories to persist the whole thing will appear in <data-dir>. The filesystem will also be mounted using FUSE under <data-dir>/fuse/mnt.
Inspecting ternrun.go is a decent way to get familiar with the services required to run a TernFS cluster.
% cd kmod
% ./fetchlinux.sh # fetch linux sources
% (cd linux && make oldconfig && make prepare && make -j) # build Linux
% make KDIR=linux -j ternfs-client-local
% cd kmod
% make deb-package
Most of the codebase is understandable by VS Code/LSP:
go/ just works out of the box with the Go extension. I (@bitonic) open a separate VS Code window which specifically has the ternfs/go directory open, since the Go extension doesn't seem to like working from a subdirectory.cpp/:Generate compile_commands.json with
% cd cpp
% ./build.py debug
% cp ./build/debug/compile_commands.json .
If you change the build process (i.e. if you change CMake files) you'll need to generate and copy compile_commands.json again.
* Code in kmod/:
- Build the module.
- Generate compile_commands.json with ./kmod/gen_compile_commands.sh.
- New files should work automatically, but if things stop working, just re-bulid and re-generate compile_commands.json.
TernFS was originally called EggsFS internally. This name quickly proved to be very poor due to the phonetic similarity to XFS, another notable filesystem. Therefore the filesystem was renamed to TernFS before open sourcing. However the old name lingers on in certain areas of the system that would have been hard to change, such as metric names.
TernFS is Free Software. The default license for TernFS is GPL-2.0-or-later.
The protocol definitions (go/msgs/), protocol generator (go/bincodegen/) and client library (go/client/, go/core/) are licensed under Apache-2.0 with the LLVM-exception. This license combination is both permissive (similar to MIT or BSD licenses) as well as compatible with all GPL licenses. We have done this to allow people to build their own proprietary client libraries while ensuring we can also freely incorporate them into the GPL v2 licensed Linux kernel.
$ claude mcp add ternfs \
-- python -m otcore.mcp_server <graph>