A replicated filesystem library built on Raft consensus using braft. This library provides strong consistency guarantees for file operations across a distributed cluster.
- Leader-based writes: All write operations (create, write, append, delete) go through the elected leader and are replicated via Raft consensus
- Local reads: Read operations can be performed on any node using local replicas
- Strong consistency: Reads see all writes committed before them (linearizable reads)
- Automatic failover: If the leader fails, a new leader is automatically elected
- Path-based API: Simple, intuitive API similar to POSIX filesystem operations
-
Write operations (create, write, delete, etc.):
- Must be submitted to the leader node
- Leader proposes the operation through Raft
- Once a majority commits, the operation is applied
- Operation is then replicated to all followers
-
Read operations (read, list, stat):
- Can be performed on any node
- Served from local storage (no network overhead)
- C++17 compiler
- CMake 3.15+
- bRaft
- Apache brpc
- spdlog
- gflags
- protobuf
- leveldb
mkdir build && cd build
cmake ..
cmake --build .To run a 3-node cluster on localhost:
Terminal 1 (Node 1):
./fs_example \
--peer_id=127.0.0.1:8100:0 \
--conf=127.0.0.1:8100:0,127.0.0.1:8101:0,127.0.0.1:8102:0 \
--data_path=./data1 \
--raft_path=./raft1Terminal 2 (Node 2):
./fs_example \
--peer_id=127.0.0.1:8101:0 \
--conf=127.0.0.1:8100:0,127.0.0.1:8101:0,127.0.0.1:8102:0 \
--data_path=./data2 \
--raft_path=./raft2Terminal 3 (Node 3):
./fs_example \
--peer_id=127.0.0.1:8102:0 \
--conf=127.0.0.1:8100:0,127.0.0.1:8101:0,127.0.0.1:8102:0 \
--data_path=./data3 \
--raft_path=./raft3#include "diarkis/fs_client.h"
using namespace diarkis;
int main() {
Client::Config config;
config.data_path = "./data";
config.raft_path = "./raft";
config.group_id = "my_fs";
config.peer_id = "127.0.0.1:8100:0";
config.initial_conf = "127.0.0.1:8100:0,127.0.0.1:8101:0,127.0.0.1:8102:0";
Client client(config);
auto result = client.init();
if (!result.ok()) {
return 1;
}
// Write operations (must be leader)
if (client.is_leader()) {
client.create_directory("docs");
client.write_file("docs/hello.txt", "Hello, World!");
client.append_file("docs/hello.txt", "\nGoodbye!");
}
// Read operations (any node)
auto content = client.read_file_string("docs/hello.txt");
if (content.ok()) {
std::cout << content.value << std::endl;
}
auto entries = client.list_directory("docs");
if (entries.ok()) {
for (const auto& entry : entries.value) {
std::cout << entry << std::endl;
}
}
client.shutdown();
return 0;
}These operations require the node to be the leader. They return Result<void> with status:
create_file(path)- Create a new file (idempotent)write_file(path, data)- Write data to file, overwriting existing contentappend_file(path, data)- Append data to filedelete_file(path)- Delete a file (idempotent)create_directory(path)- Create a directory (idempotent)delete_directory(path)- Delete an empty directoryrename(old_path, new_path)- Rename/move a file or directory
These operations can be performed on any node:
read_file(path)→Result<vector<uint8_t>>- Read file contents as bytesread_file_string(path)→Result<string>- Read file contents as stringlist_directory(path)→Result<vector<string>>- List directory entriesstat(path)→Result<FileInfo>- Get file/directory metadataexists(path)→Result<bool>- Check if path exists
is_leader()→bool- Check if this node is the leaderget_leader()→string- Get the current leader's peer IDget_commit_index()→int64_t- Get current commit index
All operations return a Result<T> type:
Result<T> result = client.some_operation();
if (result.ok()) {
// Success - use result.value
auto value = result.value;
} else {
// Error - check result.status and result.error_message
std::cerr << "Error: " << result.error_message << std::endl;
}Status codes: OK, NOT_FOUND, ALREADY_EXISTS, NOT_LEADER, NO_LEADER, IO_ERROR, INVALID_PATH, NOT_DIRECTORY, DIRECTORY_NOT_EMPTY, RAFT_ERROR
Followers serve reads from local storage but check their commit index. This provides:
- Low latency: No network round-trip for reads
- Strong consistency: Reads see committed writes
- High availability: Reads work even if leader is unavailable
This project is licensed under the MIT License.