Skip to content

Commit 907c99e

Browse files
committed
Add 'contrib/raftable/raft/' from commit '4f69a62fd88a05e7010b51f18ae0e715a8454743'
git-subtree-dir: contrib/raftable/raft git-subtree-mainline: 1642902 git-subtree-split: 4f69a62
2 parents 1642902 + 4f69a62 commit 907c99e

File tree

8 files changed

+1636
-0
lines changed

8 files changed

+1636
-0
lines changed

contrib/raftable/raft/LICENSE

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Copyright (c) 2015-2016, Constantin S. Pan
2+
All rights reserved.
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
1. Redistributions of source code must retain the above copyright notice, this
8+
list of conditions and the following disclaimer.
9+
10+
2. Redistributions in binary form must reproduce the above copyright notice,
11+
this list of conditions and the following disclaimer in the documentation
12+
and/or other materials provided with the distribution.
13+
14+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

contrib/raftable/raft/Makefile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#override CC := clang
2+
override CFLAGS += -Wfatal-errors -O0 -g
3+
override CPPFLAGS += -I. -Iinclude -DDEBUG
4+
override HEART_LDFLAGS += -Llib -lraft -ljansson
5+
6+
AR = ar
7+
ARFLAGS = -cru
8+
9+
.PHONY: all clean bindir objdir libdir
10+
11+
all: lib/libraft.a bin/heart
12+
@echo Done.
13+
14+
lib/libraft.a: obj/raft.o obj/util.o | libdir objdir
15+
$(AR) $(ARFLAGS) lib/libraft.a obj/raft.o obj/util.o
16+
17+
bin/heart: obj/heart.o lib/libraft.a | bindir objdir
18+
$(CC) -o bin/heart $(CFLAGS) $(CPPFLAGS) \
19+
obj/heart.o $(HEART_LDFLAGS)
20+
21+
obj/%.o: src/%.c | objdir
22+
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
23+
24+
obj/%.o: example/%.c | objdir
25+
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
26+
27+
bindir:
28+
mkdir -p bin
29+
30+
objdir:
31+
mkdir -p obj
32+
33+
libdir:
34+
mkdir -p lib
35+
36+
clean:
37+
rm -rfv bin obj lib

contrib/raftable/raft/README

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
libraft
2+
=======
3+
4+
Raft protocol implementation in C.
5+
6+
Features
7+
--------
8+
9+
+ Leader Election
10+
+ Log Replication
11+
+ Log Compaction
12+
13+
TODO
14+
----
15+
16+
+ Membership Changes

contrib/raftable/raft/example/heart.c

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <unistd.h>
5+
#include <assert.h>
6+
#include <time.h>
7+
#include <signal.h>
8+
#include <errno.h>
9+
#include <sys/wait.h>
10+
#include <sys/time.h>
11+
#include <stdbool.h>
12+
13+
#include <jansson.h>
14+
15+
#include "raft.h"
16+
#include "util.h"
17+
18+
static void applier(void *state, raft_update_t update, raft_bool_t snapshot) {
19+
json_error_t error;
20+
21+
json_t *patch = json_loadb(update.data, update.len, 0, &error);
22+
if (!patch) {
23+
shout(
24+
"error parsing json at position %d: %s\n",
25+
error.column,
26+
error.text
27+
);
28+
}
29+
30+
if (snapshot) {
31+
json_object_clear(state);
32+
}
33+
34+
if (json_object_update(state, patch)) {
35+
shout("error updating state\n");
36+
}
37+
38+
json_decref(patch);
39+
40+
char *encoded = json_dumps(state, JSON_INDENT(4) | JSON_SORT_KEYS);
41+
if (encoded) {
42+
debug(
43+
"applied %s: new state is %s\n",
44+
snapshot ? "a snapshot" : "an update",
45+
encoded
46+
);
47+
} else {
48+
shout(
49+
"applied %s, but new state could not be encoded\n",
50+
snapshot ? "a snapshot" : "an update"
51+
);
52+
}
53+
free(encoded);
54+
}
55+
56+
static raft_update_t snapshooter(void *state) {
57+
json_error_t error;
58+
59+
raft_update_t shot;
60+
shot.data = json_dumps(state, JSON_SORT_KEYS);
61+
shot.len = strlen(shot.data);
62+
if (shot.data) {
63+
debug("snapshot taken: %.*s\n", shot.len, shot.data);
64+
} else {
65+
shout("failed to take a snapshot\n");
66+
}
67+
68+
return shot;
69+
}
70+
71+
static void die(int signum) {
72+
debug("dying\n");
73+
exit(signum);
74+
}
75+
76+
static void usage(char *prog) {
77+
printf(
78+
"Usage: %s -i ID -r ID:HOST:PORT [-r ID:HOST:PORT ...] [-l LOGFILE]\n"
79+
" -l : Run as a daemon and write output to LOGFILE.\n",
80+
prog
81+
);
82+
}
83+
84+
raft_t raft;
85+
86+
static void main_loop(char *host, int port) {
87+
mstimer_t t;
88+
mstimer_reset(&t);
89+
90+
// create a UDP socket for raft
91+
int r = raft_create_udp_socket(raft);
92+
if (r == NOBODY) {
93+
die(EXIT_FAILURE);
94+
}
95+
96+
#define EMIT_EVERY_MS 1000
97+
int emit_ms = 0;
98+
while (true) {
99+
int ms;
100+
raft_msg_t m;
101+
int applied;
102+
103+
ms = mstimer_reset(&t);
104+
105+
raft_tick(raft, ms);
106+
m = raft_recv_message(raft);
107+
if (m) {
108+
raft_handle_message(raft, m);
109+
}
110+
111+
if (raft_is_leader(raft)) {
112+
emit_ms += ms;
113+
while (emit_ms > EMIT_EVERY_MS) {
114+
emit_ms -= EMIT_EVERY_MS;
115+
char buf[1000];
116+
char key = 'a' + rand() % 5;
117+
int value = rand() % 10000;
118+
sprintf(buf, "{\"key-%c\":%d}", key, value);
119+
shout("emit update: = %s\n", buf);
120+
raft_update_t update = {strlen(buf), buf, NULL};
121+
raft_emit(raft, update);
122+
}
123+
}
124+
}
125+
126+
close(r);
127+
}
128+
129+
int main(int argc, char **argv) {
130+
char *logfilename = NULL;
131+
bool daemonize = false;
132+
133+
int myid = NOBODY;
134+
int id;
135+
char *host;
136+
char *str;
137+
int port;
138+
int opt;
139+
140+
char *myhost = NULL;
141+
int myport;
142+
143+
json_t *state = json_object();
144+
145+
raft_config_t rc;
146+
rc.peernum_max = 64;
147+
rc.heartbeat_ms = 20;
148+
rc.election_ms_min = 150;
149+
rc.election_ms_max = 300;
150+
rc.log_len = 10;
151+
rc.chunk_len = 4;
152+
rc.msg_len_max = 500;
153+
rc.userdata = state;
154+
rc.applier = applier;
155+
rc.snapshooter = snapshooter;
156+
raft = raft_init(&rc);
157+
158+
int peernum = 0;
159+
while ((opt = getopt(argc, argv, "hi:r:l:")) != -1) {
160+
switch (opt) {
161+
case 'i':
162+
myid = atoi(optarg);
163+
break;
164+
case 'r':
165+
if (myid == NOBODY) {
166+
usage(argv[0]);
167+
return EXIT_FAILURE;
168+
}
169+
170+
str = strtok(optarg, ":");
171+
if (str) {
172+
id = atoi(str);
173+
} else {
174+
usage(argv[0]);
175+
return EXIT_FAILURE;
176+
}
177+
178+
host = strtok(NULL, ":");
179+
180+
str = strtok(NULL, ":");
181+
if (str) {
182+
port = atoi(str);
183+
} else {
184+
usage(argv[0]);
185+
return EXIT_FAILURE;
186+
}
187+
188+
if (!raft_peer_up(raft, id, host, port, id == myid)) {
189+
usage(argv[0]);
190+
return EXIT_FAILURE;
191+
}
192+
if (id == myid) {
193+
myhost = host;
194+
myport = port;
195+
}
196+
peernum++;
197+
break;
198+
case 'l':
199+
logfilename = optarg;
200+
daemonize = true;
201+
break;
202+
case 'h':
203+
usage(argv[0]);
204+
return EXIT_SUCCESS;
205+
default:
206+
usage(argv[0]);
207+
return EXIT_FAILURE;
208+
}
209+
}
210+
if (!myhost) {
211+
usage(argv[0]);
212+
return EXIT_FAILURE;
213+
}
214+
215+
if (logfilename) {
216+
if (!freopen(logfilename, "a", stdout)) {
217+
// nowhere to report this failure
218+
return EXIT_FAILURE;
219+
}
220+
if (!freopen(logfilename, "a", stderr)) {
221+
// nowhere to report this failure
222+
return EXIT_FAILURE;
223+
}
224+
}
225+
226+
if (daemonize) {
227+
if (daemon(true, true) == -1) {
228+
shout("could not daemonize: %s\n", strerror(errno));
229+
return EXIT_FAILURE;
230+
}
231+
}
232+
233+
signal(SIGTERM, die);
234+
signal(SIGINT, die);
235+
236+
main_loop(myhost, myport);
237+
238+
return EXIT_SUCCESS;
239+
}

0 commit comments

Comments
 (0)