Skip to content

Commit 53e000c

Browse files
committed
2 parents bb988b1 + 5c6c0eb commit 53e000c

File tree

9 files changed

+1676
-1
lines changed

9 files changed

+1676
-1
lines changed

contrib/raftable/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ OBJS = raftable.o worker.o state.o blockmem.o
33
EXTENSION = raftable
44
DATA = raftable--1.0.sql
55

6+
raftable.so: raft/lib/libraft.a
7+
8+
raft/lib/libraft.a:
9+
make -C raft
10+
611
EXTRA_INSTALL = contrib/raftable
712

8-
RAFT_PREFIX = $(HOME)/raft
13+
RAFT_PREFIX = raft
914
override LDFLAGS += -L$(RAFT_PREFIX)/lib -Wl,-whole-archive -lraft -Wl,-no-whole-archive
1015
override CFLAGS += -Wfatal-errors
1116
override CPPFLAGS += -I$(RAFT_PREFIX)/include

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 += -fpic -Wall -Wfatal-errors -O0 -g -pedantic -std=c99
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+
lib/libraft.a: obj/raft.o obj/util.o | libdir objdir
12+
$(AR) $(ARFLAGS) lib/libraft.a obj/raft.o obj/util.o
13+
14+
all: lib/libraft.a bin/heart
15+
@echo Done.
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: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
#define _POSIX_C_SOURCE 2
2+
#define _BSD_SOURCE
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
#include <unistd.h>
7+
#include <assert.h>
8+
#include <time.h>
9+
#include <signal.h>
10+
#include <errno.h>
11+
#include <sys/wait.h>
12+
#include <sys/time.h>
13+
#include <stdbool.h>
14+
15+
#include <jansson.h>
16+
17+
#include "raft.h"
18+
#include "util.h"
19+
20+
static void applier(void *state, raft_update_t update, raft_bool_t snapshot) {
21+
json_error_t error;
22+
23+
json_t *patch = json_loadb(update.data, update.len, 0, &error);
24+
if (!patch) {
25+
shout(
26+
"error parsing json at position %d: %s\n",
27+
error.column,
28+
error.text
29+
);
30+
}
31+
32+
if (snapshot) {
33+
json_object_clear(state);
34+
}
35+
36+
if (json_object_update(state, patch)) {
37+
shout("error updating state\n");
38+
}
39+
40+
json_decref(patch);
41+
42+
char *encoded = json_dumps(state, JSON_INDENT(4) | JSON_SORT_KEYS);
43+
if (encoded) {
44+
debug(
45+
"applied %s: new state is %s\n",
46+
snapshot ? "a snapshot" : "an update",
47+
encoded
48+
);
49+
} else {
50+
shout(
51+
"applied %s, but new state could not be encoded\n",
52+
snapshot ? "a snapshot" : "an update"
53+
);
54+
}
55+
free(encoded);
56+
}
57+
58+
static raft_update_t snapshooter(void *state) {
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+
102+
ms = mstimer_reset(&t);
103+
104+
raft_tick(raft, ms);
105+
m = raft_recv_message(raft);
106+
if (m) {
107+
raft_handle_message(raft, m);
108+
}
109+
110+
if (raft_is_leader(raft)) {
111+
emit_ms += ms;
112+
while (emit_ms > EMIT_EVERY_MS) {
113+
emit_ms -= EMIT_EVERY_MS;
114+
char buf[1000];
115+
char key = 'a' + rand() % 5;
116+
int value = rand() % 10000;
117+
sprintf(buf, "{\"key-%c\":%d}", key, value);
118+
shout("emit update: = %s\n", buf);
119+
raft_update_t update = {strlen(buf), buf, NULL};
120+
raft_emit(raft, update);
121+
}
122+
}
123+
}
124+
125+
close(r);
126+
}
127+
128+
int main(int argc, char **argv) {
129+
char *logfilename = NULL;
130+
bool daemonize = false;
131+
132+
int myid = NOBODY;
133+
int id;
134+
char *host;
135+
char *str;
136+
int port;
137+
int opt;
138+
139+
char *myhost = NULL;
140+
int myport;
141+
142+
json_t *state = json_object();
143+
144+
raft_config_t rc;
145+
rc.peernum_max = 64;
146+
rc.heartbeat_ms = 20;
147+
rc.election_ms_min = 150;
148+
rc.election_ms_max = 300;
149+
rc.log_len = 10;
150+
rc.chunk_len = 4;
151+
rc.msg_len_max = 500;
152+
rc.userdata = state;
153+
rc.applier = applier;
154+
rc.snapshooter = snapshooter;
155+
raft = raft_init(&rc);
156+
157+
int peernum = 0;
158+
while ((opt = getopt(argc, argv, "hi:r:l:")) != -1) {
159+
switch (opt) {
160+
case 'i':
161+
myid = atoi(optarg);
162+
break;
163+
case 'r':
164+
if (myid == NOBODY) {
165+
usage(argv[0]);
166+
return EXIT_FAILURE;
167+
}
168+
169+
str = strtok(optarg, ":");
170+
if (str) {
171+
id = atoi(str);
172+
} else {
173+
usage(argv[0]);
174+
return EXIT_FAILURE;
175+
}
176+
177+
host = strtok(NULL, ":");
178+
179+
str = strtok(NULL, ":");
180+
if (str) {
181+
port = atoi(str);
182+
} else {
183+
usage(argv[0]);
184+
return EXIT_FAILURE;
185+
}
186+
187+
if (!raft_peer_up(raft, id, host, port, id == myid)) {
188+
usage(argv[0]);
189+
return EXIT_FAILURE;
190+
}
191+
if (id == myid) {
192+
myhost = host;
193+
myport = port;
194+
}
195+
peernum++;
196+
break;
197+
case 'l':
198+
logfilename = optarg;
199+
daemonize = true;
200+
break;
201+
case 'h':
202+
usage(argv[0]);
203+
return EXIT_SUCCESS;
204+
default:
205+
usage(argv[0]);
206+
return EXIT_FAILURE;
207+
}
208+
}
209+
if (!myhost) {
210+
usage(argv[0]);
211+
return EXIT_FAILURE;
212+
}
213+
214+
if (logfilename) {
215+
if (!freopen(logfilename, "a", stdout)) {
216+
// nowhere to report this failure
217+
return EXIT_FAILURE;
218+
}
219+
if (!freopen(logfilename, "a", stderr)) {
220+
// nowhere to report this failure
221+
return EXIT_FAILURE;
222+
}
223+
}
224+
225+
if (daemonize) {
226+
if (daemon(true, true) == -1) {
227+
shout("could not daemonize: %s\n", strerror(errno));
228+
return EXIT_FAILURE;
229+
}
230+
}
231+
232+
signal(SIGTERM, die);
233+
signal(SIGINT, die);
234+
235+
main_loop(myhost, myport);
236+
237+
return EXIT_SUCCESS;
238+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy