C-Raft

C-Raft is a fully asynchronous C implementation of the Raft consensus protocol.

Design

The library has modular design: its core part implements only the core Raft algorithm logic, in a fully platform independent way. On top of that, a pluggable interface defines the I/O implementation for networking and disk persistence.

A stock implementation of the I/O interface is provided when building the library with default options. It is based on libuv and should fit the vast majority of use cases.

Features

C-Raft implements all the basic features described in the Raft dissertation:

  • Leader election

  • Log replication

  • Log compaction

  • Membership changes

It also includes a few optional enhancements:

  • Optimistic pipelining to reduce log replication latency

  • Writing to leader’s disk in parallel

  • Automatic stepping down when the leader loses quorum

  • Leadership transfer extension

  • Non-voting servers

Quick start

Make sure that libuv is installed on your system, then run:

1 autoreconf -i
2 ./configure --enable-example
3 make

Then create a main.c file with this simple test program that just runs a single raft server and implements a basic state machine for incrementing a counter:

 1 #include <raft.h>
 2 #include <raft/uv.h>
 3 
 4 static raft_id id = 12345;
 5 static const char *address = "127.0.0.1:8080";
 6 static const char *dir = "/tmp/raft-quick-start";
 7 static struct uv_loop_s loop;
 8 static struct raft_uv_transport transport;
 9 static struct raft_io io;
10 static struct raft_fsm fsm;
11 static struct raft raft;
12 static struct raft_configuration conf;
13 static struct uv_timer_s timer;
14 static struct raft_apply apply;
15 static unsigned counter = 0;
16 static uint64_t command;
17 
18 static int applyCommand(struct raft_fsm *fsm,
19                         const struct raft_buffer *buf,
20                         void **result) {
21     counter += *(uint64_t *)buf->base;
22     printf("counter: %u\n", counter);
23     return 0;
24 }
25 
26 static void submitCommand(uv_timer_t *timer) {
27     struct raft_buffer buf;
28     command = uv_now(timer->loop) % 10;
29     buf.len = sizeof command;
30     buf.base = &command;
31     raft_apply(&raft, &apply, &buf, 1, NULL);
32 }
33 
34 int main() {
35     mkdir(dir, 0755);
36     uv_loop_init(&loop);
37     raft_uv_tcp_init(&transport, &loop);
38     raft_uv_init(&io, &loop, dir, &transport);
39     fsm.apply = applyCommand;
40     raft_init(&raft, &io, &fsm, id, address);
41     raft_configuration_init(&conf);
42     raft_configuration_add(&conf, id, address, RAFT_VOTER);
43     raft_bootstrap(&raft, &conf);
44     raft_start(&raft);
45     uv_timer_init(&loop, &timer);
46     uv_timer_start(&timer, submitCommand, 0, 1000);
47     uv_run(&loop, UV_RUN_DEFAULT);
48 }

You can compile and run it with:

1 cc main.c -o main -lraft -luv && ./main

Licence

This raft C library is released under a slightly modified version of LGPLv3, that includes a copyright exception letting users to statically link the library code in their project and release the final work under their own terms. See the full license text.