├── vr ├── .gitignore ├── tests │ └── Rules.mk ├── Rules.mk ├── vr-proto.proto ├── client.h ├── replica.h └── client.cc ├── spec ├── .gitignore ├── tests │ ├── merge-tests │ │ ├── EmptyLogs │ │ ├── OneEmpty │ │ ├── SpeculativeNoQuorum │ │ ├── AllCommitted │ │ ├── SpeculativeQuorum │ │ ├── Conflict │ │ └── Divergence │ ├── Rules.mk │ └── merge-test-case.proto ├── Rules.mk ├── spec-proto.proto ├── client.h └── replica.h ├── sequencer ├── .gitignore ├── Rules.mk └── sequencer.h ├── .gitignore ├── bench ├── .gitignore ├── Rules.mk ├── benchmark.h └── benchmark.cc ├── fastpaxos ├── .gitignore ├── tests │ └── Rules.mk ├── Rules.mk ├── fastpaxos-proto.proto ├── client.h ├── replica.h └── client.cc ├── nopaxos ├── tests │ ├── .gitignore │ └── Rules.mk ├── Rules.mk ├── nopaxos-proto.proto └── client.h ├── unreplicated ├── .gitignore ├── tests │ ├── Rules.mk │ └── unreplicated-test.cc ├── unreplicated-proto.proto ├── Rules.mk ├── replica.h ├── client.h ├── replica.cc └── client.cc ├── common ├── tests │ └── Rules.mk ├── Lib.mk ├── Rules.mk ├── request.proto ├── replica-inl.h ├── client.cc ├── replica.cc ├── log-impl.h ├── client.h ├── quorumset.h ├── replica.h ├── messageset.h ├── log.h └── log.cc ├── lib ├── .gitignore ├── tests │ ├── simtransport-testmessage.proto │ ├── configuration-test-1.conf │ ├── Rules.mk │ └── workertasks-test.cc ├── latency-format.proto ├── Rules.mk ├── workertasks.cc ├── workertasks.h ├── memory.h ├── assert.h ├── transport.cc ├── hash.h ├── memory.cc ├── timeval.h ├── viewstamp.h ├── configuration.h ├── latency.h ├── message.h ├── simtransport.h ├── transport.h └── udptransport.h ├── COPYING ├── ctpl ├── README.md └── example.cpp └── README.md /vr/.gitignore: -------------------------------------------------------------------------------- 1 | vr-test 2 | -------------------------------------------------------------------------------- /spec/.gitignore: -------------------------------------------------------------------------------- 1 | merge-test 2 | -------------------------------------------------------------------------------- /sequencer/.gitignore: -------------------------------------------------------------------------------- 1 | sequencer 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .obj/ 2 | TAGS 3 | *.swp 4 | -------------------------------------------------------------------------------- /bench/.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | replica 3 | -------------------------------------------------------------------------------- /fastpaxos/.gitignore: -------------------------------------------------------------------------------- 1 | fastpaxos-test 2 | -------------------------------------------------------------------------------- /nopaxos/tests/.gitignore: -------------------------------------------------------------------------------- 1 | nopaxos-test 2 | -------------------------------------------------------------------------------- /unreplicated/.gitignore: -------------------------------------------------------------------------------- 1 | unreplicated-test 2 | -------------------------------------------------------------------------------- /common/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | -------------------------------------------------------------------------------- /lib/.gitignore: -------------------------------------------------------------------------------- 1 | configuration-test 2 | simtransport-test 3 | workertasks-test 4 | -------------------------------------------------------------------------------- /lib/tests/simtransport-testmessage.proto: -------------------------------------------------------------------------------- 1 | package specpaxos.test; 2 | 3 | message TestMessage { 4 | required string test = 1; 5 | } 6 | -------------------------------------------------------------------------------- /common/Lib.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | PROTOS += $(addprefix $(d), \ 4 | request.proto) 5 | 6 | LIB-request := $(o)request.o 7 | -------------------------------------------------------------------------------- /lib/tests/configuration-test-1.conf: -------------------------------------------------------------------------------- 1 | # This is a test configuration file 2 | f 1 3 | group 4 | replica localhost:12345 5 | replica localhost:12346 6 | replica localhost:12347 7 | multicast localhost:12348 8 | -------------------------------------------------------------------------------- /sequencer/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | sequencer.cc) 5 | 6 | $(d)sequencer: $(o)sequencer.o $(LIB-message) 7 | 8 | BINS += $(d)sequencer 9 | -------------------------------------------------------------------------------- /spec/tests/merge-tests/EmptyLogs: -------------------------------------------------------------------------------- 1 | newview: 1 2 | log: { 3 | replicaidx: 0 4 | view: 0 5 | lastNormalView: 0 6 | } 7 | 8 | log: { 9 | replicaidx: 1 10 | view: 0 11 | lastNormalView: 0 12 | } 13 | -------------------------------------------------------------------------------- /vr/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | GTEST_SRCS += $(d)vr-test.cc 4 | 5 | $(d)vr-test: $(o)vr-test.o \ 6 | $(OBJS-vr-replica) $(OBJS-vr-client) \ 7 | $(LIB-simtransport) \ 8 | $(GTEST_MAIN) 9 | 10 | TEST_BINS += $(d)vr-test 11 | -------------------------------------------------------------------------------- /fastpaxos/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | GTEST_SRCS += $(d)fastpaxos-test.cc 4 | 5 | $(d)fastpaxos-test: $(o)fastpaxos-test.o \ 6 | $(OBJS-fastpaxos-replica) $(OBJS-fastpaxos-client) \ 7 | $(LIB-simtransport) \ 8 | $(GTEST_MAIN) 9 | 10 | TEST_BINS += $(d)fastpaxos-test 11 | -------------------------------------------------------------------------------- /unreplicated/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | GTEST_SRCS += $(d)unreplicated-test.cc 4 | 5 | $(d)unreplicated-test: $(o)unreplicated-test.o \ 6 | $(OBJS-unreplicated-replica) $(OBJS-unreplicated-client) \ 7 | $(LIB-simtransport) \ 8 | $(GTEST_MAIN) 9 | 10 | TEST_BINS += $(d)unreplicated-test 11 | -------------------------------------------------------------------------------- /nopaxos/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | GTEST_SRCS += $(d)nopaxos-test.cc 4 | 5 | $(d)nopaxos-test: $(o)nopaxos-test.o \ 6 | $(OBJS-nopaxos-replica) $(OBJS-nopaxos-client) \ 7 | $(LIB-simtransport) \ 8 | $(GTEST_MAIN) 9 | 10 | TEST_BINS += $(d)nopaxos-test 11 | -------------------------------------------------------------------------------- /spec/tests/merge-tests/OneEmpty: -------------------------------------------------------------------------------- 1 | newview: 1 2 | log: { 3 | replicaidx: 0 4 | view: 0 5 | lastNormalView: 0 6 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 7 | entries: {view: 0; opnum: 2; id: "1/2"; spec: f} 8 | } 9 | 10 | log: { 11 | replicaidx: 1 12 | view: 0 13 | lastNormalView: 0 14 | } 15 | 16 | expected: {view: 0; opnum: 1; id: "1/1"; spec: f} 17 | expected: {view: 0; opnum: 2; id: "1/2"; spec: f} 18 | -------------------------------------------------------------------------------- /spec/tests/merge-tests/SpeculativeNoQuorum: -------------------------------------------------------------------------------- 1 | newview: 2 2 | log: { 3 | replicaidx: 0 4 | view: 2 5 | lastNormalView: 1 6 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 7 | } 8 | 9 | log: { 10 | replicaidx: 1 11 | view: 2 12 | lastNormalView: 1 13 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 14 | entries: {view: 1; opnum: 2; id: "1/2"; spec: t} 15 | } 16 | 17 | expected: {view: 0; opnum: 1; id: "1/1"; spec: f} 18 | expected: {view: 2; opnum: 2; id: "1/2"; spec: t} 19 | -------------------------------------------------------------------------------- /lib/latency-format.proto: -------------------------------------------------------------------------------- 1 | package specpaxos.latency.format; 2 | 3 | message LatencyDist 4 | { 5 | required uint32 type = 1; 6 | required uint64 min = 2; 7 | required uint64 max = 3; 8 | required uint64 total = 4; 9 | required uint64 count = 5; 10 | repeated uint32 buckets = 6; 11 | } 12 | 13 | message Latency 14 | { 15 | required string name = 1; 16 | repeated LatencyDist dists = 2; 17 | } 18 | 19 | message LatencyFile 20 | { 21 | repeated Latency latencies = 1; 22 | } 23 | -------------------------------------------------------------------------------- /spec/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | GTEST_SRCS += $(d)spec-test.cc $(d)merge-test.cc 4 | PROTOS += $(d)merge-test-case.proto 5 | 6 | $(d)spec-test: $(o)spec-test.o \ 7 | $(OBJS-spec-replica) $(OBJS-spec-client) \ 8 | $(LIB-simtransport) \ 9 | $(GTEST_MAIN) 10 | 11 | $(d)merge-test: $(o)merge-test.o $(o)merge-test-case.o \ 12 | $(OBJS-spec-replica) $(OBJS-spec-client) \ 13 | $(LIB-simtransport) \ 14 | $(GTEST_MAIN) 15 | 16 | TEST_BINS += $(d)merge-test $(d)spec-test 17 | -------------------------------------------------------------------------------- /nopaxos/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | replica.cc client.cc) 5 | 6 | PROTOS += $(addprefix $(d), \ 7 | nopaxos-proto.proto) 8 | 9 | OBJS-nopaxos-client := $(o)client.o $(o)nopaxos-proto.o \ 10 | $(OBJS-client) $(LIB-message) \ 11 | $(LIB-configuration) 12 | 13 | OBJS-nopaxos-replica := $(o)replica.o $(o)nopaxos-proto.o \ 14 | $(OBJS-replica) $(LIB-message) \ 15 | $(LIB-configuration) 16 | 17 | include $(d)tests/Rules.mk 18 | -------------------------------------------------------------------------------- /spec/tests/merge-tests/AllCommitted: -------------------------------------------------------------------------------- 1 | newview: 2 2 | log: { 3 | replicaidx: 0 4 | view: 2 5 | lastNormalView: 1 6 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 7 | entries: {view: 0; opnum: 2; id: "1/2"; spec: f} 8 | } 9 | 10 | log: { 11 | replicaidx: 1 12 | view: 2 13 | lastNormalView: 1 14 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 15 | entries: {view: 0; opnum: 2; id: "1/2"; spec: f} 16 | } 17 | 18 | expected: {view: 0; opnum: 1; id: "1/1"; spec: f} 19 | expected: {view: 0; opnum: 2; id: "1/2"; spec: f} 20 | -------------------------------------------------------------------------------- /spec/tests/merge-tests/SpeculativeQuorum: -------------------------------------------------------------------------------- 1 | newview: 2 2 | log: { 3 | replicaidx: 0 4 | view: 2 5 | lastNormalView: 1 6 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 7 | entries: {view: 1; opnum: 2; id: "1/2"; spec: t} 8 | } 9 | 10 | log: { 11 | replicaidx: 1 12 | view: 2 13 | lastNormalView: 1 14 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 15 | entries: {view: 1; opnum: 2; id: "1/2"; spec: t} 16 | } 17 | 18 | expected: {view: 0; opnum: 1; id: "1/1"; spec: f} 19 | expected: {view: 1; opnum: 2; id: "1/2"; spec: f} 20 | -------------------------------------------------------------------------------- /vr/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | replica.cc client.cc) 5 | 6 | PROTOS += $(addprefix $(d), \ 7 | vr-proto.proto) 8 | 9 | OBJS-vr-client := $(o)client.o $(o)vr-proto.o \ 10 | $(OBJS-client) $(LIB-message) \ 11 | $(LIB-configuration) 12 | 13 | OBJS-vr-replica := $(o)replica.o $(o)vr-proto.o \ 14 | $(OBJS-replica) $(LIB-message) \ 15 | $(LIB-configuration) $(LIB-latency) 16 | 17 | include $(d)tests/Rules.mk 18 | 19 | -------------------------------------------------------------------------------- /spec/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | replica.cc client.cc) 5 | 6 | PROTOS += $(addprefix $(d), \ 7 | spec-proto.proto) 8 | 9 | OBJS-spec-client := $(o)client.o $(o)spec-proto.o \ 10 | $(OBJS-client) $(LIB-message) \ 11 | $(LIB-configuration) 12 | 13 | OBJS-spec-replica := $(o)replica.o $(o)spec-proto.o \ 14 | $(OBJS-replica) $(LIB-message) \ 15 | $(LIB-configuration) $(LIB-latency) 16 | 17 | #include $(d)tests/Rules.mk 18 | -------------------------------------------------------------------------------- /common/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | client.cc replica.cc log.cc) 5 | 6 | PROTOS += $(addprefix $(d), \ 7 | request.proto) 8 | 9 | LIB-request := $(o)request.o 10 | 11 | OBJS-client := $(o)client.o \ 12 | $(LIB-message) $(LIB-configuration) $(LIB-transport) \ 13 | $(LIB-request) 14 | 15 | OBJS-replica := $(o)replica.o $(o)log.o \ 16 | $(LIB-message) $(LIB-request) \ 17 | $(LIB-configuration) $(LIB-udptransport) 18 | 19 | include $(d)tests/Rules.mk 20 | -------------------------------------------------------------------------------- /unreplicated/unreplicated-proto.proto: -------------------------------------------------------------------------------- 1 | import "common/request.proto"; 2 | 3 | package specpaxos.unreplicated.proto; 4 | 5 | message RequestMessage { 6 | required specpaxos.Request req = 1; 7 | } 8 | 9 | message ReplyMessage { 10 | optional uint64 view = 1; 11 | optional uint64 opnum = 2; 12 | required specpaxos.Request req = 3; 13 | required bytes reply = 4; 14 | } 15 | 16 | message UnloggedRequestMessage { 17 | required specpaxos.UnloggedRequest req = 1; 18 | } 19 | 20 | message UnloggedReplyMessage { 21 | required bytes reply = 1; 22 | } 23 | -------------------------------------------------------------------------------- /fastpaxos/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | replica.cc client.cc) 5 | 6 | PROTOS += $(addprefix $(d), \ 7 | fastpaxos-proto.proto) 8 | 9 | OBJS-fastpaxos-client := $(o)client.o $(o)fastpaxos-proto.o \ 10 | $(OBJS-client) $(LIB-message) \ 11 | $(LIB-configuration) 12 | 13 | OBJS-fastpaxos-replica := $(o)replica.o $(o)fastpaxos-proto.o \ 14 | $(OBJS-replica) $(LIB-message) \ 15 | $(LIB-configuration) 16 | 17 | #include $(d)tests/Rules.mk 18 | -------------------------------------------------------------------------------- /unreplicated/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | replica.cc client.cc) 5 | 6 | PROTOS += $(addprefix $(d), \ 7 | unreplicated-proto.proto) 8 | 9 | OBJS-unreplicated-client := $(o)client.o $(o)unreplicated-proto.o \ 10 | $(OBJS-client) $(LIB-message) \ 11 | $(LIB-configuration) 12 | 13 | OBJS-unreplicated-replica := $(o)replica.o $(o)unreplicated-proto.o \ 14 | $(OBJS-replica) $(LIB-message) \ 15 | $(LIB-configuration) 16 | 17 | include $(d)tests/Rules.mk 18 | 19 | -------------------------------------------------------------------------------- /spec/tests/merge-tests/Conflict: -------------------------------------------------------------------------------- 1 | newview: 2 2 | log: { 3 | replicaidx: 0 4 | view: 2 5 | lastNormalView: 1 6 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 7 | entries: {view: 1; opnum: 2; id: "2/1"; spec: t} 8 | } 9 | 10 | log: { 11 | replicaidx: 1 12 | view: 2 13 | lastNormalView: 1 14 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 15 | entries: {view: 1; opnum: 2; id: "1/2"; spec: t} 16 | } 17 | 18 | expected: {view: 0; opnum: 1; id: "1/1"; spec: f} 19 | expected: {view: 2; opnum: 2; id: "2/1"; spec: t} 20 | expected: {view: 2; opnum: 3; id: "1/2"; spec: t} 21 | -------------------------------------------------------------------------------- /bench/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | client.cc benchmark.cc replica.cc) 5 | 6 | OBJS-benchmark := $(o)benchmark.o \ 7 | $(LIB-message) $(LIB-latency) 8 | 9 | $(d)client: $(o)client.o $(OBJS-spec-client) $(OBJS-vr-client) $(OBJS-fastpaxos-client) $(OBJS-unreplicated-client) $(OBJS-nopaxos-client) $(OBJS-benchmark) $(LIB-udptransport) 10 | 11 | $(d)replica: $(o)replica.o $(OBJS-spec-replica) $(OBJS-vr-replica) $(OBJS-fastpaxos-replica) $(OBJS-unreplicated-replica) $(OBJS-nopaxos-replica) $(LIB-udptransport) 12 | 13 | BINS += $(d)client $(d)replica 14 | -------------------------------------------------------------------------------- /spec/tests/merge-test-case.proto: -------------------------------------------------------------------------------- 1 | package specpaxos.spec.test; 2 | 3 | import "spec/spec-proto.proto"; 4 | 5 | message TestLogEntry 6 | { 7 | required uint64 view = 1; 8 | required uint64 opnum = 2; 9 | required string id = 3; 10 | required bool spec = 4; 11 | } 12 | 13 | message TestLog 14 | { 15 | required uint32 replicaidx = 1; 16 | required uint64 view = 2; 17 | required uint64 lastNormalView = 3; 18 | repeated TestLogEntry entries = 4; 19 | } 20 | 21 | message MergeTestCase 22 | { 23 | required uint64 newview = 1; 24 | repeated TestLog log = 2; 25 | repeated TestLogEntry expected = 3; 26 | } 27 | -------------------------------------------------------------------------------- /lib/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | # 4 | # gtest-based tests 5 | # 6 | GTEST_SRCS += $(addprefix $(d), \ 7 | configuration-test.cc \ 8 | simtransport-test.cc \ 9 | workertasks-test.cc) 10 | 11 | PROTOS += $(d)simtransport-testmessage.proto 12 | 13 | $(d)configuration-test: $(o)configuration-test.o $(LIB-configuration) $(GTEST_MAIN) 14 | 15 | TEST_BINS += $(d)configuration-test 16 | 17 | $(d)simtransport-test: $(o)simtransport-test.o $(LIB-simtransport) $(o)simtransport-testmessage.o $(GTEST_MAIN) 18 | 19 | TEST_BINS += $(d)simtransport-test 20 | 21 | $(d)workertasks-test: $(o)workertasks-test.o $(LIB-transport) $(GTEST_MAIN) 22 | 23 | TEST_BINS += $(d)workertasks-test 24 | -------------------------------------------------------------------------------- /common/request.proto: -------------------------------------------------------------------------------- 1 | package specpaxos; 2 | 3 | message ShardOp { 4 | required uint32 shard = 1; 5 | required bytes op = 2; 6 | } 7 | 8 | message Request { 9 | required bytes op = 1; 10 | required uint64 clientid = 2; 11 | required uint64 clientreqid = 3; 12 | repeated ShardOp ops = 4; 13 | } 14 | 15 | message UnloggedRequest { 16 | required bytes op = 1; 17 | required uint64 clientid = 2; 18 | required uint64 clientreqid = 3; 19 | } 20 | 21 | message MsgLogEntry { 22 | required uint64 view = 1; 23 | required uint64 opnum = 2; 24 | required uint64 sessnum = 3; 25 | required uint64 msgnum = 4; 26 | required uint32 shardnum = 5; 27 | required Request request = 6; 28 | required uint32 state = 7; 29 | required bytes hash = 8; 30 | } 31 | -------------------------------------------------------------------------------- /spec/tests/merge-tests/Divergence: -------------------------------------------------------------------------------- 1 | newview: 2 2 | log: { 3 | replicaidx: 0 4 | view: 2 5 | lastNormalView: 1 6 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 7 | entries: {view: 1; opnum: 2; id: "2/1"; spec: t} 8 | entries: {view: 1; opnum: 3; id: "1/2"; spec: t} 9 | entries: {view: 1; opnum: 4; id: "3/1"; spec: t} 10 | } 11 | 12 | log: { 13 | replicaidx: 1 14 | view: 2 15 | lastNormalView: 1 16 | entries: {view: 0; opnum: 1; id: "1/1"; spec: f} 17 | entries: {view: 1; opnum: 2; id: "1/2"; spec: t} 18 | entries: {view: 1; opnum: 3; id: "2/1"; spec: t} 19 | entries: {view: 1; opnum: 4; id: "3/1"; spec: t} 20 | } 21 | 22 | expected: {view: 0; opnum: 1; id: "1/1"; spec: f} 23 | expected: {view: 2; opnum: 2; id: "2/1"; spec: t} 24 | expected: {view: 2; opnum: 3; id: "1/2"; spec: t} 25 | expected: {view: 2; opnum: 4; id: "3/1"; spec: t} 26 | -------------------------------------------------------------------------------- /lib/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | lookup3.cc message.cc memory.cc \ 5 | latency.cc configuration.cc transport.cc udptransport.cc simtransport.cc \ 6 | workertasks.cc) 7 | 8 | PROTOS += $(addprefix $(d), \ 9 | latency-format.proto) 10 | 11 | LIB-hash := $(o)lookup3.o 12 | 13 | LIB-message := $(o)message.o $(LIB-hash) 14 | 15 | LIB-hashtable := $(LIB-hash) $(LIB-message) 16 | 17 | LIB-memory := $(o)memory.o 18 | 19 | LIB-latency := $(o)latency.o $(o)latency-format.o $(LIB-message) 20 | 21 | LIB-configuration := $(o)configuration.o $(LIB-message) 22 | 23 | LIB-transport := $(o)transport.o $(o)workertasks.o $(LIB-message) $(LIB-configuration) 24 | 25 | LIB-simtransport := $(o)simtransport.o $(LIB-transport) $(LIB-request) $(LIB-no-proto) $(LIB-mcast-proto) 26 | 27 | LIB-udptransport := $(o)udptransport.o $(LIB-transport) 28 | 29 | 30 | include $(d)tests/Rules.mk 31 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013--2017 University of Washington 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/tests/workertasks-test.cc: -------------------------------------------------------------------------------- 1 | #include "lib/workertasks.h" 2 | #include "ctpl/ctpl_stl.h" 3 | #include 4 | #include 5 | 6 | class WorkerTasksTest : public ::testing::Test 7 | { 8 | protected: 9 | virtual void SetUp() override { 10 | worker_pool = new ctpl::thread_pool(4); 11 | tasks = new WorkerTasks(); 12 | } 13 | 14 | virtual void TearDown() override { 15 | delete tasks; 16 | delete worker_pool; 17 | } 18 | 19 | ctpl::thread_pool *worker_pool; 20 | WorkerTasks *tasks; 21 | }; 22 | 23 | TEST_F(WorkerTasksTest, SimpleTasksTest) 24 | { 25 | std::thread client([=](){ 26 | for (int i = 0; i < 10; i++) { 27 | task_t task = this->tasks->PullNextCompletedTask(); 28 | EXPECT_TRUE(task.done); 29 | EXPECT_EQ(task.sid, 0); 30 | EXPECT_EQ(task.msgid, i); 31 | } 32 | }); 33 | 34 | for (int i = 0; i < 10; i++) { 35 | taskid_t taskid = tasks->CreateTask(); 36 | worker_pool->push([=](int fd){ 37 | task_t task; 38 | task.sid = 0; 39 | task.msgid = taskid; 40 | this->tasks->CompleteTask(taskid, task); 41 | }); 42 | } 43 | 44 | client.join(); 45 | EXPECT_TRUE(tasks->IsEmpty()); 46 | } 47 | -------------------------------------------------------------------------------- /fastpaxos/fastpaxos-proto.proto: -------------------------------------------------------------------------------- 1 | import "common/request.proto"; 2 | 3 | package specpaxos.fastpaxos.proto; 4 | 5 | message RequestMessage { 6 | required specpaxos.Request req = 1; 7 | } 8 | 9 | message ReplyMessage { 10 | required uint64 view = 1; 11 | required uint64 opnum = 2; 12 | required bytes reply = 3; 13 | required uint64 clientreqid = 4; 14 | } 15 | 16 | message UnloggedRequestMessage { 17 | required specpaxos.UnloggedRequest req = 1; 18 | } 19 | 20 | message UnloggedReplyMessage { 21 | required bytes reply = 1; 22 | } 23 | 24 | message PrepareOKMessage { 25 | required uint64 view = 1; 26 | required uint64 opnum = 2; 27 | required uint32 replicaIdx = 3; 28 | required specpaxos.Request req = 4; 29 | required uint32 slowpath = 5; 30 | } 31 | 32 | message PrepareMessage { 33 | required uint64 view = 1; 34 | required uint64 opnum = 2; 35 | required specpaxos.Request req = 3; 36 | } 37 | 38 | message CommitMessage { 39 | required uint64 view = 1; 40 | required uint64 opnum = 2; 41 | required specpaxos.Request req = 3; 42 | } 43 | 44 | message RequestStateTransferMessage { 45 | required uint64 view = 1; 46 | required uint64 opnum = 2; 47 | } 48 | 49 | message StateTransferMessage { 50 | required uint64 view = 1; 51 | required uint64 opnum = 2; 52 | repeated specpaxos.MsgLogEntry entries = 3; 53 | required uint64 lastop = 4; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /lib/workertasks.cc: -------------------------------------------------------------------------------- 1 | #include "lib/workertasks.h" 2 | 3 | WorkerTasks::WorkerTasks() 4 | { 5 | next_taskid_ = 0; 6 | done_ = false; 7 | } 8 | 9 | WorkerTasks::~WorkerTasks() { } 10 | 11 | taskid_t 12 | WorkerTasks::CreateTask() 13 | { 14 | // Only the main transport thread can 15 | // call this function 16 | std::unique_lock lck(tasks_mutex_); 17 | taskid_t taskid = next_taskid_++; 18 | task_t task; 19 | task.done = false; 20 | 21 | tasks_[taskid] = task; 22 | task_queue_.push_back(taskid); 23 | 24 | return taskid; 25 | } 26 | 27 | void 28 | WorkerTasks::CompleteTask(taskid_t taskid, task_t task) 29 | { 30 | std::unique_lock lck(tasks_mutex_); 31 | task.done = true; 32 | tasks_[taskid] = task; 33 | task_cv_.notify_all(); 34 | } 35 | 36 | task_t 37 | WorkerTasks::PullNextCompletedTask() 38 | { 39 | std::unique_lock lck(tasks_mutex_); 40 | task_t completed_task; 41 | while (!done_) { 42 | if (!task_queue_.empty()) { 43 | if (tasks_[task_queue_.front()].done) { 44 | break; 45 | } 46 | } 47 | task_cv_.wait(lck); 48 | } 49 | if (!done_) { 50 | completed_task = tasks_[task_queue_.front()]; 51 | tasks_.erase(task_queue_.front()); 52 | task_queue_.pop_front(); 53 | } 54 | return completed_task; 55 | } 56 | 57 | bool 58 | WorkerTasks::IsEmpty() 59 | { 60 | return tasks_.empty(); 61 | } 62 | 63 | void 64 | WorkerTasks::Stop() { 65 | done_ = true; 66 | task_cv_.notify_all(); 67 | } 68 | -------------------------------------------------------------------------------- /lib/workertasks.h: -------------------------------------------------------------------------------- 1 | /** 2 | * lib/workertasks.h 3 | * A work queue for multi-threaded transports. The main 4 | * transport thread reads network packets and create a 5 | * task (ordered). The main thread assign the task to a 6 | * worker thread which deserialize the packet. After the 7 | * worker is done, it writes the deserialized packet into 8 | * the task and indicates the task is done. The replication 9 | * thread reads finished tasks in the order assigned by 10 | * the main thread. 11 | * 12 | * @author Jialin Li. 13 | */ 14 | 15 | #ifndef _LIB_WORKERTASKS_H_ 16 | #define _LIB_WORKERTASKS_H_ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "transport.h" 24 | 25 | typedef uint64_t taskid_t; 26 | 27 | struct task_t { 28 | TransportReceiver *receiver; 29 | TransportAddress *remote; 30 | string type; 31 | string data; 32 | uint64_t sid; 33 | uint64_t msgid; 34 | std::map *rid_msgid; 35 | bool done; 36 | }; 37 | 38 | class WorkerTasks { 39 | public: 40 | WorkerTasks(); 41 | ~WorkerTasks(); 42 | 43 | taskid_t CreateTask(); 44 | void CompleteTask(taskid_t taskid, task_t task); 45 | task_t PullNextCompletedTask(); 46 | bool IsEmpty(); 47 | void Stop(); 48 | 49 | private: 50 | std::unordered_map tasks_; 51 | std::list task_queue_; 52 | taskid_t next_taskid_; 53 | 54 | std::mutex tasks_mutex_; 55 | std::condition_variable task_cv_; 56 | bool done_; 57 | }; 58 | 59 | #endif /* _LIB_WORKERTASKS_H_ */ 60 | -------------------------------------------------------------------------------- /lib/memory.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * memory.h: 5 | * parsing and pretty-printing of memory sizes 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Copyright 2009-2012 Massachusetts Institute of Technology 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_MEMORY_H_ 33 | #define _LIB_MEMORY_H_ 34 | 35 | #include 36 | 37 | // Experimentally determined malloc size (for smallish objects, at 38 | // least). This is (v+8) rounded up to the nearest multiple of 16 39 | // (though anything less than 24 takes 32 bytes). Obviously this 40 | // doesn't account for fragmentation. 41 | #define MALLOC_SIZE(size) ((size) <= 24 ? 32 : (((size) + 7) | 15) + 1) 42 | 43 | #define MEMORY_FMTSIZE_BUF 22 44 | 45 | char *Memory_FmtSize(char *buf, size_t n); 46 | size_t Memory_ReadSize(const char *buf, const char **endPtr); 47 | 48 | #endif // _LIB_MEMORY_H_ 49 | -------------------------------------------------------------------------------- /common/replica-inl.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * replica-inl.h: 5 | * inline/template functions for common replica interface 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _COMMON_REPLICA_INL_H_ 32 | #define _COMMON_REPLICA_INL_H_ 33 | 34 | template 35 | void 36 | Replica::Execute(opnum_t opnum, 37 | const Request &msg, 38 | MSG &reply, 39 | void *arg, 40 | void *ret) 41 | { 42 | string res; 43 | ReplicaUpcall(opnum, msg.op(), res, arg, ret); 44 | 45 | reply.set_reply(res); 46 | } 47 | 48 | template 49 | void 50 | Replica::ExecuteUnlogged(const UnloggedRequest &msg, 51 | MSG &reply) 52 | { 53 | string res; 54 | UnloggedUpcall(msg.op(), res); 55 | 56 | reply.set_reply(res); 57 | } 58 | 59 | #endif // _COMMON_REPLICA_INL_H_ 60 | -------------------------------------------------------------------------------- /vr/vr-proto.proto: -------------------------------------------------------------------------------- 1 | import "common/request.proto"; 2 | 3 | package specpaxos.vr.proto; 4 | 5 | message RequestMessage { 6 | required specpaxos.Request req = 1; 7 | } 8 | 9 | message ReplyMessage { 10 | required uint64 view = 1; 11 | required uint64 opnum = 2; 12 | required bytes reply = 3; 13 | required uint64 clientreqid = 4; 14 | } 15 | 16 | message UnloggedRequestMessage { 17 | required specpaxos.UnloggedRequest req = 1; 18 | } 19 | 20 | message UnloggedReplyMessage { 21 | required bytes reply = 1; 22 | } 23 | 24 | message PrepareMessage { 25 | required uint64 view = 1; 26 | required uint64 opnum = 2; 27 | required uint64 batchstart = 3; 28 | repeated Request request = 4; 29 | } 30 | 31 | message PrepareOKMessage { 32 | required uint64 view = 1; 33 | required uint64 opnum = 2; 34 | required uint32 replicaIdx = 3; 35 | } 36 | 37 | message CommitMessage { 38 | required uint64 view = 1; 39 | required uint64 opnum = 2; 40 | } 41 | 42 | message RequestStateTransferMessage { 43 | required uint64 view = 1; 44 | required uint64 opnum = 2; 45 | } 46 | 47 | message StateTransferMessage { 48 | required uint64 view = 1; 49 | required uint64 opnum = 2; 50 | repeated specpaxos.MsgLogEntry entries = 3; 51 | } 52 | 53 | message StartViewChangeMessage { 54 | required uint64 view = 1; 55 | required uint32 replicaIdx = 2; 56 | required uint64 lastCommitted = 3; 57 | } 58 | 59 | message DoViewChangeMessage { 60 | required uint64 view = 1; 61 | required uint64 lastNormalView = 2; 62 | required uint64 lastOp = 3; 63 | required uint64 lastCommitted = 4; 64 | repeated specpaxos.MsgLogEntry entries = 5; 65 | required uint32 replicaIdx = 6; 66 | } 67 | 68 | message StartViewMessage { 69 | required uint64 view = 1; 70 | required uint64 lastOp = 2; 71 | required uint64 lastCommitted = 3; 72 | repeated specpaxos.MsgLogEntry entries = 4; 73 | } 74 | 75 | message RecoveryMessage { 76 | required uint32 replicaIdx = 1; 77 | required uint64 nonce = 2; 78 | } 79 | 80 | message RecoveryResponseMessage { 81 | required uint64 view = 1; 82 | required uint64 nonce = 2; 83 | repeated specpaxos.MsgLogEntry entries = 3; 84 | optional uint64 lastOp = 4; 85 | optional uint64 lastCommitted = 5; 86 | required uint32 replicaIdx = 6; 87 | } 88 | -------------------------------------------------------------------------------- /spec/spec-proto.proto: -------------------------------------------------------------------------------- 1 | import "common/request.proto"; 2 | 3 | package specpaxos.spec.proto; 4 | 5 | message RequestMessage { 6 | required specpaxos.Request req = 1; 7 | } 8 | 9 | message SpeculativeReplyMessage { 10 | required uint64 clientreqid = 1; 11 | required uint32 replicaidx = 2; 12 | required uint64 view = 3; 13 | required uint64 opnum = 4; 14 | required bytes loghash = 5; 15 | required bytes reply = 6; 16 | required bool committed = 7; 17 | } 18 | 19 | message UnloggedRequestMessage { 20 | required specpaxos.UnloggedRequest req = 1; 21 | } 22 | 23 | message UnloggedReplyMessage { 24 | required bytes reply = 1; 25 | } 26 | 27 | message SyncMessage { 28 | required uint64 view = 1; 29 | optional uint64 lastCommitted = 2; 30 | optional bytes lastCommittedHash = 3; 31 | optional uint64 lastSpeculative = 4; 32 | } 33 | 34 | message SyncReplyMessage { 35 | required uint64 view = 1; 36 | required uint64 lastSpeculative = 2; 37 | required bytes lastSpeculativeHash = 3; 38 | required uint32 replicaidx = 4; 39 | } 40 | 41 | // This is from a client to server. 42 | message RequestViewChangeMessage { 43 | // Note that this is the view the client saw an operation fail in, 44 | // not the desired new view. (It's not really the client's place 45 | // to specify what the new view should be!) 46 | required uint64 view = 1; 47 | } 48 | 49 | message StartViewChangeMessage { 50 | required uint64 view = 1; 51 | required uint32 replicaIdx = 2; 52 | required uint64 lastCommitted = 3; 53 | } 54 | 55 | message DoViewChangeMessage { 56 | required uint64 view = 1; 57 | required uint64 lastNormalView = 2; 58 | required uint64 lastSpeculative = 3; 59 | required uint64 lastCommitted = 4; 60 | repeated specpaxos.MsgLogEntry entries = 5; 61 | required uint32 replicaIdx = 6; 62 | } 63 | 64 | message StartViewMessage { 65 | required uint64 view = 1; 66 | required uint64 lastSpeculative = 2; 67 | required uint64 lastCommitted = 3; 68 | repeated specpaxos.MsgLogEntry entries = 4; 69 | } 70 | 71 | message InViewMessage { 72 | required uint64 view = 1; 73 | required uint64 lastSpeculative = 2; 74 | required uint32 replicaIdx = 3; 75 | } 76 | 77 | message FillLogGapMessage { 78 | required uint64 view = 1; 79 | required uint64 lastCommitted = 2; 80 | } 81 | 82 | message FillDVCGapMessage { 83 | required uint64 view = 1; 84 | required uint64 lastCommitted = 2; 85 | } 86 | -------------------------------------------------------------------------------- /ctpl/README.md: -------------------------------------------------------------------------------- 1 | CTPL 2 | ==== 3 | 4 | Modern and efficient C++ Thread Pool Library 5 | 6 | 7 | A thread pool is a programming pattern for parallel execution of jobs, http://en.wikipedia.org/wiki/Thread_pool_pattern. 8 | 9 | More specifically, there are some threads dedicated to the pool and a container of jobs. The jobs come to the pool dynamically. A job is fetched and deleted from the container when there is an idle thread. The job is then run on that thread. 10 | 11 | A thread pool is helpful when you want to minimize time of loading and destroying threads and when you want to limit the number of parallel jobs that run simultanuasly. For example, time consuming event handlers may be processed in a thread pool to make UI more responsive. 12 | 13 | Features: 14 | - standard c++ language, tested to compile on MS Visual Studio 2013 (2012?), gcc 4.8.2 and mingw 4.8.1(with posix threads) 15 | - simple but effiecient solution, one header only, no need to compile a binary library 16 | - query the number of idle threads and resize the pool dynamically 17 | - one API to push to the thread pool any collable object: lambdas, functors, functions, result of bind expression 18 | - collable objects with variadic number of parameters plus index of the thread running the object 19 | - automatic template argument deduction 20 | - get returned value of any type with standard c++ futures 21 | - get fired exceptions with standard c++ futures 22 | - use for any purpose under Apache license 23 | - two variants, one depends on Boost Lockfree Queue library, http://boost.org, which is a header only library 24 | 25 | 26 | Sample usage 27 | 28 | void first(int id) { 29 | std::cout << "hello from " << id << '\n'; 30 | } 31 | 32 | struct Second { 33 | void operator()(int id) const { 34 | std::cout << "hello from " << id << '\n'; 35 | } 36 | } second; 37 | 38 | void third(int id, const std::string & additional_param) {} 39 | 40 | 41 | int main () { 42 | 43 | ctpl::thread_pool p(2 /* two threads in the pool */); 44 | 45 | p.push(first); // function 46 | 47 | p.push(third, "additional_param"); 48 | 49 | p.push( [] (int id){ 50 | std::cout << "hello from " << id << '\n'; 51 | }); // lambda 52 | 53 | p.push(std::ref(second)); // functor, reference 54 | 55 | p.push(const_cast<const Second &>(second)); // functor, copy ctor 56 | 57 | p.push(std::move(second)); // functor, move ctor 58 | 59 | } 60 | -------------------------------------------------------------------------------- /bench/benchmark.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * benchmark.h: 5 | * simple replication benchmark client 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "common/client.h" 32 | #include "lib/latency.h" 33 | #include "lib/transport.h" 34 | 35 | namespace specpaxos { 36 | 37 | class BenchmarkClient 38 | { 39 | public: 40 | BenchmarkClient(Client &client, Transport &transport, 41 | int numRequests, uint64_t delay, 42 | int warmupSec, 43 | int tputInterval, 44 | string latencyFilename = ""); 45 | void Start(); 46 | void OnReply(const string &request, const string &reply); 47 | struct Latency_t latency; 48 | bool started; 49 | bool done; 50 | bool cooldownDone; 51 | int tputInterval; 52 | std::vector latencies; 53 | 54 | private: 55 | void SendNext(); 56 | void Finish(); 57 | void WarmupDone(); 58 | void CooldownDone(); 59 | void TimeInterval(); 60 | Client &client; 61 | Transport &transport; 62 | int numRequests; 63 | uint64_t delay; 64 | int n; 65 | int warmupSec; 66 | struct timeval startTime; 67 | struct timeval endTime; 68 | string latencyFilename; 69 | int msSinceStart; 70 | int opLastInterval; 71 | }; 72 | 73 | } // namespace specpaxos 74 | -------------------------------------------------------------------------------- /lib/assert.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * assert.h: 5 | * assertion macros that integrate with the logging framework 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _LIB_ASSERT_H_ 32 | #define _LIB_ASSERT_H_ 33 | 34 | /* 35 | * Assertion macros. 36 | * 37 | * Currently these mostly just wrap the standard C assert but 38 | * eventually they should tie in better with the logging framework. 39 | */ 40 | #include 41 | #include 42 | #include 43 | #include "lib/message.h" 44 | 45 | #define ASSERT(x) Assert(x) 46 | 47 | // XXX These should output the expected and actual values in addition 48 | // to failing. 49 | #define ASSERT_EQ(x, y) Assert(x == y) 50 | #define ASSERT_LT(x, y) Assert(x < y) 51 | #define ASSERT_GT(x, y) Assert(x > y) 52 | #define ASSERT_LE(x, y) Assert(x <= y) 53 | #define ASSERT_GE(x, y) Assert(x >= y) 54 | 55 | #define NOT_REACHABLE() do { \ 56 | fprintf(stderr, "NOT_REACHABLE point reached: %s, line %d\n", \ 57 | __FILE__, __LINE__); \ 58 | abort(); \ 59 | } while (0) 60 | 61 | #define NOT_IMPLEMENTED() do { \ 62 | fprintf(stderr, "NOT_IMPLEMENTED point reached: %s, line %d\n", \ 63 | __FILE__, __LINE__); \ 64 | abort(); \ 65 | } while (0) 66 | 67 | 68 | #endif /* _LIB_ASSERT_H */ 69 | -------------------------------------------------------------------------------- /lib/transport.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * transport.cc: 5 | * message-passing network interface; common definitions 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "lib/assert.h" 32 | #include "lib/transport.h" 33 | 34 | TransportReceiver::~TransportReceiver() 35 | { 36 | delete this->myAddress; 37 | } 38 | 39 | void 40 | TransportReceiver::SetAddress(const TransportAddress *addr) 41 | { 42 | this->myAddress = addr; 43 | } 44 | 45 | const TransportAddress & 46 | TransportReceiver::GetAddress() 47 | { 48 | return *(this->myAddress); 49 | } 50 | 51 | Timeout::Timeout(Transport *transport, uint64_t ms, timer_callback_t cb) 52 | : transport(transport), ms(ms), cb(cb) 53 | { 54 | timerId = 0; 55 | } 56 | 57 | Timeout::~Timeout() 58 | { 59 | Stop(); 60 | } 61 | 62 | void 63 | Timeout::SetTimeout(uint64_t ms) 64 | { 65 | ASSERT(!Active()); 66 | this->ms = ms; 67 | } 68 | 69 | uint64_t 70 | Timeout::Start() 71 | { 72 | return this->Reset(); 73 | } 74 | 75 | 76 | uint64_t 77 | Timeout::Reset() 78 | { 79 | Stop(); 80 | 81 | timerId = transport->Timer(ms, [this]() { 82 | timerId = 0; 83 | Reset(); 84 | cb(); 85 | }); 86 | 87 | return ms; 88 | } 89 | 90 | void 91 | Timeout::Stop() 92 | { 93 | if (timerId > 0) { 94 | transport->CancelTimer(timerId); 95 | timerId = 0; 96 | } 97 | } 98 | 99 | bool 100 | Timeout::Active() const 101 | { 102 | return (timerId != 0); 103 | } 104 | -------------------------------------------------------------------------------- /common/client.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * client.cc: 5 | * interface to replication client stubs 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "common/client.h" 32 | #include "common/request.pb.h" 33 | #include "lib/message.h" 34 | #include "lib/transport.h" 35 | 36 | #include 37 | 38 | namespace specpaxos { 39 | 40 | Client::Client(const Configuration &config, Transport *transport, 41 | uint64_t clientid) 42 | : config(config), transport(transport) 43 | { 44 | this->clientid = clientid; 45 | 46 | // Randomly generate a client ID 47 | // This is surely not the fastest way to get a random 64-bit int, 48 | // but it should be fine for this purpose. 49 | while (this->clientid == 0) { 50 | std::random_device rd; 51 | std::mt19937_64 gen(rd()); 52 | std::uniform_int_distribution dis; 53 | this->clientid = dis(gen); 54 | } 55 | 56 | transport->Register(this, config, -1, -1); 57 | } 58 | 59 | Client::~Client() 60 | { 61 | 62 | } 63 | 64 | void 65 | Client::ReceiveMessage(const TransportAddress &remote, 66 | const string &type, const string &data, 67 | void *meta_data) 68 | { 69 | Panic("Received unexpected message type: %s", 70 | type.c_str()); 71 | } 72 | 73 | void 74 | Client::Invoke(const std::map &requests, 75 | g_continuation_t continuation, 76 | void *arg) 77 | { 78 | Panic("Protocol does not support multi-shard request"); 79 | } 80 | 81 | } // namespace specpaxos 82 | -------------------------------------------------------------------------------- /lib/hash.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * hash.h: 5 | * header defining hash functions 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Copyright 2009-2012 Massachusetts Institute of Technology 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_HASH_H_ 33 | #define _LIB_HASH_H_ 34 | 35 | #include /* defines uint32_t etc */ 36 | #include /* size_t */ 37 | 38 | #ifdef __APPLE__ 39 | /* OS X: defines __LITTLE_ENDIAN__ or __BIG_ENDIAN__ */ 40 | #include 41 | #else 42 | #include /* attempt to define endianness */ 43 | #endif 44 | 45 | 46 | #define hashsize(n) ((uint32_t)1<<(n)) 47 | #define hashmask(n) (hashsize(n)-1) 48 | 49 | /* 50 | * My best guess at if you are big-endian or little-endian. This may 51 | * need adjustment. 52 | */ 53 | #if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ 54 | __BYTE_ORDER == __LITTLE_ENDIAN) || \ 55 | (defined(i386) || defined(__i386__) || defined(__i486__) || \ 56 | defined(__i586__) || defined(__i686__) || defined(vax) || \ 57 | defined(MIPSEL) || defined(__LITTLE_ENDIAN__)) 58 | # define HASH_LITTLE_ENDIAN 1 59 | # define HASH_BIG_ENDIAN 0 60 | #elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ 61 | __BYTE_ORDER == __BIG_ENDIAN) || \ 62 | (defined(sparc) || defined(POWERPC) || defined(mc68000) || \ 63 | defined(sel) || defined(__LITTLE_ENDIAN__)) 64 | # define HASH_LITTLE_ENDIAN 0 65 | # define HASH_BIG_ENDIAN 1 66 | #else 67 | # define HASH_LITTLE_ENDIAN 0 68 | # define HASH_BIG_ENDIAN 0 69 | #endif 70 | 71 | uint32_t hash(const void *key, size_t length, uint32_t initval); 72 | 73 | #endif // _LIB_HASH_H_ 74 | 75 | -------------------------------------------------------------------------------- /unreplicated/replica.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * unreplicated/replica.h: 5 | * dummy implementation of replication interface that just uses a 6 | * single replica and passes commands directly to it 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _UNREPLICATED_REPLICA_H_ 33 | #define _UNREPLICATED_REPLICA_H_ 34 | 35 | #include "common/replica.h" 36 | #include "unreplicated/unreplicated-proto.pb.h" 37 | 38 | #include "common/log.h" 39 | 40 | namespace specpaxos { 41 | namespace unreplicated { 42 | 43 | class UnreplicatedReplica : public Replica 44 | { 45 | public: 46 | UnreplicatedReplica(Configuration config, int myIdx, 47 | bool initialize, 48 | Transport *transport, AppReplica *app); 49 | void ReceiveMessage(const TransportAddress &remote, 50 | const string &type, const string &data, 51 | void *meta_data) override; 52 | 53 | private: 54 | void HandleRequest(const TransportAddress &remote, 55 | const proto::RequestMessage &msg); 56 | void HandleUnloggedRequest(const TransportAddress &remote, 57 | const proto::UnloggedRequestMessage &msg); 58 | 59 | void UpdateClientTable(const Request &req, 60 | const proto::ReplyMessage &reply); 61 | 62 | opnum_t last_op_; 63 | Log log; 64 | struct ClientTableEntry 65 | { 66 | uint64_t lastReqId; 67 | proto::ReplyMessage reply; 68 | }; 69 | std::map clientTable; 70 | }; 71 | 72 | } // namespace specpaxos::unreplicated 73 | } // namespace specpaxos 74 | 75 | #endif /* _UNREPLICATED_REPLICA_H_ */ 76 | -------------------------------------------------------------------------------- /sequencer/sequencer.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * sequencer/sequencer.h: 5 | * End-host network sequencer implementation. 6 | * 7 | * Copyright 2017 Jialin Li 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef __SEQUENCER_H__ 32 | #define __SEQUENCER_H__ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | 48 | namespace sequencer { 49 | 50 | class Sequencer { 51 | public: 52 | Sequencer(uint64_t sequencer_id); 53 | ~Sequencer(); 54 | 55 | uint64_t Increment(uint32_t groupIdx); 56 | uint64_t GetSequencerID() { return this->sequencer_id; }; 57 | 58 | private: 59 | std::unordered_map counters; 60 | uint64_t sequencer_id; 61 | }; 62 | 63 | class Configuration { 64 | public: 65 | Configuration(std::ifstream &file); 66 | ~Configuration(); 67 | 68 | std::string GetInterface(); 69 | std::string GetGroupAddr(); 70 | 71 | private: 72 | std::string interface; 73 | std::string groupAddr; 74 | }; 75 | 76 | class Transport { 77 | public: 78 | Transport(Sequencer *sequencer, Configuration *config); 79 | ~Transport(); 80 | void Run(); 81 | 82 | private: 83 | static const int ETHER_TYPE = 0x0800; 84 | static const int BUFFER_SIZE = 16384; 85 | static const int NONFRAG_MAGIC = 0x20050318; 86 | Sequencer *sequencer; 87 | Configuration *config; 88 | int sockfd; 89 | struct sockaddr_ll destSockAddr; 90 | 91 | bool ProcessPacket(uint8_t *packet, size_t len); 92 | }; 93 | 94 | } // namespace sequencer 95 | 96 | #endif /* __SEQUENCER_H__ */ 97 | -------------------------------------------------------------------------------- /lib/memory.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * memory.cc: 5 | * parsing and pretty-printing of memory sizes 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Copyright 2009-2012 Massachusetts Institute of Technology 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #include "memory.h" 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | char * 39 | Memory_FmtSize(char *buf, size_t n) 40 | { 41 | char suffix = 0; 42 | if ((n & 0x3ff) == 0) { 43 | n >>= 10; 44 | suffix = 'K'; 45 | } 46 | if ((n & 0x3ff) == 0) { 47 | n >>= 10; 48 | suffix = 'M'; 49 | } 50 | if ((n & 0x3ff) == 0) { 51 | n >>= 10; 52 | suffix = 'G'; 53 | } 54 | if (suffix) { 55 | sprintf(buf, "%llu%c", (unsigned long long)n, suffix); 56 | } else { 57 | sprintf(buf, "%llu", (unsigned long long)n); 58 | } 59 | return buf; 60 | } 61 | 62 | static unsigned long long 63 | Memory_ReadSize1(const char *buf, const char **endPtr) 64 | { 65 | unsigned long long res = strtoull(buf, (char **)endPtr, 0); 66 | switch (**endPtr) { 67 | case 'G': 68 | case 'g': 69 | res <<= 10; 70 | case 'M': 71 | case 'm': 72 | res <<= 10; 73 | case 'K': 74 | case 'k': 75 | res <<= 10; 76 | ++(*endPtr); 77 | } 78 | return res; 79 | } 80 | 81 | size_t 82 | Memory_ReadSize(const char *buf, const char **endPtr) 83 | { 84 | unsigned long long ret = 0; 85 | bool more; 86 | 87 | do { 88 | ret += Memory_ReadSize1(buf, &buf); 89 | if (*buf == '+' && *(buf+1)) { 90 | more = true; 91 | ++buf; 92 | } else { 93 | more = false; 94 | } 95 | } while (more); 96 | 97 | if (endPtr) 98 | *endPtr = buf; 99 | return (size_t)ret; 100 | } 101 | -------------------------------------------------------------------------------- /lib/timeval.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * timeval.h: 5 | * utility functions for manipulating timevals 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Copyright 2009-2012 Massachusetts Institute of Technology 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_TIMEVAL_H_ 33 | #define _LIB_TIMEVAL_H_ 34 | 35 | #include 36 | #include /* strftime */ 37 | #include /* malloc */ 38 | #include /* sprintf */ 39 | #include 40 | 41 | static inline struct timeval 42 | timeval_sub(struct timeval a, struct timeval b) { 43 | struct timeval result; 44 | 45 | if (a.tv_usec < b.tv_usec) { 46 | result.tv_sec = a.tv_sec - b.tv_sec - 1; 47 | result.tv_usec = a.tv_usec + 1000000 - b.tv_usec; 48 | } else { 49 | result.tv_sec = a.tv_sec - b.tv_sec; 50 | result.tv_usec = a.tv_usec - b.tv_usec; 51 | } 52 | return result; 53 | }; 54 | 55 | static inline bool 56 | timeval_lessthan(struct timeval a, struct timeval b) { 57 | return ((a.tv_sec < b.tv_sec) || 58 | ((a.tv_sec == b.tv_sec) && 59 | (a.tv_usec < b.tv_usec))); 60 | }; 61 | 62 | static inline struct timeval 63 | Timeval_FromSecs(double secs) 64 | { 65 | struct timeval res; 66 | res.tv_sec = (time_t)secs; 67 | res.tv_usec = (time_t) (secs - (long long)secs) * 1000000; 68 | return res; 69 | } 70 | 71 | #define FMT_TIMEVAL_ABS "%s" 72 | #define XVA_TIMEVAL_ABS(t) Message_DFree(Timeval_FmtAbs(t)) 73 | 74 | static inline char * 75 | Timeval_FmtAbs(struct timeval tv) 76 | { 77 | static const int LEN = 32; 78 | char *buf = (char *)malloc(LEN); 79 | if (!buf) 80 | return NULL; 81 | strftime(buf, LEN, "%H:%M:%S", localtime(&tv.tv_sec)); 82 | sprintf(buf + strlen(buf), ":%06ld", tv.tv_usec); 83 | return buf; 84 | } 85 | 86 | #define FMT_TIMEVAL_DIFF "%ld.%06ld" 87 | #define VA_TIMEVAL_DIFF(t) t.tv_sec, t.tv_usec 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /common/replica.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * replica.cc: 5 | * common functions for replica implementation regardless of 6 | * replication protocol 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #include "common/log.h" 33 | #include "common/replica.h" 34 | 35 | #include "lib/message.h" 36 | 37 | #include 38 | 39 | namespace specpaxos { 40 | 41 | Replica::Replica(const Configuration &configuration, int groupIdx, int replicaIdx, 42 | bool initialize, Transport *transport, AppReplica *app) 43 | : configuration(configuration), groupIdx(groupIdx), replicaIdx(replicaIdx), 44 | transport(transport), app(app) 45 | { 46 | transport->Register(this, configuration, groupIdx, replicaIdx); 47 | } 48 | 49 | Replica::~Replica() 50 | { 51 | 52 | } 53 | 54 | void 55 | Replica::LeaderUpcall(opnum_t opnum, const string &op, bool &replicate, string &res) 56 | { 57 | app->LeaderUpcall(opnum, op, replicate, res); 58 | } 59 | 60 | void 61 | Replica::ReplicaUpcall(opnum_t opnum, const string &op, string &res, void *arg, void *ret) 62 | { 63 | Debug("Making upcall for operation %s", op.c_str()); 64 | app->ReplicaUpcall(opnum, op, res, arg, ret); 65 | Debug("Upcall result: %s", res.c_str()); 66 | } 67 | 68 | void 69 | Replica::Rollback(opnum_t current, opnum_t to, Log &log) 70 | { 71 | Debug("Making rollback-upcall from " FMT_OPNUM " to " FMT_OPNUM, 72 | current, to); 73 | 74 | std::map reqs; 75 | for (opnum_t x = current; x > to; x--) { 76 | reqs.insert(std::pair(x, 77 | log.Find(x)->request.op())); 78 | } 79 | 80 | app->RollbackUpcall(current, to, reqs); 81 | } 82 | 83 | void 84 | Replica::Commit(opnum_t op) 85 | { 86 | app->CommitUpcall(op); 87 | } 88 | 89 | void 90 | Replica::UnloggedUpcall(const string &op, string &res) 91 | { 92 | app->UnloggedUpcall(op, res); 93 | } 94 | 95 | } // namespace specpaxos 96 | -------------------------------------------------------------------------------- /nopaxos/nopaxos-proto.proto: -------------------------------------------------------------------------------- 1 | import "common/request.proto"; 2 | 3 | package specpaxos.nopaxos.proto; 4 | 5 | message RequestMessage { 6 | required uint64 sessnum = 1; 7 | required uint64 msgnum = 2; 8 | required specpaxos.Request req = 3; 9 | } 10 | 11 | message ReplyMessage { 12 | required uint64 view = 1; 13 | required uint64 sessnum = 2; 14 | required uint64 opnum = 3; 15 | required uint64 clientreqid = 4; 16 | required uint32 replicaidx = 5; 17 | optional bytes reply = 6; 18 | } 19 | 20 | message UnloggedRequestMessage { 21 | required specpaxos.UnloggedRequest req = 1; 22 | } 23 | 24 | message UnloggedReplyMessage { 25 | required bytes reply = 1; 26 | } 27 | 28 | message GapRequestMessage { 29 | required uint64 view = 1; 30 | required uint64 sessnum = 2; 31 | required uint64 opnum = 3; 32 | } 33 | 34 | message GapReplyMessage { 35 | required uint64 view = 1; 36 | required uint64 sessnum = 2; 37 | required uint64 opnum = 3; 38 | required bool isfound = 4; 39 | required bool isgap = 5; 40 | required uint32 replicaidx = 6; 41 | optional specpaxos.Request req = 7; 42 | } 43 | 44 | message StateTransferRequestMessage { 45 | required uint64 sessnum = 1; 46 | required uint64 view = 2; 47 | required uint64 begin = 3; 48 | required uint64 end = 4; 49 | } 50 | 51 | message StateTransferReplyMessage { 52 | required uint64 sessnum = 1; 53 | required uint64 view = 2; 54 | required uint64 begin = 3; 55 | required uint64 end = 4; 56 | repeated specpaxos.MsgLogEntry entries = 5; 57 | } 58 | 59 | message GapCommitMessage { 60 | required uint64 sessnum = 1; 61 | required uint64 view = 2; 62 | required uint64 opnum = 3; 63 | } 64 | 65 | message GapCommitReplyMessage { 66 | required uint64 sessnum = 1; 67 | required uint64 view = 2; 68 | required uint64 opnum = 3; 69 | required uint32 replicaidx = 4; 70 | } 71 | 72 | message ViewChangeRequestMessage { 73 | required uint64 sessnum = 1; 74 | required uint64 view = 2; 75 | } 76 | 77 | message ViewChangeMessage { 78 | required uint64 sessnum = 1; 79 | required uint64 view = 2; 80 | required uint64 lastnormalsessnum = 3; 81 | required uint64 lastnormalview = 4; 82 | required uint64 lastop = 5; 83 | repeated uint64 committedgaps = 6; 84 | required uint32 replicaidx = 7; 85 | } 86 | 87 | message StartViewMessage { 88 | required uint64 sessnum = 1; 89 | required uint64 view = 2; 90 | required uint64 lastnormalsessnum = 3; 91 | required uint64 lastnormalview = 4; 92 | required uint64 lastop = 5; 93 | repeated uint64 committedgaps = 6; 94 | } 95 | 96 | message StartViewReplyMessage { 97 | required uint64 sessnum = 1; 98 | required uint64 view = 2; 99 | required uint32 replicaidx = 3; 100 | } 101 | 102 | message SyncPrepareRequestMessage { 103 | required uint64 sessnum = 1; 104 | required uint64 view = 2; 105 | } 106 | 107 | message SyncPrepareMessage { 108 | required uint64 sessnum = 1; 109 | required uint64 view = 2; 110 | required uint64 lastop = 3; 111 | repeated uint64 committedgaps = 4; 112 | } 113 | 114 | message SyncPrepareReplyMessage { 115 | required uint64 sessnum = 1; 116 | required uint64 view = 2; 117 | required uint64 syncpoint = 3; 118 | required uint32 replicaidx = 4; 119 | } 120 | 121 | message SyncCommitMessage { 122 | required uint64 sessnum = 1; 123 | required uint64 view = 2; 124 | required uint64 syncpoint = 3; 125 | } 126 | -------------------------------------------------------------------------------- /common/log-impl.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * log.h: 5 | * a replica's log of pending and committed operations 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Jialin Li 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _COMMON_LOG_IMPL_H_ 33 | #define _COMMON_LOG_IMPL_H_ 34 | 35 | template void 36 | Log::Dump(opnum_t from, T out) 37 | { 38 | Dump(from, LastOpnum()+1, out); 39 | } 40 | 41 | template void 42 | Log::Dump(opnum_t from, opnum_t to, T out) 43 | { 44 | ASSERT(to <= LastOpnum()+1); 45 | for (opnum_t i = std::max(from, start); i < to; i++) { 46 | 47 | const LogEntry *entry = Find(i); 48 | ASSERT(entry != NULL); 49 | 50 | auto elem = out->Add(); 51 | elem->set_view(entry->viewstamp.view); 52 | elem->set_opnum(entry->viewstamp.opnum); 53 | elem->set_sessnum(entry->viewstamp.sessnum); 54 | elem->set_msgnum(entry->viewstamp.msgnum); 55 | elem->set_shardnum(entry->viewstamp.shardnum); 56 | elem->set_state(entry->state); 57 | elem->set_hash(entry->hash); 58 | *(elem->mutable_request()) = entry->request; 59 | } 60 | } 61 | 62 | template void 63 | Log::Install(iter start, iter end) 64 | { 65 | // Find the first divergence in the log 66 | iter it = start; 67 | for (it = start; it != end; it++) { 68 | const LogEntry *oldEntry = Find(it->opnum()); 69 | if (oldEntry == NULL) { 70 | break; 71 | } 72 | if (it->view() != oldEntry->viewstamp.view) { 73 | RemoveAfter(it->opnum()); 74 | break; 75 | } 76 | } 77 | 78 | if (it == end) { 79 | // We didn't find a divergence. This means that the logs 80 | // should be identical. If the existing log is longer, 81 | // something is wrong. 82 | // it--; 83 | // ASSERT(it->opnum() == lastViewstamp.opnum); 84 | // ASSERT(it->view() == lastViewstamp.view); 85 | // ASSERT(Find(it->opnum()+1) == NULL); 86 | } 87 | 88 | // Install the new log entries 89 | for (; it != end; it++) { 90 | viewstamp_t vs = { it->view(), it->opnum() }; 91 | Append(vs, it->request(), LOG_STATE_PREPARED); 92 | } 93 | } 94 | 95 | #endif /* _COMMON_LOG_IMPL_H_ */ 96 | -------------------------------------------------------------------------------- /common/client.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * client.h: 5 | * interface to replication client stubs 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _COMMON_CLIENT_H_ 32 | #define _COMMON_CLIENT_H_ 33 | 34 | #include "lib/configuration.h" 35 | #include "common/request.pb.h" 36 | #include "lib/transport.h" 37 | //#include "store/common/transaction.h" 38 | #include 39 | #include 40 | 41 | 42 | #include 43 | 44 | namespace specpaxos { 45 | 46 | class Client : public TransportReceiver 47 | { 48 | public: 49 | typedef std::function continuation_t; 50 | typedef std::function &, 51 | const std::map &, 52 | bool)> g_continuation_t; 53 | typedef std::function timeout_continuation_t; 54 | // currently do not have group version of timeout_continuation_t 55 | 56 | static const uint32_t DEFAULT_UNLOGGED_OP_TIMEOUT = 1000; // milliseconds 57 | 58 | Client(const Configuration &config, Transport *transport, 59 | uint64_t clientid = 0); 60 | virtual ~Client(); 61 | virtual void Invoke(const string &request, 62 | continuation_t continuation) = 0; // Request goes to the default group (0) 63 | virtual void Invoke(const std::map &requests, 64 | g_continuation_t continuation, 65 | void *arg = nullptr); // Request goes to multiple groups 66 | virtual void InvokeUnlogged(int replicaIdx, 67 | const string &request, 68 | continuation_t continuation, 69 | timeout_continuation_t timeoutContinuation = nullptr, 70 | uint32_t timeout = DEFAULT_UNLOGGED_OP_TIMEOUT) = 0; 71 | virtual void ReceiveMessage(const TransportAddress &remote, 72 | const string &type, 73 | const string &data, 74 | void *meta_data) override; 75 | 76 | protected: 77 | Configuration config; 78 | Transport *transport; 79 | 80 | uint64_t clientid; 81 | }; 82 | 83 | } // namespace specpaxos 84 | 85 | #endif /* _COMMON_CLIENT_H_ */ 86 | -------------------------------------------------------------------------------- /unreplicated/client.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * unreplicated/client.h: 5 | * dummy implementation of replication interface that just uses a 6 | * single replica and passes commands directly to it 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _UNREPLICATED_CLIENT_H_ 33 | #define _UNREPLICATED_CLIENT_H_ 34 | 35 | #include "common/client.h" 36 | #include "lib/configuration.h" 37 | #include "unreplicated/unreplicated-proto.pb.h" 38 | 39 | namespace specpaxos { 40 | namespace unreplicated { 41 | 42 | class UnreplicatedClient : public Client 43 | { 44 | public: 45 | UnreplicatedClient(const Configuration &config, 46 | Transport *transport, 47 | uint64_t clientid = 0); 48 | virtual ~UnreplicatedClient(); 49 | virtual void Invoke(const string &request, continuation_t continuation) override; 50 | virtual void InvokeUnlogged(int replicaIdx, 51 | const string &request, 52 | continuation_t continuation, 53 | timeout_continuation_t timeoutContinuation = nullptr, 54 | uint32_t timeout = DEFAULT_UNLOGGED_OP_TIMEOUT) override; 55 | virtual void ReceiveMessage(const TransportAddress &remote, 56 | const string &type, const string &data, 57 | void *meta_data) override; 58 | 59 | protected: 60 | struct PendingRequest 61 | { 62 | string request; 63 | uint64_t clientid; 64 | uint64_t clientreqid; 65 | continuation_t continuation; 66 | inline PendingRequest(string request, uint64_t clientreqid, continuation_t continuation) 67 | : request(request), clientreqid(clientreqid), continuation(continuation) { } 68 | }; 69 | PendingRequest *pendingRequest; 70 | PendingRequest *pendingUnloggedRequest; 71 | Timeout *requestTimeout; 72 | uint64_t lastReqId; 73 | 74 | void HandleReply(const TransportAddress &remote, 75 | const proto::ReplyMessage &msg); 76 | void HandleUnloggedReply(const TransportAddress &remote, 77 | const proto::UnloggedReplyMessage &msg); 78 | void SendRequest(); 79 | void ResendRequest(); 80 | }; 81 | 82 | } // namespace specpaxos::unreplicated 83 | } // namespace specpaxos 84 | 85 | #endif /* _UNREPLICATED_CLIENT_H_ */ 86 | -------------------------------------------------------------------------------- /lib/viewstamp.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * viewstamp.h: 5 | * definition of types and utility functions for viewstamps and 6 | * related types 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_VIEWSTAMP_H_ 33 | #define _LIB_VIEWSTAMP_H_ 34 | 35 | #define __STDC_FORMAT_MACROS 36 | #include 37 | 38 | typedef uint64_t view_t; 39 | typedef uint64_t opnum_t; 40 | typedef uint64_t sessnum_t; 41 | typedef uint64_t msgnum_t; 42 | typedef uint32_t shardnum_t; 43 | 44 | struct viewstamp_t 45 | { 46 | view_t view; 47 | opnum_t opnum; 48 | sessnum_t sessnum; 49 | msgnum_t msgnum; 50 | shardnum_t shardnum; 51 | 52 | viewstamp_t() : view(0), opnum(0), sessnum(0), msgnum(0), shardnum(0) {} 53 | viewstamp_t(view_t view, 54 | opnum_t opnum, 55 | sessnum_t sessnum=0, 56 | msgnum_t msgnum=0, 57 | shardnum_t shardnum=0) 58 | : view(view), opnum(opnum), sessnum(sessnum), msgnum(msgnum), shardnum(shardnum) {} 59 | }; 60 | 61 | #define FMT_VIEW "%" PRIu64 62 | #define FMT_OPNUM "%" PRIu64 63 | 64 | #define FMT_VIEWSTAMP "<" FMT_VIEW "," FMT_OPNUM ">" 65 | #define VA_VIEWSTAMP(x) x.view, x.opnum 66 | 67 | static inline int 68 | Viewstamp_Compare(viewstamp_t a, viewstamp_t b) 69 | { 70 | if (a.view < b.view) return -1; 71 | if (a.view > b.view) return 1; 72 | if (a.opnum < b.opnum) return -1; 73 | if (a.opnum > b.opnum) return 1; 74 | if (a.sessnum < b.sessnum) return -1; 75 | if (a.sessnum > b.sessnum) return 1; 76 | if (a.msgnum < b.msgnum) return -1; 77 | if (a.msgnum > b.msgnum) return 1; 78 | if (a.shardnum < b.shardnum) return -1; 79 | if (a.shardnum > b.shardnum) return 1; 80 | return 0; 81 | } 82 | 83 | inline bool operator==(const viewstamp_t& lhs, const viewstamp_t& rhs){ return Viewstamp_Compare(lhs,rhs) == 0; } 84 | inline bool operator!=(const viewstamp_t& lhs, const viewstamp_t& rhs){return !operator==(lhs,rhs);} 85 | inline bool operator< (const viewstamp_t& lhs, const viewstamp_t& rhs){ return Viewstamp_Compare(lhs,rhs) < 0; } 86 | inline bool operator> (const viewstamp_t& lhs, const viewstamp_t& rhs){return operator< (rhs,lhs);} 87 | inline bool operator<=(const viewstamp_t& lhs, const viewstamp_t& rhs){return !operator> (lhs,rhs);} 88 | inline bool operator>=(const viewstamp_t& lhs, const viewstamp_t& rhs){return !operator< (lhs,rhs);} 89 | 90 | #endif /* _LIB_VIEWSTAMP_H_ */ 91 | -------------------------------------------------------------------------------- /fastpaxos/client.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * fastpaxos/client.h: 5 | * Fast Paxos client 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _FASTPAXOS_CLIENT_H_ 32 | #define _FASTPAXOS_CLIENT_H_ 33 | 34 | #include "common/client.h" 35 | #include "lib/configuration.h" 36 | #include "fastpaxos/fastpaxos-proto.pb.h" 37 | 38 | namespace specpaxos { 39 | namespace fastpaxos { 40 | 41 | class FastPaxosClient : public Client 42 | { 43 | public: 44 | FastPaxosClient(const Configuration &config, 45 | Transport *transport, 46 | uint64_t clientid = 0); 47 | virtual ~FastPaxosClient(); 48 | virtual void Invoke(const string &request, 49 | continuation_t continuation); 50 | virtual void InvokeUnlogged(int replicaIdx, 51 | const string &request, 52 | continuation_t continuation, 53 | timeout_continuation_t timeoutContinuation = nullptr, 54 | uint32_t timeout = DEFAULT_UNLOGGED_OP_TIMEOUT); 55 | virtual void ReceiveMessage(const TransportAddress &remote, 56 | const string &type, const string &data, 57 | void *meta_data); 58 | 59 | protected: 60 | int view; 61 | int opnumber; 62 | uint64_t lastReqId; 63 | 64 | struct PendingRequest 65 | { 66 | string request; 67 | uint64_t clientReqId; 68 | continuation_t continuation; 69 | timeout_continuation_t timeoutContinuation; 70 | inline PendingRequest(string request, uint64_t clientReqId, 71 | continuation_t continuation) 72 | : request(request), clientReqId(clientReqId), 73 | continuation(continuation) { } 74 | }; 75 | PendingRequest *pendingRequest; 76 | PendingRequest *pendingUnloggedRequest; 77 | Timeout *requestTimeout; 78 | Timeout *unloggedRequestTimeout; 79 | 80 | void SendRequest(); 81 | void ResendRequest(); 82 | void HandleReply(const TransportAddress &remote, 83 | const proto::ReplyMessage &msg); 84 | void HandleUnloggedReply(const TransportAddress &remote, 85 | const proto::UnloggedReplyMessage &msg); 86 | void UnloggedRequestTimeoutCallback(); 87 | }; 88 | 89 | } // namespace specpaxos::fastpaxos 90 | } // namespace specpaxos 91 | 92 | #endif /* _FASTPAXOS_CLIENT_H_ */ 93 | -------------------------------------------------------------------------------- /vr/client.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * vr/client.h: 5 | * dummy implementation of replication interface that just uses a 6 | * single replica and passes commands directly to it 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _VR_CLIENT_H_ 33 | #define _VR_CLIENT_H_ 34 | 35 | #include "common/client.h" 36 | #include "lib/configuration.h" 37 | #include "vr/vr-proto.pb.h" 38 | 39 | namespace specpaxos { 40 | namespace vr { 41 | 42 | class VRClient : public Client 43 | { 44 | public: 45 | VRClient(const Configuration &config, 46 | Transport *transport, 47 | uint64_t clientid = 0); 48 | virtual ~VRClient(); 49 | virtual void Invoke(const string &request, 50 | continuation_t continuation) override; 51 | virtual void InvokeUnlogged(int replicaIdx, 52 | const string &request, 53 | continuation_t continuation, 54 | timeout_continuation_t timeoutContinuation = nullptr, 55 | uint32_t timeout = DEFAULT_UNLOGGED_OP_TIMEOUT) override; 56 | virtual void ReceiveMessage(const TransportAddress &remote, 57 | const string &type, const string &data, 58 | void *meta_data) override; 59 | 60 | protected: 61 | int view; 62 | int opnumber; 63 | uint64_t lastReqId; 64 | 65 | struct PendingRequest 66 | { 67 | string request; 68 | uint64_t clientReqId; 69 | continuation_t continuation; 70 | timeout_continuation_t timeoutContinuation; 71 | inline PendingRequest(string request, uint64_t clientReqId, 72 | continuation_t continuation) 73 | : request(request), clientReqId(clientReqId), 74 | continuation(continuation) { } 75 | }; 76 | PendingRequest *pendingRequest; 77 | PendingRequest *pendingUnloggedRequest; 78 | Timeout *requestTimeout; 79 | Timeout *unloggedRequestTimeout; 80 | 81 | void SendRequest(); 82 | void ResendRequest(); 83 | void HandleReply(const TransportAddress &remote, 84 | const proto::ReplyMessage &msg); 85 | void HandleUnloggedReply(const TransportAddress &remote, 86 | const proto::UnloggedReplyMessage &msg); 87 | void UnloggedRequestTimeoutCallback(); 88 | }; 89 | 90 | } // namespace specpaxos::vr 91 | } // namespace specpaxos 92 | 93 | #endif /* _VR_CLIENT_H_ */ 94 | -------------------------------------------------------------------------------- /common/quorumset.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * quorumset.h: 5 | * utility type for tracking sets of messages received from other 6 | * replicas and determining whether a quorum of responses has been met 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _COMMON_QUORUMSET_H_ 33 | #define _COMMON_QUORUMSET_H_ 34 | 35 | namespace specpaxos { 36 | 37 | template 38 | class QuorumSet 39 | { 40 | public: 41 | QuorumSet(int numRequired) 42 | : numRequired(numRequired) 43 | { 44 | 45 | } 46 | 47 | void 48 | Clear() 49 | { 50 | messages.clear(); 51 | } 52 | 53 | void 54 | Clear(IDTYPE vs) 55 | { 56 | std::map &vsmessages = messages[vs]; 57 | vsmessages.clear(); 58 | } 59 | 60 | int 61 | NumRequired() const 62 | { 63 | return numRequired; 64 | } 65 | 66 | const std::map & 67 | GetMessages(IDTYPE vs) 68 | { 69 | return messages[vs]; 70 | } 71 | 72 | const std::map * 73 | CheckForQuorum(IDTYPE vs) 74 | { 75 | std::map &vsmessages = messages[vs]; 76 | int count = vsmessages.size(); 77 | if (count >= numRequired) { 78 | return &vsmessages; 79 | } else { 80 | return NULL; 81 | } 82 | } 83 | 84 | const std::map * 85 | AddAndCheckForQuorum(IDTYPE vs, int replicaIdx, const MSGTYPE &msg) 86 | { 87 | std::map &vsmessages = messages[vs]; 88 | if (vsmessages.find(replicaIdx) != vsmessages.end()) { 89 | // This is a duplicate message 90 | 91 | // But we'll ignore that, replace the old message from 92 | // this replica, and proceed. 93 | // 94 | // XXX Is this the right thing to do? It is for 95 | // speculative replies in SpecPaxos... 96 | } 97 | 98 | vsmessages[replicaIdx] = msg; 99 | 100 | return CheckForQuorum(vs); 101 | } 102 | 103 | void 104 | Add(IDTYPE vs, int replicaIdx, const MSGTYPE &msg) 105 | { 106 | AddAndCheckForQuorum(vs, replicaIdx, msg); 107 | } 108 | 109 | public: 110 | int numRequired; 111 | private: 112 | std::map > messages; 113 | }; 114 | 115 | } // namespace specpaxos 116 | 117 | #endif // _COMMON_QUORUMSET_H_ 118 | -------------------------------------------------------------------------------- /ctpl/example.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | 7 | void first(int id) { 8 | std::cout << "hello from " << id << ", function\n"; 9 | } 10 | 11 | void aga(int id, int par) { 12 | std::cout << "hello from " << id << ", function with parameter " << par <<'\n'; 13 | } 14 | 15 | struct Third { 16 | Third(int v) { this->v = v; std::cout << "Third ctor " << this->v << '\n'; } 17 | Third(Third && c) { this->v = c.v; std::cout<<"Third move ctor\n"; } 18 | Third(const Third & c) { this->v = c.v; std::cout<<"Third copy ctor\n"; } 19 | ~Third() { std::cout << "Third dtor\n"; } 20 | int v; 21 | }; 22 | 23 | void mmm(int id, const std::string & s) { 24 | std::cout << "mmm function " << id << ' ' << s << '\n'; 25 | } 26 | 27 | void ugu(int id, Third & t) { 28 | std::this_thread::sleep_for(std::chrono::milliseconds(2000)); 29 | std::cout << "hello from " << id << ", function with parameter Third " << t.v <<'\n'; 30 | } 31 | 32 | int main(int argc, char **argv) { 33 | ctpl::thread_pool p(2 /* two threads in the pool */); 34 | 35 | std::future qw = p.push(std::ref(first)); // function 36 | p.push(first); // function 37 | p.push(aga, 7); // function 38 | 39 | { 40 | struct Second { 41 | Second(const std::string & s) { std::cout << "Second ctor\n"; this->s = s; } 42 | Second(Second && c) { std::cout << "Second move ctor\n"; s = std::move(c.s); } 43 | Second(const Second & c) { std::cout << "Second copy ctor\n"; this->s = c.s; }; 44 | ~Second() { std::cout << "Second dtor\n"; } 45 | void operator()(int id) const { 46 | std::cout << "hello from " << id << ' ' << this->s << '\n'; 47 | } 48 | private: 49 | std::string s; 50 | } second(", functor"); 51 | 52 | p.push(std::ref(second)); // functor, reference 53 | std::this_thread::sleep_for(std::chrono::milliseconds(2000)); 54 | p.push(const_cast(second)); // functor, copy ctor 55 | p.push(std::move(second)); // functor, move ctor 56 | p.push(second); // functor, move ctor 57 | p.push(Second(", functor")); // functor, move ctor 58 | } 59 | { 60 | Third t(100); 61 | 62 | p.push(ugu, std::ref(t)); // function. reference 63 | p.push(ugu, t); // function. copy ctor, move ctor 64 | p.push(ugu, std::move(t)); // function. move ctor, move ctor 65 | 66 | } 67 | p.push(ugu, Third(200)); // function 68 | 69 | 70 | 71 | std::string s = ", lambda"; 72 | p.push([s](int id){ // lambda 73 | std::this_thread::sleep_for(std::chrono::milliseconds(2000)); 74 | std::cout << "hello from " << id << ' ' << s << '\n'; 75 | }); 76 | 77 | p.push([s](int id){ // lambda 78 | std::this_thread::sleep_for(std::chrono::milliseconds(2000)); 79 | std::cout << "hello from " << id << ' ' << s << '\n'; 80 | }); 81 | 82 | p.push(mmm, "worked"); 83 | 84 | auto f = p.pop(); 85 | if (f) { 86 | std::cout << "poped function from the pool "; 87 | f(0); 88 | } 89 | // change the number of treads in the pool 90 | 91 | p.resize(1); 92 | 93 | std::string s2 = "result"; 94 | auto f1 = p.push([s2](int){ 95 | return s2; 96 | }); 97 | // other code here 98 | //... 99 | std::cout << "returned " << f1.get() << '\n'; 100 | 101 | auto f2 = p.push([](int){ 102 | throw std::exception(); 103 | }); 104 | // other code here 105 | //... 106 | try { 107 | f2.get(); 108 | } 109 | catch (std::exception & e) { 110 | std::cout << "caught exception\n"; 111 | } 112 | 113 | // get thread 0 114 | auto & th = p.get_thread(0); 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /spec/client.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * spec/client.h: 5 | * Speculative Paxos client 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _SPEC_CLIENT_H_ 32 | #define _SPEC_CLIENT_H_ 33 | 34 | #include "common/client.h" 35 | #include "lib/configuration.h" 36 | #include "common/quorumset.h" 37 | #include "spec/spec-proto.pb.h" 38 | 39 | namespace specpaxos { 40 | namespace spec { 41 | 42 | class SpecClient : public Client 43 | { 44 | public: 45 | SpecClient(const Configuration &config, 46 | Transport *transport, 47 | uint64_t clientid = 0); 48 | virtual ~SpecClient(); 49 | virtual void Invoke(const string &request, 50 | continuation_t continuation); 51 | virtual void InvokeUnlogged(int replicaIdx, 52 | const string &request, 53 | continuation_t continuation, 54 | timeout_continuation_t timeoutContinuation = nullptr, 55 | uint32_t timeout = DEFAULT_UNLOGGED_OP_TIMEOUT); 56 | virtual void ReceiveMessage(const TransportAddress &remote, 57 | const string &type, const string &data, 58 | void *meta_data); 59 | 60 | protected: 61 | view_t view; 62 | opnum_t opnum; 63 | uint64_t lastReqId; 64 | 65 | struct PendingRequest 66 | { 67 | string request; 68 | uint64_t clientReqId; 69 | continuation_t continuation; 70 | timeout_continuation_t timeoutContinuation; 71 | inline PendingRequest(string request, uint64_t clientReqId, 72 | continuation_t continuation) 73 | : request(request), clientReqId(clientReqId), 74 | continuation(continuation) { } 75 | }; 76 | PendingRequest *pendingRequest; 77 | PendingRequest *pendingUnloggedRequest; 78 | Timeout *requestTimeout; 79 | Timeout *unloggedRequestTimeout; 80 | QuorumSet speculativeReplyQuorum; 81 | 82 | void SendRequest(); 83 | void ResendRequest(); 84 | void CompleteOperation(const proto::SpeculativeReplyMessage &msg); 85 | void HandleReply(const TransportAddress &remote, 86 | const proto::SpeculativeReplyMessage &msg); 87 | void HandleUnloggedReply(const TransportAddress &remote, 88 | const proto::UnloggedReplyMessage &msg); 89 | void UnloggedRequestTimeoutCallback(); 90 | }; 91 | 92 | } // namespace specpaxos::spec 93 | } // namespace specpaxos 94 | 95 | #endif /* _SPEC_CLIENT_H_ */ 96 | -------------------------------------------------------------------------------- /nopaxos/client.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * nopaxos/client.h: 5 | * Network Ordered Paxos client implementation 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Jialin Li 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _NOPAXOS_CLIENT_H_ 33 | #define _NOPAXOS_CLIENT_H_ 34 | 35 | #include "common/client.h" 36 | #include "common/quorumset.h" 37 | #include "lib/configuration.h" 38 | #include "nopaxos/nopaxos-proto.pb.h" 39 | 40 | namespace specpaxos { 41 | namespace nopaxos { 42 | 43 | class NOPaxosClient : public Client 44 | { 45 | public: 46 | NOPaxosClient(const Configuration &config, 47 | Transport *transport, 48 | uint64_t clientid = 0); 49 | ~NOPaxosClient(); 50 | void Invoke(const string &request, 51 | continuation_t continuation) override; 52 | void InvokeUnlogged(int replicaIdx, 53 | const string &request, 54 | continuation_t continuation, 55 | timeout_continuation_t timeoutContinuation = nullptr, 56 | uint32_t timeout = DEFAULT_UNLOGGED_OP_TIMEOUT) override; 57 | void ReceiveMessage(const TransportAddress &remote, 58 | const string &type, 59 | const string &data, 60 | void *meta_data) override; 61 | 62 | private: 63 | opnum_t lastReqID; 64 | 65 | struct PendingRequest 66 | { 67 | string request; 68 | opnum_t clientReqID; 69 | continuation_t continuation; 70 | timeout_continuation_t timeoutContinuation; 71 | inline PendingRequest(string request, opnum_t clientReqID, 72 | continuation_t continuation) 73 | : request(request), clientReqID(clientReqID), 74 | continuation(continuation) { } 75 | }; 76 | PendingRequest *pendingRequest; 77 | PendingRequest *pendingUnloggedRequest; 78 | Timeout *requestTimeout; 79 | Timeout *unloggedRequestTimeout; 80 | QuorumSet replyQuorum; 81 | 82 | void SendRequest(); 83 | void ResendRequest(); 84 | void CompleteOperation(const proto::ReplyMessage &msg); 85 | void HandleReply(const TransportAddress &remote, 86 | const proto::ReplyMessage &msg); 87 | void HandleUnloggedReply(const TransportAddress &remote, 88 | const proto::UnloggedReplyMessage &msg); 89 | void UnloggedRequestTimeoutCallback(); 90 | bool IsLeader(view_t view, int replicaIdx); 91 | }; 92 | 93 | } // namespace specpaxos::nopaxos 94 | } // namespace specpaxos 95 | 96 | #endif /* _NOPAXOS_CLIENT_H_ */ 97 | -------------------------------------------------------------------------------- /common/replica.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * replica.h: 5 | * common interface to different replication protocols 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _COMMON_REPLICA_H_ 32 | #define _COMMON_REPLICA_H_ 33 | 34 | 35 | #include "lib/configuration.h" 36 | #include "common/log.h" 37 | #include "common/request.pb.h" 38 | #include "lib/transport.h" 39 | #include "lib/viewstamp.h" 40 | #include "lib/workertasks.h" 41 | 42 | namespace specpaxos { 43 | 44 | class Replica; 45 | 46 | enum ReplicaStatus { 47 | STATUS_NORMAL, 48 | STATUS_VIEW_CHANGE, 49 | STATUS_RECOVERING, 50 | STATUS_GAP_COMMIT 51 | }; 52 | 53 | class AppReplica 54 | { 55 | public: 56 | AppReplica() { }; 57 | virtual ~AppReplica() { }; 58 | // Invoke callback on the leader, with the option to replicate on success 59 | virtual void LeaderUpcall(opnum_t opnum, const string &str1, bool &replicate, string &str2) { replicate = true; str2 = str1; }; 60 | // Invoke callback on all replicas 61 | virtual void ReplicaUpcall(opnum_t opnum, const string &str1, string &str2, 62 | void *arg = nullptr, void *ret = nullptr) { }; 63 | // Rollback callback on failed speculative operations 64 | virtual void RollbackUpcall(opnum_t current, opnum_t to, const std::map &opMap) { }; 65 | // Commit callback to commit speculative operations 66 | virtual void CommitUpcall(opnum_t) { }; 67 | // Invoke call back for unreplicated operations run on only one replica 68 | virtual void UnloggedUpcall(const string &str1, string &str2) { }; 69 | }; 70 | 71 | class Replica : public TransportReceiver 72 | { 73 | public: 74 | Replica(const Configuration &config, int groupIdx, int replicaIdx, 75 | bool initialize, Transport *transport, AppReplica *app); 76 | virtual ~Replica(); 77 | 78 | protected: 79 | void LeaderUpcall(opnum_t opnum, const string &op, bool &replicate, string &res); 80 | void ReplicaUpcall(opnum_t opnum, const string &op, string &res, 81 | void *arg = nullptr, void *ret = nullptr); 82 | template void Execute(opnum_t opnum, 83 | const Request & msg, 84 | MSG &reply, 85 | void *arg = nullptr, 86 | void *ret = nullptr); 87 | void Rollback(opnum_t current, opnum_t to, Log &log); 88 | void Commit(opnum_t op); 89 | void UnloggedUpcall(const string &op, string &res); 90 | template void ExecuteUnlogged(const UnloggedRequest & msg, 91 | MSG &reply); 92 | 93 | protected: 94 | Configuration configuration; 95 | int groupIdx; 96 | int replicaIdx; 97 | Transport *transport; 98 | AppReplica *app; 99 | ReplicaStatus status; 100 | }; 101 | 102 | #include "replica-inl.h" 103 | 104 | } // namespace specpaxos 105 | 106 | #endif /* _COMMON_REPLICA_H */ 107 | -------------------------------------------------------------------------------- /unreplicated/tests/unreplicated-test.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * unreplicated-test.cc: 5 | * test cases for unreplicated protocol 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "lib/configuration.h" 32 | #include "common/client.h" 33 | #include "common/replica.h" 34 | #include "lib/transport.h" 35 | #include "lib/simtransport.h" 36 | #include "unreplicated/client.h" 37 | #include "unreplicated/replica.h" 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | using namespace specpaxos; 44 | using namespace specpaxos::unreplicated; 45 | using namespace specpaxos::unreplicated::proto; 46 | using std::map; 47 | using std::vector; 48 | 49 | static string replicaLastOp; 50 | static string clientLastOp; 51 | static string clientLastReply; 52 | static string replicaLastUnloggedOp; 53 | 54 | class UnrepTestApp : public AppReplica { 55 | public: 56 | UnrepTestApp() { }; 57 | ~UnrepTestApp() { }; 58 | 59 | void ReplicaUpcall(opnum_t opnum, const string &req, string &reply, 60 | void *arg = nullptr, void *ret = nullptr) override { 61 | replicaLastOp = req; 62 | reply = "reply: " + req; 63 | } 64 | 65 | void UnloggedUpcall(const string &req, string &reply) { 66 | replicaLastUnloggedOp = req; 67 | reply = "unlreply: " + req; 68 | } 69 | }; 70 | 71 | static void ClientUpcallHandler(const string &req, const string &reply) 72 | { 73 | clientLastOp = req; 74 | clientLastReply = reply; 75 | } 76 | 77 | 78 | TEST(Unreplicated, OneOp) 79 | { 80 | map > replicaAddrs = 81 | { {0, { 82 | { "localhost", "12345" } 83 | } 84 | } }; 85 | Configuration c(1, 1, 0, replicaAddrs); 86 | 87 | SimulatedTransport transport; 88 | 89 | UnrepTestApp app; 90 | 91 | UnreplicatedReplica replica(c, 0, true, &transport, &app); 92 | UnreplicatedClient client(c, &transport); 93 | 94 | client.Invoke(string("test"), ClientUpcallHandler); 95 | 96 | transport.Run(); 97 | 98 | EXPECT_EQ(replicaLastOp, "test"); 99 | EXPECT_EQ(clientLastOp, "test"); 100 | EXPECT_EQ(clientLastReply, "reply: test"); 101 | EXPECT_EQ(replicaLastUnloggedOp, ""); 102 | } 103 | 104 | TEST(Unreplicated, Unlogged) 105 | { 106 | map > replicaAddrs = 107 | { {0, { 108 | { "localhost", "12345" } 109 | } 110 | } }; 111 | Configuration c(1, 1, 0, replicaAddrs); 112 | 113 | SimulatedTransport transport; 114 | UnrepTestApp app; 115 | 116 | UnreplicatedReplica replica(c, 0, true, &transport, &app); 117 | UnreplicatedClient client(c, &transport); 118 | 119 | client.InvokeUnlogged(0, string("test2"), ClientUpcallHandler); 120 | 121 | transport.Run(); 122 | 123 | EXPECT_EQ(replicaLastOp, "test"); 124 | EXPECT_EQ(replicaLastUnloggedOp, "test2"); 125 | EXPECT_EQ(clientLastOp, "test2"); 126 | EXPECT_EQ(clientLastReply, "unlreply: test2"); 127 | } 128 | -------------------------------------------------------------------------------- /common/messageset.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * messageset.h: 5 | * utility type for tracking sets of messages received 6 | * 7 | * Copyright 2016 Dan R. K. Ports 8 | * Jialin Li 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _COMMON_MESSAGESET_H_ 33 | #define _COMMON_MESSAGESET_H_ 34 | 35 | #include 36 | #include 37 | 38 | namespace specpaxos { 39 | 40 | template 41 | class MessageSet 42 | { 43 | public: 44 | MessageSet(uint32_t replicaRequired) 45 | : replicaRequired(replicaRequired) 46 | { 47 | 48 | } 49 | 50 | void 51 | Clear() 52 | { 53 | messages.clear(); 54 | } 55 | 56 | void 57 | Clear(IDTYPE vs) 58 | { 59 | if (messages.find(vs) == messages.end()) { 60 | return; 61 | } 62 | std::map > &vsmessages = messages[vs].first; 63 | vsmessages.clear(); 64 | } 65 | 66 | void 67 | Remove(IDTYPE vs) 68 | { 69 | messages.erase(vs); 70 | } 71 | 72 | int 73 | ReplicaRequied() const 74 | { 75 | return replicaRequired; 76 | } 77 | 78 | const std::map > * 79 | GetMessages(IDTYPE vs) 80 | { 81 | if (messages.find(vs) == messages.end()) { 82 | return NULL; 83 | } 84 | return &(messages[vs].first); 85 | } 86 | 87 | const std::map > * 88 | CheckForQuorum(IDTYPE vs) 89 | { 90 | if (messages.find(vs) == messages.end()) { 91 | return NULL; 92 | } 93 | 94 | std::map > &vsmessages = messages[vs].first; 95 | if (vsmessages.size() >= messages[vs].second) { 96 | for (auto &replicas : vsmessages) { 97 | if (replicas.second.size() < replicaRequired) { 98 | return NULL; 99 | } 100 | } 101 | return &vsmessages; 102 | } else { 103 | return NULL; 104 | } 105 | } 106 | 107 | const std::map > * 108 | AddAndCheckForQuorum(IDTYPE vs, int shard, 109 | int replica, const MSGTYPE &msg) 110 | { 111 | if (messages.find(vs) == messages.end()) { 112 | return NULL; 113 | } 114 | 115 | std::map > &vsmessages = messages[vs].first; 116 | 117 | (vsmessages[shard])[replica] = msg; 118 | 119 | return CheckForQuorum(vs); 120 | } 121 | 122 | void 123 | Add(IDTYPE vs, int shard, int replica, const MSGTYPE &msg) 124 | { 125 | AddAndCheckForQuorum(vs, shard, replica, msg); 126 | } 127 | 128 | void 129 | SetShardRequired(IDTYPE vs, uint32_t num) 130 | { 131 | messages[vs].second = num; 132 | } 133 | 134 | public: 135 | uint32_t replicaRequired; 136 | private: 137 | std::map >, uint32_t> > messages; 138 | }; 139 | 140 | } // namespace specpaxos 141 | 142 | #endif // _COMMON_MESSAGESET_H_ 143 | -------------------------------------------------------------------------------- /lib/configuration.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * configuration.h: 5 | * Representation of a replica group configuration, i.e. the number 6 | * and list of replicas in the group 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_CONFIGURATION_H_ 33 | #define _LIB_CONFIGURATION_H_ 34 | 35 | #include "lib/viewstamp.h" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | using std::string; 44 | 45 | namespace specpaxos { 46 | 47 | struct ReplicaAddress 48 | { 49 | string host; 50 | string port; 51 | ReplicaAddress(const string &host, const string &port); 52 | bool operator==(const ReplicaAddress &other) const; 53 | inline bool operator!=(const ReplicaAddress &other) const { 54 | return !(*this == other); 55 | } 56 | }; 57 | 58 | class Configuration 59 | { 60 | public: 61 | Configuration(const Configuration &c); 62 | Configuration(int g, int n, int f, 63 | std::map > replicas, 64 | ReplicaAddress *multicastAddress = nullptr, 65 | ReplicaAddress *fcAddress = nullptr); 66 | Configuration(std::ifstream &file); 67 | virtual ~Configuration(); 68 | ReplicaAddress replica(int group, int idx) const; 69 | const ReplicaAddress *multicast() const; 70 | const ReplicaAddress *fc() const; 71 | inline int GetLeaderIndex(view_t view) const { 72 | return (view % n); 73 | }; 74 | int QuorumSize() const; 75 | int FastQuorumSize() const; 76 | bool operator==(const Configuration &other) const; 77 | inline bool operator!= (const Configuration &other) const { 78 | return !(*this == other); 79 | } 80 | 81 | public: 82 | int g; // number of groups 83 | int n; // number of replicas per group 84 | int f; // number of failures tolerated (assume homogeneous across groups) 85 | private: 86 | std::map > replicas; 87 | ReplicaAddress *multicastAddress; 88 | bool hasMulticast; 89 | ReplicaAddress *fcAddress; 90 | bool hasFC; 91 | }; 92 | 93 | } // namespace specpaxos 94 | 95 | namespace std { 96 | template <> struct hash 97 | { 98 | size_t operator()(const specpaxos::ReplicaAddress & x) const 99 | { 100 | return hash()(x.host) * 37 + hash()(x.port); 101 | } 102 | }; 103 | } 104 | 105 | namespace std { 106 | template <> struct hash 107 | { 108 | size_t operator()(const specpaxos::Configuration & x) const 109 | { 110 | size_t out = 0; 111 | out = x.n * 37 + x.f; 112 | for (int i = 0; i < x.g; i++ ) { 113 | for (int j = 0; j < x.n; j++) { 114 | out *= 37; 115 | out += hash()(x.replica(i, j)); 116 | } 117 | } 118 | return out; 119 | } 120 | }; 121 | } 122 | 123 | 124 | #endif /* _LIB_CONFIGURATION_H_ */ 125 | -------------------------------------------------------------------------------- /fastpaxos/replica.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * fastpaxos/replica.h: 5 | * Fast Paxos protocol 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _FASTPAXOS_REPLICA_H_ 32 | #define _FASTPAXOS_REPLICA_H_ 33 | 34 | #include "lib/configuration.h" 35 | #include "common/log.h" 36 | #include "common/replica.h" 37 | #include "common/quorumset.h" 38 | #include "fastpaxos/fastpaxos-proto.pb.h" 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | namespace specpaxos { 45 | namespace fastpaxos { 46 | 47 | class FastPaxosReplica : public Replica 48 | { 49 | public: 50 | FastPaxosReplica(Configuration config, int myIdx, bool initialize, 51 | Transport *transport, AppReplica *app); 52 | ~FastPaxosReplica(); 53 | 54 | void ReceiveMessage(const TransportAddress &remote, 55 | const string &type, const string &data, 56 | void *meta_data) override; 57 | 58 | private: 59 | view_t view; 60 | opnum_t lastCommitted; 61 | opnum_t lastFastPath; 62 | opnum_t lastSlowPath; 63 | view_t lastRequestStateTransferView; 64 | opnum_t lastRequestStateTransferOpnum; 65 | std::list > pendingPrepares; 67 | std::list > pendingPrepareOKs; 69 | proto::PrepareMessage lastPrepare; 70 | 71 | Log log; 72 | std::map > clientAddresses; 73 | struct ClientTableEntry 74 | { 75 | uint64_t lastReqId; 76 | bool replied; 77 | proto::ReplyMessage reply; 78 | }; 79 | std::map clientTable; 80 | 81 | QuorumSet slowPrepareOKQuorum; 82 | QuorumSet fastPrepareOKQuorum; 83 | 84 | Timeout *stateTransferTimeout; 85 | Timeout *resendPrepareTimeout; 86 | 87 | bool AmLeader() const; 88 | void CommitUpTo(opnum_t upto); 89 | void SendPrepareOKs(opnum_t oldLastOp); 90 | void RequestStateTransfer(); 91 | void EnterView(view_t newview); 92 | void UpdateClientTable(const Request &req); 93 | void ResendPrepare(); 94 | 95 | void HandleRequest(const TransportAddress &remote, 96 | const proto::RequestMessage &msg); 97 | void HandleUnloggedRequest(const TransportAddress &remote, 98 | const proto::UnloggedRequestMessage &msg); 99 | 100 | void HandlePrepare(const TransportAddress &remote, 101 | const proto::PrepareMessage &msg); 102 | void HandlePrepareOK(const TransportAddress &remote, 103 | const proto::PrepareOKMessage &msg); 104 | void HandleCommit(const TransportAddress &remote, 105 | const proto::CommitMessage &msg); 106 | void HandleRequestStateTransfer(const TransportAddress &remote, 107 | const proto::RequestStateTransferMessage &msg); 108 | void HandleStateTransfer(const TransportAddress &remote, 109 | const proto::StateTransferMessage &msg); 110 | }; 111 | 112 | } // namespace specpaxos::vr 113 | } // namespace specpaxos 114 | 115 | #endif /* _FASTPAXOS_REPLICA_H_ */ 116 | -------------------------------------------------------------------------------- /lib/latency.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * latency.h: 5 | * latency profiling functions 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Copyright 2009-2012 Massachusetts Institute of Technology 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_LATENCY_H_ 33 | #define _LIB_LATENCY_H_ 34 | 35 | #include "lib/latency-format.pb.h" 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | // The number of the maximum distribution type. Since we use 44 | // characters as distribution types, this is 127. We could probably 45 | // shift things down by 32 to save some space, but that's probably not 46 | // worth anything. 47 | #define LATENCY_MAX_DIST 127 48 | 49 | // The maximum number of unique distribution types in a single latency 50 | // distribution. 51 | #define LATENCY_DIST_POOL_SIZE 5 52 | 53 | // The width of a printed histogram in characters. 54 | #define LATENCY_HISTOGRAM_WIDTH 50 55 | 56 | // The number of histogram buckets. 57 | #define LATENCY_NUM_BUCKETS 65 58 | 59 | typedef struct Latency_Frame_t 60 | { 61 | struct timespec start; 62 | uint64_t accum; 63 | struct Latency_Frame_t *parent; 64 | } Latency_Frame_t; 65 | 66 | typedef struct Latency_Dist_t 67 | { 68 | uint64_t min, max, total, count; 69 | uint32_t buckets[LATENCY_NUM_BUCKETS]; 70 | char type; 71 | } Latency_Dist_t; 72 | 73 | typedef struct Latency_t 74 | { 75 | const char *name; 76 | 77 | Latency_Dist_t *dists[LATENCY_MAX_DIST]; 78 | Latency_Dist_t distPool[LATENCY_DIST_POOL_SIZE]; 79 | int distPoolNext; 80 | 81 | Latency_Frame_t *bottom; 82 | Latency_Frame_t defaultFrame; 83 | 84 | struct Latency_t *next; 85 | } Latency_t; 86 | 87 | #define DEFINE_LATENCY(name) \ 88 | static Latency_t name; \ 89 | static __attribute__((constructor)) void _##name##_init(void) \ 90 | { \ 91 | _Latency_Init(&name, #name); \ 92 | } 93 | 94 | void _Latency_Init(Latency_t *l, const char *name); 95 | 96 | void Latency_StartRec(Latency_t *l, Latency_Frame_t *fr); 97 | uint64_t Latency_EndRecType(Latency_t *l, Latency_Frame_t *fr, char type); 98 | void Latency_Pause(Latency_t *l); 99 | void Latency_Resume(Latency_t *l); 100 | 101 | void Latency_Sum(Latency_t *dest, Latency_t *summand); 102 | 103 | void Latency_Dump(Latency_t *l); 104 | void Latency_DumpAll(void); 105 | void Latency_FlushTo(const char *fname); 106 | void Latency_Flush(void); 107 | 108 | void Latency_Put(Latency_t *l, 109 | ::specpaxos::latency::format::Latency &out); 110 | bool Latency_TryGet(const ::specpaxos::latency::format::Latency &in, 111 | Latency_t *l); 112 | 113 | static inline void 114 | Latency_Start(Latency_t *l) 115 | { 116 | Latency_StartRec(l, &l->defaultFrame); 117 | } 118 | 119 | static inline uint64_t 120 | Latency_EndRec(Latency_t *l, Latency_Frame_t *fr) 121 | { 122 | return Latency_EndRecType(l, fr, '='); 123 | } 124 | 125 | static inline uint64_t 126 | Latency_EndType(Latency_t *l, char type) 127 | { 128 | return Latency_EndRecType(l, &l->defaultFrame, type); 129 | } 130 | 131 | static inline uint64_t 132 | Latency_End(Latency_t *l) 133 | { 134 | return Latency_EndRec(l, &l->defaultFrame); 135 | } 136 | 137 | char *LatencyFmtNS(uint64_t ns, char *buf); 138 | 139 | 140 | #endif // _LIB_LATENCY_H_ 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Network-Ordered Paxos 2 | 3 | This is an implementation of the Network-Ordered Paxos (NOPaxos) protocol, as 4 | described in the paper 5 | ["Just Say NO to Paxos Overhead: Replacing Consensus with Network Ordering"](http://homes.cs.washington.edu/~lijl/papers/nopaxos-osdi16.pdf) 6 | from OSDI 2016. 7 | 8 | NOPaxos is a state machine replication protocol based on the 9 | idea of co-designing distributed systems with the datacenter 10 | network. NOPaxos divides replication responsibility between the 11 | network and protocol layers. The network orders requests but does 12 | not ensure reliable delivery -- using a new network primitive, 13 | Ordered Unreliable Multicast (OUM). The replication protocol exploits 14 | network ordering to provide strongly consistent replication without 15 | coordination. 16 | 17 | In normal case, NOPaxos avoids coordination entirely by relying on the 18 | network to deliver messages in the same order. It requires application-level 19 | coordination only to handle dropped packets. The resulting protocol is simple, 20 | achieving near-optimal throughput and latency, and remains robust to 21 | network-level failures. It not only outperforms both latency- and throughput-optimized protocols on their respective metrics, but also yields throughput within 2% and latency within 16 us of an unreplicated system -- providing replication without the performance cost. 22 | 23 | ## Contents 24 | 25 | This repository contains implementations of 5 replication protocols: 26 | 27 | 1. Network Ordered Paxos, including normal operation, gap agreement, 28 | view change, and synchronization protocols. 29 | 30 | 2. Speculative Paxos, including normal operation, synchronization, and 31 | reconciliation protocols. 32 | 33 | 3. Viewstamped Replication (VR), aka Multi-Paxos, as described in the 34 | paper 35 | ["Viewstamped Replication Revisited"](http://pmg.csail.mit.edu/papers/vr-revisited.pdf), 36 | including an optional batching optimization 37 | 38 | 4. Fast Paxos, although only the normal case is implemented. 39 | 40 | 5. A simple unreplicated RPC protocol for comparison 41 | 42 | ...as well as an endhost implementation of the sequencer. 43 | 44 | ## Building and Running 45 | 46 | NOPaxos and can be built using `make`. It has been tested on Ubuntu 14.04, 47 | 16.04 and Debian 8. Regression tests can be run with `make check` 48 | 49 | Dependencies include (Debian/Ubuntu packages): 50 | protobuf-compiler pkg-config libunwind-dev libssl-dev libprotobuf-dev libevent-dev libgtest-dev 51 | 52 | You will need to create a configuration file with the following 53 | syntax: 54 | 55 | ``` 56 | f 57 | replica : 58 | replica : 59 | ... 60 | multicast : 61 | ``` 62 | 63 | Multicast address is optional. However, the Ordered Unreliable Multicast (OUM) implementation 64 | uses the multicast address as the OUM group address. For testing, a reasonable option is to use the broadcast 65 | address as multicast address. 66 | 67 | In order to run NOPaxos, you need to configure the network to route OUM packets first to the 68 | sequencer, and then multicast to all OUM receivers. How this is implemented would depend on 69 | network design. The easiest way is to use OpenFlow and install rules that match on the multicast address. 70 | 71 | Our OUM implementation expects a custom header at the beginning of the UDP data, which contains 72 | the session number and message number described in the paper. If you need to write your own 73 | sequencer, please refer to `sequencer/sequencer.cc` for the custom header format. If you need to 74 | modify the header format, you will have to modify `ProcessPacket` and `DecodePacket` in 75 | `lib/udptransport.cc`. 76 | 77 | The endhost sequencer also requires a configuration file with the following syntax: 78 | 79 | ``` 80 | interface 81 | groupaddr 82 | ``` 83 | 84 | The endhost sequencer uses raw sockets, so you will need to provide the network interface name. `groupaddr` 85 | is the same as the multicast address used in the previous configuration. You can start the endhost 86 | sequencer with `sudo ./sequencer/sequencer -c ` (sudo is required 87 | because of the use of raw sockets) 88 | 89 | You can then start a replica with `./bench/replica -c -i -m `, where `mode` is either: 90 | - `nopaxos` for Network Ordered Paxos 91 | - `spec` for Speculative Paxos 92 | - `vr` for Viewstamped Replication 93 | - `fastpaxos` for Fast Paxos 94 | - `unreplicated` for no replication (uses only the first replica) 95 | 96 | The `vr` mode also accepts a `-b` option to specify the maximum batch 97 | size. 98 | 99 | To run a single client, use `./bench/client -c 100 | -m `. 101 | 102 | For performance measurements, you will likely want to add `-DNASSERT` 103 | and `-O2` to the `CFLAGS` in the Makefile, and run `make PARANOID=0`, 104 | which disables complexity-changing assertions. 105 | 106 | ## Contact 107 | 108 | NOPaxos is a product of the 109 | [UW Systems Lab](http://syslab.cs.washington.edu/). Please email Jialin 110 | Li at lijl@cs.washington.edu with any questions. 111 | -------------------------------------------------------------------------------- /lib/message.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * message.h: 5 | * logging functions 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Copyright 2009-2012 Massachusetts Institute of Technology 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_MESSAGE_H_ 33 | #define _LIB_MESSAGE_H_ 34 | 35 | #include 36 | #include 37 | #include 38 | 39 | enum Message_Type { 40 | MSG_PANIC = 0, 41 | MSG_WARNING, 42 | MSG_NOTICE, 43 | MSG_DEBUG, 44 | MSG_NUM_TYPES, 45 | MSG_PERROR = 1 << 16, 46 | }; 47 | 48 | #define PanicFlags(flags, msg...) \ 49 | do { \ 50 | _Message((Message_Type)(MSG_PANIC|flags), __FILE__, __LINE__, __func__, msg); \ 51 | _Panic(); \ 52 | } while (0) 53 | #define MessageFlags(flags, msg...) \ 54 | _Message(flags, __FILE__, __LINE__, __func__, msg) 55 | 56 | #define Panic(msg...) PanicFlags(0, msg) 57 | #define Warning(msg...) MessageFlags(MSG_WARNING, msg) 58 | #define Notice(msg...) MessageFlags(MSG_NOTICE, msg) 59 | #define QNotice(msg...) _Message(MSG_NOTICE, NULL, 0, NULL, msg) 60 | 61 | #define PPanic(msg...) PanicFlags(MSG_PERROR, msg) 62 | #define PWarning(msg...) MessageFlags((Message_Type)(MSG_WARNING|MSG_PERROR), msg) 63 | #define PNotice(msg...) MessageFlags((Message_Type)(MSG_NOTICE|MSG_PERROR), msg) 64 | 65 | void _Message(enum Message_Type type, 66 | const char *fname, int line, const char *func, 67 | const char *fmt, ...) 68 | __attribute__((format(printf,5,6))); 69 | void _Panic(void) __attribute__((noreturn)); 70 | bool _Message_DebugEnabled(const char *fname); 71 | 72 | void Message_VA(enum Message_Type type, 73 | const char *fname, int line, const char *func, 74 | const char *fmt, va_list args); 75 | 76 | void _Message_VA(enum Message_Type type, FILE *fp, 77 | const char *fname, int line, const char *func, 78 | const char *fmt, va_list args); 79 | 80 | const char *Message_DFree(char *buf); 81 | void Message_DoFrees(void); 82 | 83 | void _Message_Hexdump(const void *data, int len); 84 | char *Message_FmtBlob(const void *data, int len); 85 | void PanicOnSignal(int signo); 86 | 87 | // This is not a mistake. We actually want exactly one of these flags 88 | // per file that uses the Debug macro. 89 | static __attribute__((unused)) signed char _Message_FileDebugFlag = -1; 90 | 91 | #define Debug(msg...) \ 92 | do { \ 93 | if (Message_DebugEnabled(__FILE__)) \ 94 | MessageFlags(MSG_DEBUG, msg); \ 95 | } while (0) 96 | #define Message_Hexdump(data, len) \ 97 | do { \ 98 | if (Message_DebugEnabled(__FILE__)) \ 99 | _Message_Hexdump(data, len); \ 100 | } while (0) 101 | #ifndef NASSERT 102 | #define Assert(pred) \ 103 | do { \ 104 | if (!(pred)) \ 105 | Panic("Assertion `%s' failed", #pred); \ 106 | } while (0) 107 | #else 108 | #define Assert(pred) 109 | #endif 110 | 111 | static inline bool 112 | Message_DebugEnabled(const char *fname) 113 | { 114 | if (_Message_FileDebugFlag >= 0) 115 | return _Message_FileDebugFlag; 116 | _Message_FileDebugFlag = _Message_DebugEnabled(fname); 117 | return _Message_FileDebugFlag; 118 | } 119 | 120 | #include "hash.h" 121 | 122 | #define FMT_BLOB "<%ld %08x>" 123 | #define VA_BLOB(d, l) (long)l, hash(d, l, 0) 124 | #define VA_BLOB_STRING(d) (long)d.size(), \ 125 | hash(d.c_str(), d.size(), 0) 126 | 127 | #define FMT_VBLOB "%s" 128 | #define XVA_VBLOB(d, l) Message_DFree(Message_FmtBlob(d, l)) 129 | #define XVA_VBLOB_STRING(d) Message_DFree(Message_FmtBlob(d.c_str(), \ 130 | d.size())) 131 | 132 | #endif // _LIB_MESSAGE_H_ 133 | -------------------------------------------------------------------------------- /unreplicated/replica.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * unreplicated.cc: 5 | * dummy implementation of replication interface that just uses a 6 | * single replica and passes commands directly to it 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #include "common/replica.h" 33 | #include "unreplicated/replica.h" 34 | #include "unreplicated/unreplicated-proto.pb.h" 35 | 36 | #include "lib/message.h" 37 | #include "lib/transport.h" 38 | 39 | namespace specpaxos { 40 | namespace unreplicated { 41 | 42 | using namespace proto; 43 | 44 | void 45 | UnreplicatedReplica::HandleRequest(const TransportAddress &remote, 46 | const proto::RequestMessage &msg) 47 | { 48 | proto::ReplyMessage reply; 49 | 50 | auto kv = clientTable.find(msg.req().clientid()); 51 | if (kv != clientTable.end()) { 52 | const ClientTableEntry &entry = kv->second; 53 | if (msg.req().clientreqid() < entry.lastReqId) { 54 | Notice("Ignoring stale request"); 55 | return; 56 | } 57 | if (msg.req().clientreqid() == entry.lastReqId) { 58 | Notice("Received duplicate request; resending reply"); 59 | if (!(transport->SendMessage(this, remote, entry.reply))) { 60 | Warning("Failed to resend reply to client"); 61 | } 62 | return; 63 | } 64 | } 65 | 66 | ++last_op_; 67 | viewstamp_t v; 68 | v.view = 0; 69 | v.opnum = last_op_; 70 | v.sessnum = 0; 71 | v.msgnum = 0; 72 | log.Append(v, msg.req(), LOG_STATE_RECEIVED); 73 | 74 | Debug("Received request %s", (char *)msg.req().op().c_str()); 75 | 76 | Execute(0, msg.req(), reply); 77 | 78 | // The protocol defines these as required, even if they're not 79 | // meaningful. 80 | reply.set_view(0); 81 | reply.set_opnum(0); 82 | *(reply.mutable_req()) = msg.req(); 83 | 84 | if (!(transport->SendMessage(this, remote, reply))) 85 | Warning("Failed to send reply message"); 86 | 87 | UpdateClientTable(msg.req(), reply); 88 | } 89 | 90 | void 91 | UnreplicatedReplica::HandleUnloggedRequest(const TransportAddress &remote, 92 | const proto::UnloggedRequestMessage &msg) 93 | { 94 | proto::UnloggedReplyMessage reply; 95 | 96 | Debug("Received unlogged request %s", (char *)msg.req().op().c_str()); 97 | 98 | ExecuteUnlogged(msg.req(), reply); 99 | 100 | if (!(transport->SendMessage(this, remote, reply))) 101 | Warning("Failed to send reply message"); 102 | } 103 | 104 | UnreplicatedReplica::UnreplicatedReplica(Configuration config, 105 | int myIdx, 106 | bool initialize, 107 | Transport *transport, 108 | AppReplica *app) 109 | : Replica(config, 0, myIdx, initialize, transport, app), 110 | log(false) 111 | { 112 | if (!initialize) { 113 | Panic("Recovery does not make sense for unreplicated mode"); 114 | } 115 | 116 | this->status = STATUS_NORMAL; 117 | this->last_op_ = 0; 118 | } 119 | 120 | void 121 | UnreplicatedReplica::ReceiveMessage(const TransportAddress &remote, 122 | const string &type, const string &data, 123 | void *meta_data) 124 | { 125 | static proto::RequestMessage request; 126 | static proto::UnloggedRequestMessage unloggedRequest; 127 | 128 | if (type == request.GetTypeName()) { 129 | request.ParseFromString(data); 130 | HandleRequest(remote, request); 131 | } else if (type == unloggedRequest.GetTypeName()) { 132 | unloggedRequest.ParseFromString(data); 133 | HandleUnloggedRequest(remote, unloggedRequest); 134 | } else { 135 | Panic("Received unexpected message type in unreplicated proto: %s", 136 | type.c_str()); 137 | } 138 | } 139 | 140 | void 141 | UnreplicatedReplica::UpdateClientTable(const Request &req, 142 | const proto::ReplyMessage &reply) 143 | { 144 | ClientTableEntry &entry = clientTable[req.clientid()]; 145 | 146 | ASSERT(entry.lastReqId <= req.clientreqid()); 147 | 148 | if (entry.lastReqId == req.clientreqid()) { 149 | // Duplicate request 150 | return; 151 | } 152 | 153 | entry.lastReqId = req.clientreqid(); 154 | entry.reply = reply; 155 | } 156 | 157 | } // namespace specpaxos::unreplicated 158 | } // namespace specpaxos 159 | -------------------------------------------------------------------------------- /lib/simtransport.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * simtransport.h: 5 | * simulated message-passing interface for testing use 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Jialin Li 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_SIMTRANSPORT_H_ 33 | #define _LIB_SIMTRANSPORT_H_ 34 | 35 | #include "lib/transport.h" 36 | #include "lib/transportcommon.h" 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | class SimulatedTransportAddress : public TransportAddress 43 | { 44 | public: 45 | SimulatedTransportAddress * clone() const; 46 | int GetAddr() const; 47 | bool operator==(const SimulatedTransportAddress &other) const; 48 | inline bool operator!=(const SimulatedTransportAddress &other) const 49 | { 50 | return !(*this == other); 51 | } 52 | private: 53 | SimulatedTransportAddress(int addr); 54 | 55 | int addr; 56 | friend class SimulatedTransport; 57 | }; 58 | 59 | class SimulatedTransport : 60 | public TransportCommon 61 | { 62 | typedef std::function, 63 | TransportReceiver*, std::pair, 64 | Message &, uint64_t &delay)> filter_t; 65 | public: 66 | SimulatedTransport(bool continuous = false); 67 | ~SimulatedTransport(); 68 | void Register(TransportReceiver *receiver, 69 | const specpaxos::Configuration &config, 70 | int groupIdx, 71 | int replicaIdx) override; 72 | void Run() override; 73 | void Stop() override; 74 | void AddFilter(int id, filter_t filter); 75 | void RemoveFilter(int id); 76 | int Timer(uint64_t ms, timer_callback_t cb) override; 77 | bool CancelTimer(int id) override; 78 | void CancelAllTimers() override; 79 | bool OrderedMulticast(TransportReceiver *src, 80 | const std::vector &groups, 81 | const Message &m) override; 82 | 83 | // Returns if simtransport still have timers 84 | bool HasTimers() { 85 | return !timers.empty(); 86 | } 87 | 88 | // Increment session number. (for testing only) 89 | void SessionChange(); 90 | 91 | protected: 92 | bool SendMessageInternal(TransportReceiver *src, 93 | const SimulatedTransportAddress &dstAddr, 94 | const Message &m) override; 95 | SimulatedTransportAddress 96 | LookupAddress(const specpaxos::Configuration &cfg, 97 | int groupdIdx, 98 | int replicaIdx) override; 99 | const SimulatedTransportAddress * 100 | LookupMulticastAddress(const specpaxos::Configuration *cfg) override; 101 | const SimulatedTransportAddress * 102 | LookupFCAddress(const specpaxos::Configuration *cfg) override; 103 | 104 | private: 105 | struct QueuedMessage { 106 | int dst; 107 | int src; 108 | string type; 109 | string msg; 110 | multistamp_t stamp; 111 | inline QueuedMessage(int dst, int src, 112 | const string &type, const string &msg, const multistamp_t &stamp) : 113 | dst(dst), src(src), type(type), msg(msg), stamp(stamp) { } 114 | }; 115 | struct PendingTimer { 116 | uint64_t when; 117 | int id; 118 | timer_callback_t cb; 119 | }; 120 | 121 | std::deque queue; 122 | std::map endpoints; 123 | int lastAddr; 124 | std::map > replicaIdxs; // address to 125 | int fcAddress; 126 | std::multimap filters; 127 | std::multimap timers; 128 | int lastTimerId; 129 | uint64_t vtime; 130 | bool processTimers; 131 | bool running; 132 | bool continuous; 133 | 134 | // Network-Ordered packet counters 135 | std::map noCounters; // (64bit) counter for each (32bit) group 136 | uint64_t sequencerID; // current sequencer ID 137 | 138 | bool _SendMessageInternal(TransportReceiver *src, 139 | const SimulatedTransportAddress &dstAddr, 140 | const Message &m, 141 | const multistamp_t &stamp); 142 | void RegisterEndpoint(TransportReceiver *receiver, int groupIdx, int replicaIdx); 143 | void RegisterFC(); 144 | }; 145 | 146 | #endif // _LIB_SIMTRANSPORT_H_ 147 | -------------------------------------------------------------------------------- /vr/replica.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * vr/replica.h: 5 | * Viewstamped Replication protocol 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _VR_REPLICA_H_ 32 | #define _VR_REPLICA_H_ 33 | 34 | #include "lib/configuration.h" 35 | #include "lib/latency.h" 36 | #include "common/log.h" 37 | #include "common/replica.h" 38 | #include "common/quorumset.h" 39 | #include "vr/vr-proto.pb.h" 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | namespace specpaxos { 46 | namespace vr { 47 | 48 | class VRReplica : public Replica 49 | { 50 | public: 51 | VRReplica(Configuration config, int myIdx, bool initialize, 52 | Transport *transport, int batchSize, 53 | AppReplica *app); 54 | ~VRReplica(); 55 | 56 | void ReceiveMessage(const TransportAddress &remote, 57 | const string &type, const string &data, 58 | void *meta_data) override; 59 | 60 | private: 61 | view_t view; 62 | opnum_t lastCommitted; 63 | opnum_t lastOp; 64 | view_t lastRequestStateTransferView; 65 | opnum_t lastRequestStateTransferOpnum; 66 | uint64_t recoveryNonce; 67 | std::list > pendingPrepares; 69 | proto::PrepareMessage lastPrepare; 70 | int batchSize; 71 | opnum_t lastBatchEnd; 72 | bool batchComplete; 73 | 74 | Log log; 75 | std::map > clientAddresses; 76 | struct ClientTableEntry 77 | { 78 | uint64_t lastReqId; 79 | bool replied; 80 | proto::ReplyMessage reply; 81 | }; 82 | std::map clientTable; 83 | 84 | QuorumSet prepareOKQuorum; 85 | QuorumSet startViewChangeQuorum; 86 | QuorumSet doViewChangeQuorum; 87 | QuorumSet recoveryResponseQuorum; 88 | 89 | Timeout *viewChangeTimeout; 90 | Timeout *nullCommitTimeout; 91 | Timeout *stateTransferTimeout; 92 | Timeout *resendPrepareTimeout; 93 | Timeout *closeBatchTimeout; 94 | Timeout *recoveryTimeout; 95 | 96 | Latency_t requestLatency; 97 | Latency_t executeAndReplyLatency; 98 | 99 | uint64_t GenerateNonce() const; 100 | bool AmLeader() const; 101 | void CommitUpTo(opnum_t upto); 102 | void SendPrepareOKs(opnum_t oldLastOp); 103 | void SendRecoveryMessages(); 104 | void RequestStateTransfer(); 105 | void EnterView(view_t newview); 106 | void StartViewChange(view_t newview); 107 | void SendNullCommit(); 108 | void UpdateClientTable(const Request &req); 109 | void ResendPrepare(); 110 | void CloseBatch(); 111 | 112 | void HandleRequest(const TransportAddress &remote, 113 | const proto::RequestMessage &msg); 114 | void HandleUnloggedRequest(const TransportAddress &remote, 115 | const proto::UnloggedRequestMessage &msg); 116 | 117 | void HandlePrepare(const TransportAddress &remote, 118 | const proto::PrepareMessage &msg); 119 | void HandlePrepareOK(const TransportAddress &remote, 120 | const proto::PrepareOKMessage &msg); 121 | void HandleCommit(const TransportAddress &remote, 122 | const proto::CommitMessage &msg); 123 | void HandleRequestStateTransfer(const TransportAddress &remote, 124 | const proto::RequestStateTransferMessage &msg); 125 | void HandleStateTransfer(const TransportAddress &remote, 126 | const proto::StateTransferMessage &msg); 127 | void HandleStartViewChange(const TransportAddress &remote, 128 | const proto::StartViewChangeMessage &msg); 129 | void HandleDoViewChange(const TransportAddress &remote, 130 | const proto::DoViewChangeMessage &msg); 131 | void HandleStartView(const TransportAddress &remote, 132 | const proto::StartViewMessage &msg); 133 | void HandleRecovery(const TransportAddress &remote, 134 | const proto::RecoveryMessage &msg); 135 | void HandleRecoveryResponse(const TransportAddress &remote, 136 | const proto::RecoveryResponseMessage &msg); 137 | }; 138 | 139 | } // namespace specpaxos::vr 140 | } // namespace specpaxos 141 | 142 | #endif /* _VR_REPLICA_H_ */ 143 | -------------------------------------------------------------------------------- /common/log.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * log.h: 5 | * a replica's log of pending and committed operations 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * Jialin Li 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _COMMON_LOG_H_ 33 | #define _COMMON_LOG_H_ 34 | 35 | #include "common/request.pb.h" 36 | #include "lib/assert.h" 37 | #include "lib/message.h" 38 | #include "lib/transport.h" 39 | #include "lib/viewstamp.h" 40 | 41 | #include 42 | #include 43 | 44 | namespace specpaxos { 45 | 46 | enum LogEntryState { 47 | LOG_STATE_COMMITTED, 48 | LOG_STATE_PREPARED, 49 | LOG_STATE_SPECULATIVE, // specpaxos only 50 | LOG_STATE_FASTPREPARED, // fastpaxos only 51 | LOG_STATE_RECEIVED, // nopaxos only 52 | LOG_STATE_NOOP, // nopaxos only 53 | LOG_STATE_EXECUTED // granola 54 | }; 55 | 56 | 57 | class Log 58 | { 59 | 60 | public: 61 | struct LogEntry 62 | { 63 | viewstamp_t viewstamp; 64 | LogEntryState state; 65 | Request request; 66 | string hash; 67 | // Speculative client table stuff 68 | opnum_t prevClientReqOpnum; 69 | ::google::protobuf::Message *replyMessage; 70 | // Other data defined by protocols 71 | void *data; 72 | size_t data_len; 73 | 74 | LogEntry() { replyMessage = NULL; data = NULL; data_len = 0;} 75 | LogEntry(const LogEntry &x) 76 | : viewstamp(x.viewstamp), state(x.state), request(x.request), 77 | hash(x.hash), prevClientReqOpnum(x.prevClientReqOpnum) 78 | { 79 | if (x.replyMessage) { 80 | replyMessage = x.replyMessage->New(); 81 | replyMessage->CopyFrom(*x.replyMessage); 82 | } else { 83 | replyMessage = NULL; 84 | } 85 | 86 | if (x.data && x.data_len > 0) { 87 | data = malloc(x.data_len); 88 | data_len = x.data_len; 89 | memcpy(data, x.data, x.data_len); 90 | } else { 91 | data = NULL; 92 | data_len = 0; 93 | } 94 | } 95 | LogEntry(viewstamp_t viewstamp, 96 | LogEntryState state, 97 | const Request &request, 98 | const string &hash=Log::EMPTY_HASH) 99 | : viewstamp(viewstamp), state(state), request(request), 100 | hash(hash), replyMessage(NULL), data(NULL), data_len(0) { } 101 | virtual ~LogEntry() 102 | { 103 | if (replyMessage) { 104 | delete replyMessage; 105 | } 106 | if (data) { 107 | free(data); 108 | } 109 | } 110 | }; 111 | 112 | Log(bool useHash, opnum_t start = 1, string initialHash = EMPTY_HASH); 113 | LogEntry & Append(viewstamp_t vs, const Request &req, LogEntryState state, 114 | void *data = NULL, size_t data_len = 0); 115 | LogEntry & Append(viewstamp_t vs, 116 | const Request &req, 117 | const std::set &vss, 118 | LogEntryState state, 119 | void *data = NULL, 120 | size_t data_len = 0); 121 | LogEntry * Find(opnum_t opnum); 122 | LogEntry * Find(viewstamp_t vs); 123 | LogEntry * Find(const std::pair &reqid); 124 | bool SetStatus(opnum_t opnum, LogEntryState state); 125 | bool SetRequest(opnum_t op, const Request &req); 126 | void RemoveAfter(opnum_t opnum); 127 | LogEntry * Last(); 128 | viewstamp_t LastViewstamp() const; // deprecated 129 | opnum_t LastOpnum() const; 130 | opnum_t FirstOpnum() const; 131 | bool Empty() const; 132 | template void Dump(opnum_t from, T out); 133 | template void Dump(opnum_t from, opnum_t to, T out); 134 | template void Install(iter start, iter end); 135 | const string &LastHash() const; 136 | 137 | static string ComputeHash(string lastHash, const LogEntry &entry); 138 | static const string EMPTY_HASH; 139 | 140 | 141 | private: 142 | std::vector entries; 143 | string initialHash; 144 | opnum_t start; 145 | bool useHash; 146 | 147 | // Eris: Search log entry using viewstamps (from other shards) 148 | std::map vssMap; 149 | // Granola: Search log entry using tuple 150 | std::map, opnum_t> clientReqMap; 151 | }; 152 | 153 | typedef Log::LogEntry LogEntry; 154 | 155 | #include "common/log-impl.h" 156 | 157 | } // namespace specpaxos 158 | 159 | #endif /* _COMMON_LOG_H_ */ 160 | -------------------------------------------------------------------------------- /lib/transport.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * transport.h: 5 | * message-passing network interface definition 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _LIB_TRANSPORT_H_ 32 | #define _LIB_TRANSPORT_H_ 33 | 34 | #include "lib/configuration.h" 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | class TransportAddress 42 | { 43 | public: 44 | virtual ~TransportAddress() { } 45 | virtual TransportAddress *clone() const = 0; 46 | }; 47 | 48 | class TransportReceiver 49 | { 50 | protected: 51 | typedef ::google::protobuf::Message Message; 52 | 53 | public: 54 | virtual ~TransportReceiver(); 55 | virtual void SetAddress(const TransportAddress *addr); 56 | virtual const TransportAddress& GetAddress(); 57 | 58 | virtual void ReceiveMessage(const TransportAddress &remote, 59 | const string &type, 60 | const string &data, 61 | void * meta_data) = 0; 62 | 63 | protected: 64 | const TransportAddress *myAddress; 65 | }; 66 | 67 | typedef std::function timer_callback_t; 68 | 69 | // ordered multicast meta data 70 | typedef struct { 71 | sessnum_t sessnum; 72 | std::map seqnums; 73 | } multistamp_t; 74 | 75 | class Transport 76 | { 77 | protected: 78 | typedef ::google::protobuf::Message Message; 79 | public: 80 | virtual ~Transport() {} 81 | /* -1 in replicaIdx and groupIdx indicates client */ 82 | virtual void Register(TransportReceiver *receiver, 83 | const specpaxos::Configuration &config, 84 | int groupIdx, 85 | int replicaIdx) = 0; 86 | 87 | virtual bool SendMessage(TransportReceiver *src, 88 | const TransportAddress &dst, 89 | const Message &m) = 0; 90 | /* Send message to a replica in the local/default(0) group */ 91 | virtual bool SendMessageToReplica(TransportReceiver *src, 92 | int replicaIdx, 93 | const Message &m) = 0; 94 | /* Send message to a replica in a specific group */ 95 | virtual bool SendMessageToReplica(TransportReceiver *src, 96 | int groupIdx, 97 | int replicaIdx, 98 | const Message &m) = 0; 99 | /* Send message to all replicas in the local/default(0) group */ 100 | virtual bool SendMessageToAll(TransportReceiver *src, 101 | const Message &m) = 0; 102 | /* Send message to all replicas in all groups in the configuration */ 103 | virtual bool SendMessageToAllGroups(TransportReceiver *src, 104 | const Message &m) = 0; 105 | /* Send message to all replicas in specific groups */ 106 | virtual bool SendMessageToGroups(TransportReceiver *src, 107 | const std::vector &groups, 108 | const Message &m) = 0; 109 | /* Send message to all replicas in a single group */ 110 | virtual bool SendMessageToGroup(TransportReceiver *src, 111 | int groupIdx, 112 | const Message &m) = 0; 113 | /* Send multi-group message using ordered multicast. 114 | * An implementation may decide not to implement this. 115 | */ 116 | virtual bool OrderedMulticast(TransportReceiver *src, 117 | const std::vector &groups, 118 | const Message &m) = 0; 119 | /* Send ordered multicast to the default group */ 120 | virtual bool OrderedMulticast(TransportReceiver *src, 121 | const Message &m) = 0; 122 | /* Send message to failure coordinator 123 | */ 124 | virtual bool SendMessageToFC(TransportReceiver *src, 125 | const Message &m) = 0; 126 | virtual int Timer(uint64_t ms, timer_callback_t cb) = 0; 127 | virtual bool CancelTimer(int id) = 0; 128 | virtual void CancelAllTimers() = 0; 129 | virtual void Run() = 0; 130 | virtual void Stop() = 0; 131 | }; 132 | 133 | class Timeout 134 | { 135 | public: 136 | Timeout(Transport *transport, uint64_t ms, timer_callback_t cb); 137 | virtual ~Timeout(); 138 | virtual void SetTimeout(uint64_t ms); 139 | virtual uint64_t Start(); 140 | virtual uint64_t Reset(); 141 | virtual void Stop(); 142 | virtual bool Active() const; 143 | 144 | private: 145 | Transport *transport; 146 | uint64_t ms; 147 | timer_callback_t cb; 148 | int timerId; 149 | }; 150 | 151 | #endif // _LIB_TRANSPORT_H_ 152 | -------------------------------------------------------------------------------- /spec/replica.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * spec/replica.h: 5 | * Speculative Paxos protocol 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #ifndef _SPEC_REPLICA_H_ 32 | #define _SPEC_REPLICA_H_ 33 | 34 | #include "lib/configuration.h" 35 | #include "lib/latency.h" 36 | #include "common/log.h" 37 | #include "common/replica.h" 38 | #include "common/quorumset.h" 39 | #include "spec/spec-proto.pb.h" 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | class LogMergeTest; 48 | 49 | namespace specpaxos { 50 | namespace spec { 51 | 52 | class SpecReplica : public Replica 53 | { 54 | public: 55 | SpecReplica(Configuration config, int myIdx, bool initialize, 56 | Transport *transport, AppReplica *app); 57 | ~SpecReplica(); 58 | 59 | void ReceiveMessage(const TransportAddress &remote, 60 | const string &type, const string &data, 61 | void *meta_data); 62 | 63 | public: // XXX public for unit testing 64 | Log log; 65 | private: 66 | view_t view; 67 | opnum_t lastCommitted; 68 | opnum_t lastCommittedSent; 69 | opnum_t lastSpeculative; 70 | opnum_t pendingSync; 71 | opnum_t lastSync; 72 | view_t sentDoViewChange; 73 | view_t needFillDVC; 74 | std::map > clientAddresses; 75 | struct ClientTableEntry 76 | { 77 | uint64_t lastReqId; 78 | // We need the opnum to identify the correct entry in the 79 | // log. What we really want is the SpeculativeReplyMessage 80 | // corresponding to the last request, but we need to stuff 81 | // that in the log instead of keeping it here -- in order to 82 | // keep this up to date even if we roll back the log. 83 | opnum_t lastReqOpnum; 84 | }; 85 | std::map clientTable; 86 | std::list > pendingRequests; 88 | 89 | QuorumSet syncReplyQuorum; 90 | QuorumSet startViewChangeQuorum; 91 | QuorumSet doViewChangeQuorum; 92 | QuorumSet inViewQuorum; 93 | 94 | Timeout *syncTimeout; 95 | Timeout *failedSyncTimeout; 96 | Timeout *viewChangeTimeout; 97 | 98 | Latency_t reconciliationLatency; 99 | Latency_t mergeLatency; 100 | Latency_t requestLatency; 101 | 102 | bool AmLeader() const; 103 | void SendSync(); 104 | void CommitUpTo(opnum_t upto); 105 | void RollbackTo(opnum_t backto); 106 | void UpdateClientTable(const Request &req, 107 | LogEntry &entry, 108 | const proto::SpeculativeReplyMessage &reply); 109 | void EnterView(view_t newview); 110 | void StartViewChange(view_t newview); 111 | void MergeLogs(view_t newView, opnum_t maxStart, 112 | const std::map &dvcs, 113 | std::vector &out); 114 | void InstallLog(const std::vector &entries); 115 | void SendFillDVCGapMessage(int replicaIdx, view_t view); 116 | void NeedFillDVCGap(view_t view); 117 | void SendSyncReply(opnum_t opnum); 118 | 119 | void HandleRequest(const TransportAddress &remote, 120 | const proto::RequestMessage &msg); 121 | void HandleUnloggedRequest(const TransportAddress &remote, 122 | const proto::UnloggedRequestMessage &msg); 123 | void HandleSync(const TransportAddress &remote, 124 | const proto::SyncMessage &msg); 125 | void HandleSyncReply(const TransportAddress &remote, 126 | const proto::SyncReplyMessage &msg); 127 | void HandleRequestViewChange(const TransportAddress &remote, 128 | const proto::RequestViewChangeMessage &msg); 129 | void HandleStartViewChange(const TransportAddress &remote, 130 | const proto::StartViewChangeMessage &msg); 131 | void HandleDoViewChange(const TransportAddress &remote, 132 | const proto::DoViewChangeMessage &msg); 133 | void HandleStartView(const TransportAddress &remote, 134 | const proto::StartViewMessage &msg); 135 | void HandleInView(const TransportAddress &remote, 136 | const proto::InViewMessage &msg); 137 | void HandleFillLogGap(const TransportAddress &remote, 138 | const proto::FillLogGapMessage &msg); 139 | void HandleFillDVCGap(const TransportAddress &remote, 140 | const proto::FillDVCGapMessage &msg); 141 | 142 | friend class ::LogMergeTest; 143 | }; 144 | 145 | 146 | } // namespace specpaxos::spec 147 | } // namespace specpaxos 148 | 149 | #endif /* _SPEC_REPLICA_H_ */ 150 | -------------------------------------------------------------------------------- /bench/benchmark.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * benchmark.cpp: 5 | * simple replication benchmark client 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "bench/benchmark.h" 32 | #include "common/client.h" 33 | #include "lib/latency.h" 34 | #include "lib/message.h" 35 | #include "lib/transport.h" 36 | #include "lib/timeval.h" 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | namespace specpaxos { 44 | 45 | DEFINE_LATENCY(op); 46 | 47 | BenchmarkClient::BenchmarkClient(Client &client, Transport &transport, 48 | int numRequests, uint64_t delay, 49 | int warmupSec, 50 | int tputInterval, 51 | string latencyFilename) 52 | : tputInterval(tputInterval), client(client), 53 | transport(transport), numRequests(numRequests), 54 | delay(delay), warmupSec(warmupSec), 55 | latencyFilename(latencyFilename) 56 | { 57 | if (delay != 0) { 58 | Notice("Delay between requests: %ld ms", delay); 59 | } 60 | started = false; 61 | done = false; 62 | cooldownDone = false; 63 | _Latency_Init(&latency, "op"); 64 | latencies.reserve(numRequests); 65 | } 66 | 67 | void 68 | BenchmarkClient::Start() 69 | { 70 | n = 0; 71 | transport.Timer(warmupSec * 1000, 72 | std::bind(&BenchmarkClient::WarmupDone, 73 | this)); 74 | 75 | if (tputInterval > 0) { 76 | msSinceStart = 0; 77 | opLastInterval = n; 78 | transport.Timer(tputInterval, std::bind(&BenchmarkClient::TimeInterval, 79 | this)); 80 | } 81 | SendNext(); 82 | } 83 | 84 | void 85 | BenchmarkClient::TimeInterval() 86 | { 87 | if (done) { 88 | return; 89 | } 90 | 91 | struct timeval tv; 92 | gettimeofday(&tv, NULL); 93 | msSinceStart += tputInterval; 94 | Notice("Completed %d requests at %lu ms", n-opLastInterval, (((tv.tv_sec*1000000+tv.tv_usec)/1000)/10)*10); 95 | opLastInterval = n; 96 | transport.Timer(tputInterval, std::bind(&BenchmarkClient::TimeInterval, 97 | this)); 98 | } 99 | 100 | void 101 | BenchmarkClient::WarmupDone() 102 | { 103 | started = true; 104 | Notice("Completed warmup period of %d seconds with %d requests", 105 | warmupSec, n); 106 | gettimeofday(&startTime, NULL); 107 | n = 0; 108 | } 109 | 110 | void 111 | BenchmarkClient::CooldownDone() 112 | { 113 | 114 | char buf[1024]; 115 | cooldownDone = true; 116 | Notice("Finished cooldown period."); 117 | std::sort(latencies.begin(), latencies.end()); 118 | 119 | uint64_t ns = latencies[latencies.size()/2]; 120 | LatencyFmtNS(ns, buf); 121 | Notice("Median latency is %ld ns (%s)", ns, buf); 122 | 123 | ns = 0; 124 | for (auto latency : latencies) { 125 | ns += latency; 126 | } 127 | ns = ns / latencies.size(); 128 | LatencyFmtNS(ns, buf); 129 | Notice("Average latency is %ld ns (%s)", ns, buf); 130 | 131 | ns = latencies[latencies.size()*90/100]; 132 | LatencyFmtNS(ns, buf); 133 | Notice("90th percentile latency is %ld ns (%s)", ns, buf); 134 | 135 | ns = latencies[latencies.size()*95/100]; 136 | LatencyFmtNS(ns, buf); 137 | Notice("95th percentile latency is %ld ns (%s)", ns, buf); 138 | 139 | ns = latencies[latencies.size()*99/100]; 140 | LatencyFmtNS(ns, buf); 141 | Notice("99th percentile latency is %ld ns (%s)", ns, buf); 142 | } 143 | 144 | void 145 | BenchmarkClient::SendNext() 146 | { 147 | std::ostringstream msg; 148 | msg << "request" << n; 149 | 150 | Latency_Start(&latency); 151 | client.Invoke(msg.str(), std::bind(&BenchmarkClient::OnReply, 152 | this, 153 | std::placeholders::_1, 154 | std::placeholders::_2)); 155 | } 156 | 157 | void 158 | BenchmarkClient::OnReply(const string &request, const string &reply) 159 | { 160 | if (cooldownDone) { 161 | return; 162 | } 163 | 164 | if ((started) && (!done) && (n != 0)) { 165 | uint64_t ns = Latency_End(&latency); 166 | latencies.push_back(ns); 167 | if (n > numRequests) { 168 | Finish(); 169 | } 170 | } 171 | 172 | n++; 173 | if (delay == 0) { 174 | SendNext(); 175 | } else { 176 | uint64_t rdelay = rand() % delay*2; 177 | transport.Timer(rdelay, 178 | std::bind(&BenchmarkClient::SendNext, this)); 179 | } 180 | } 181 | 182 | void 183 | BenchmarkClient::Finish() 184 | { 185 | gettimeofday(&endTime, NULL); 186 | 187 | struct timeval diff = timeval_sub(endTime, startTime); 188 | 189 | Notice("Completed %d requests in " FMT_TIMEVAL_DIFF " seconds", 190 | numRequests, VA_TIMEVAL_DIFF(diff)); 191 | done = true; 192 | 193 | transport.Timer(warmupSec * 1000, 194 | std::bind(&BenchmarkClient::CooldownDone, 195 | this)); 196 | 197 | 198 | if (latencyFilename.size() > 0) { 199 | Latency_FlushTo(latencyFilename.c_str()); 200 | } 201 | } 202 | 203 | 204 | } // namespace specpaxos 205 | -------------------------------------------------------------------------------- /lib/udptransport.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * udptransport.h: 5 | * message-passing network interface that uses UDP message delivery 6 | * and libasync 7 | * 8 | * Copyright 2013 Dan R. K. Ports 9 | * 10 | * Permission is hereby granted, free of charge, to any person 11 | * obtaining a copy of this software and associated documentation 12 | * files (the "Software"), to deal in the Software without 13 | * restriction, including without limitation the rights to use, copy, 14 | * modify, merge, publish, distribute, sublicense, and/or sell copies 15 | * of the Software, and to permit persons to whom the Software is 16 | * furnished to do so, subject to the following conditions: 17 | * 18 | * The above copyright notice and this permission notice shall be 19 | * included in all copies or substantial portions of the Software. 20 | * 21 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 22 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 24 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 25 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 26 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 28 | * SOFTWARE. 29 | * 30 | **********************************************************************/ 31 | 32 | #ifndef _LIB_UDPTRANSPORT_H_ 33 | #define _LIB_UDPTRANSPORT_H_ 34 | 35 | #include "lib/configuration.h" 36 | #include "lib/transport.h" 37 | #include "lib/transportcommon.h" 38 | #include "lib/workertasks.h" 39 | 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | class UDPTransportAddress : public TransportAddress 51 | { 52 | public: 53 | UDPTransportAddress * clone() const; 54 | private: 55 | UDPTransportAddress(const sockaddr_in &addr); 56 | sockaddr_in addr; 57 | friend class UDPTransport; 58 | friend bool operator==(const UDPTransportAddress &a, 59 | const UDPTransportAddress &b); 60 | friend bool operator!=(const UDPTransportAddress &a, 61 | const UDPTransportAddress &b); 62 | friend bool operator<(const UDPTransportAddress &a, 63 | const UDPTransportAddress &b); 64 | }; 65 | 66 | class UDPTransport : public TransportCommon 67 | { 68 | public: 69 | UDPTransport(double dropRate = 0.0, double reorderRate = 0.0, 70 | int dscp = 0, event_base *evbase = nullptr); 71 | virtual ~UDPTransport(); 72 | virtual void Register(TransportReceiver *receiver, 73 | const specpaxos::Configuration &config, 74 | int groupIdx, 75 | int replicaIdx) override; 76 | virtual bool OrderedMulticast(TransportReceiver *src, 77 | const std::vector &groups, 78 | const Message &m) override; 79 | void Run() override; 80 | void Stop() override; 81 | int Timer(uint64_t ms, timer_callback_t cb) override; 82 | bool CancelTimer(int id) override; 83 | void CancelAllTimers() override; 84 | 85 | private: 86 | struct UDPTransportTimerInfo 87 | { 88 | UDPTransport *transport; 89 | timer_callback_t cb; 90 | event *ev; 91 | int id; 92 | }; 93 | 94 | double dropRate; 95 | double reorderRate; 96 | std::uniform_real_distribution uniformDist; 97 | std::default_random_engine randomEngine; 98 | struct 99 | { 100 | bool valid; 101 | UDPTransportAddress *addr; 102 | string msgType; 103 | string message; 104 | int fd; 105 | } reorderBuffer; 106 | int dscp; 107 | 108 | event_base *libeventBase; 109 | std::vector listenerEvents; 110 | std::vector signalEvents; 111 | std::map receivers; // fd -> receiver 112 | std::map fds; // receiver -> fd 113 | std::map multicastFds; 114 | std::map multicastConfigs; 115 | int lastTimerId; 116 | std::map timers; 117 | uint64_t lastFragMsgId; 118 | struct UDPTransportFragInfo 119 | { 120 | uint64_t msgId; 121 | string data; 122 | }; 123 | std::map fragInfo; 124 | 125 | bool _SendMessageInternal(TransportReceiver *src, 126 | const UDPTransportAddress &dst, 127 | const Message &m, 128 | size_t meta_len, 129 | void *meta_data); 130 | bool SendMessageInternal(TransportReceiver *src, 131 | const UDPTransportAddress &dst, 132 | const Message &m) override; 133 | 134 | UDPTransportAddress 135 | LookupAddress(const specpaxos::ReplicaAddress &addr); 136 | UDPTransportAddress 137 | LookupAddress(const specpaxos::Configuration &cfg, 138 | int groupIdx, 139 | int replicaIdx) override; 140 | const UDPTransportAddress * 141 | LookupMulticastAddress(const specpaxos::Configuration *cfg) override; 142 | const UDPTransportAddress * 143 | LookupFCAddress(const specpaxos::Configuration *cfg) override; 144 | void ListenOnMulticastPort(const specpaxos::Configuration 145 | *canonicalConfig); 146 | void OnReadable(int fd); 147 | void ProcessPacket(int fd, sockaddr_in sender, socklen_t senderSize, 148 | char *buf, ssize_t sz); 149 | void OnTimer(UDPTransportTimerInfo *info); 150 | static void SocketCallback(evutil_socket_t fd, 151 | short what, void *arg); 152 | static void TimerCallback(evutil_socket_t fd, 153 | short what, void *arg); 154 | static void LogCallback(int severity, const char *msg); 155 | static void FatalCallback(int err); 156 | static void SignalCallback(evutil_socket_t fd, 157 | short what, void *arg); 158 | }; 159 | 160 | #endif // _LIB_UDPTRANSPORT_H_ 161 | -------------------------------------------------------------------------------- /unreplicated/client.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * unreplicated/client.cc: 5 | * dummy unreplicated client 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "common/client.h" 32 | #include "common/request.pb.h" 33 | #include "lib/message.h" 34 | #include "lib/transport.h" 35 | #include "unreplicated/client.h" 36 | #include "unreplicated/unreplicated-proto.pb.h" 37 | 38 | namespace specpaxos { 39 | namespace unreplicated { 40 | 41 | UnreplicatedClient::UnreplicatedClient(const Configuration &config, 42 | Transport *transport, 43 | uint64_t clientid) 44 | : Client(config, transport, clientid) 45 | { 46 | pendingRequest = NULL; 47 | pendingUnloggedRequest = NULL; 48 | lastReqId = 0; 49 | requestTimeout = new Timeout(transport, 1000, [this]() { 50 | ResendRequest(); 51 | }); 52 | } 53 | 54 | UnreplicatedClient::~UnreplicatedClient() 55 | { 56 | if (pendingRequest) { 57 | delete pendingRequest; 58 | } 59 | if (pendingUnloggedRequest) { 60 | delete pendingUnloggedRequest; 61 | } 62 | } 63 | 64 | void 65 | UnreplicatedClient::Invoke(const string &request, 66 | continuation_t continuation) 67 | { 68 | // XXX Can only handle one pending request for now 69 | if (pendingRequest != NULL) { 70 | Panic("Client only supports one pending request"); 71 | } 72 | 73 | ++lastReqId; 74 | pendingRequest = new PendingRequest(request, lastReqId, continuation); 75 | 76 | SendRequest(); 77 | } 78 | 79 | void 80 | UnreplicatedClient::SendRequest() 81 | { 82 | proto::RequestMessage reqMsg; 83 | reqMsg.mutable_req()->set_op(pendingRequest->request); 84 | reqMsg.mutable_req()->set_clientid(clientid); 85 | reqMsg.mutable_req()->set_clientreqid(lastReqId); 86 | 87 | // Unreplicated: just send to replica 0 88 | transport->SendMessageToReplica(this, 0, reqMsg); 89 | 90 | requestTimeout->Reset(); 91 | } 92 | 93 | void 94 | UnreplicatedClient::ResendRequest() 95 | { 96 | Warning("Timeout, resending request for req id %lu", lastReqId); 97 | SendRequest(); 98 | } 99 | 100 | void 101 | UnreplicatedClient::InvokeUnlogged(int replicaIdx, 102 | const string &request, 103 | continuation_t continuation, 104 | timeout_continuation_t timeoutContinuation, 105 | uint32_t timeout) 106 | { 107 | // XXX Can only handle one pending request for now 108 | if (pendingUnloggedRequest != NULL) { 109 | Panic("Client only supports one pending request"); 110 | } 111 | 112 | pendingUnloggedRequest = new PendingRequest(request, 0, continuation); 113 | 114 | proto::UnloggedRequestMessage reqMsg; 115 | reqMsg.mutable_req()->set_op(pendingUnloggedRequest->request); 116 | reqMsg.mutable_req()->set_clientid(clientid); 117 | reqMsg.mutable_req()->set_clientreqid(0); 118 | 119 | // Unreplicated: just send to replica 0 120 | if (replicaIdx != 0) { 121 | Panic("Attempt to invoke unlogged operation on replica that doesn't exist"); 122 | } 123 | transport->SendMessageToReplica(this, 0, reqMsg); 124 | 125 | } 126 | 127 | void 128 | UnreplicatedClient::ReceiveMessage(const TransportAddress &remote, 129 | const string &type, 130 | const string &data, 131 | void *meta_data) 132 | { 133 | static proto::ReplyMessage reply; 134 | static proto::UnloggedReplyMessage unloggedReply; 135 | 136 | if (type == reply.GetTypeName()) { 137 | reply.ParseFromString(data); 138 | HandleReply(remote, reply); 139 | } else if (type == unloggedReply.GetTypeName()) { 140 | unloggedReply.ParseFromString(data); 141 | HandleUnloggedReply(remote, unloggedReply); 142 | } else { 143 | Client::ReceiveMessage(remote, type, data, NULL); 144 | } 145 | } 146 | 147 | void 148 | UnreplicatedClient::HandleReply(const TransportAddress &remote, 149 | const proto::ReplyMessage &msg) 150 | { 151 | if (pendingRequest == NULL) { 152 | Warning("Received reply when no request was pending"); 153 | return; 154 | } 155 | 156 | if (msg.req().clientreqid() != pendingRequest->clientreqid) { 157 | return; 158 | } 159 | 160 | Debug("Client received reply"); 161 | 162 | requestTimeout->Stop(); 163 | 164 | PendingRequest *req = pendingRequest; 165 | pendingRequest = NULL; 166 | 167 | req->continuation(req->request, msg.reply()); 168 | delete req; 169 | } 170 | 171 | void 172 | UnreplicatedClient::HandleUnloggedReply(const TransportAddress &remote, 173 | const proto::UnloggedReplyMessage &msg) 174 | { 175 | if (pendingUnloggedRequest == NULL) { 176 | Warning("Received unloggedReply when no request was pending"); 177 | } 178 | 179 | Debug("Client received unloggedReply"); 180 | 181 | PendingRequest *req = pendingUnloggedRequest; 182 | pendingUnloggedRequest = NULL; 183 | 184 | req->continuation(req->request, msg.reply()); 185 | delete req; 186 | } 187 | 188 | } // namespace specpaxos::unreplicated 189 | } // namespace specpaxos 190 | -------------------------------------------------------------------------------- /common/log.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * log.h: 5 | * a replica's log of pending and committed operations 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "common/log.h" 32 | #include "common/request.pb.h" 33 | #include "lib/assert.h" 34 | 35 | #include 36 | 37 | namespace specpaxos { 38 | 39 | const string Log::EMPTY_HASH = string(SHA_DIGEST_LENGTH, '\0'); 40 | 41 | Log::Log(bool useHash, opnum_t start, string initialHash) 42 | : useHash(useHash) 43 | { 44 | this->initialHash = initialHash; 45 | this->start = start; 46 | if (start == 1) { 47 | ASSERT(initialHash == EMPTY_HASH); 48 | } 49 | 50 | // reserve enough space to reduce reallocation overhead 51 | entries.reserve(10000000); 52 | } 53 | 54 | 55 | LogEntry & 56 | Log::Append(viewstamp_t vs, const Request &req, LogEntryState state, void *data, size_t data_len) 57 | { 58 | if (entries.empty()) { 59 | ASSERT(vs.opnum == start); 60 | } else { 61 | ASSERT(vs.opnum == LastOpnum()+1); 62 | } 63 | 64 | string prevHash = LastHash(); 65 | entries.push_back(LogEntry(vs, state, req)); 66 | if (useHash) { 67 | entries.back().hash = ComputeHash(prevHash, entries.back()); 68 | } 69 | if (data && data_len > 0) { 70 | entries.back().data = malloc(data_len); 71 | entries.back().data_len = data_len; 72 | memcpy(entries.back().data, data, data_len); 73 | } 74 | 75 | this->clientReqMap[std::make_pair(req.clientid(), req.clientreqid())] = vs.opnum; 76 | 77 | return entries.back(); 78 | } 79 | 80 | LogEntry & 81 | Log::Append(viewstamp_t vs, 82 | const Request &req, 83 | const std::set &vss, 84 | LogEntryState state, 85 | void *data, 86 | size_t data_len) 87 | { 88 | for (auto &v : vss) { 89 | vssMap[v] = vs.opnum; 90 | } 91 | return Append(vs, req, state, data, data_len); 92 | } 93 | 94 | // This really ought to be const 95 | LogEntry * 96 | Log::Find(opnum_t opnum) 97 | { 98 | if (entries.empty()) { 99 | return NULL; 100 | } 101 | 102 | if (opnum < start) { 103 | return NULL; 104 | } 105 | 106 | if (opnum-start > entries.size()-1) { 107 | return NULL; 108 | } 109 | 110 | LogEntry *entry = &entries[opnum-start]; 111 | ASSERT(entry->viewstamp.opnum == opnum); 112 | return entry; 113 | } 114 | 115 | LogEntry * 116 | Log::Find(viewstamp_t vs) 117 | { 118 | if (vssMap.find(vs) == vssMap.end()) { 119 | return NULL; 120 | } 121 | 122 | return Find(vssMap[vs]); 123 | } 124 | 125 | LogEntry * 126 | Log::Find(const std::pair &reqid) 127 | { 128 | if (clientReqMap.find(reqid) == clientReqMap.end()) { 129 | return NULL; 130 | } 131 | 132 | return Find(clientReqMap[reqid]); 133 | } 134 | 135 | bool 136 | Log::SetStatus(opnum_t op, LogEntryState state) 137 | { 138 | LogEntry *entry = Find(op); 139 | if (entry == NULL) { 140 | return false; 141 | } 142 | 143 | entry->state = state; 144 | return true; 145 | } 146 | 147 | bool 148 | Log::SetRequest(opnum_t op, const Request &req) 149 | { 150 | if (useHash) { 151 | Panic("Log::SetRequest on hashed log not supported."); 152 | } 153 | 154 | LogEntry *entry = Find(op); 155 | if (entry == NULL) { 156 | return false; 157 | } 158 | 159 | entry->request = req; 160 | return true; 161 | } 162 | 163 | void 164 | Log::RemoveAfter(opnum_t op) 165 | { 166 | #if PARANOID 167 | // We'd better not be removing any committed entries. 168 | for (opnum_t i = op; i <= LastOpnum(); i++) { 169 | ASSERT(Find(i)->state != LOG_STATE_COMMITTED); 170 | } 171 | #endif 172 | 173 | if (op > LastOpnum()) { 174 | return; 175 | } 176 | 177 | Debug("Removing log entries after " FMT_OPNUM, op); 178 | 179 | ASSERT(op-start < entries.size()); 180 | entries.resize(op-start); 181 | 182 | ASSERT(LastOpnum() == op-1); 183 | } 184 | 185 | LogEntry * 186 | Log::Last() 187 | { 188 | if (entries.empty()) { 189 | return NULL; 190 | } 191 | 192 | return &entries.back(); 193 | } 194 | 195 | viewstamp_t 196 | Log::LastViewstamp() const 197 | { 198 | if (entries.empty()) { 199 | return viewstamp_t(0, start-1); 200 | } else { 201 | return entries.back().viewstamp; 202 | } 203 | } 204 | 205 | opnum_t 206 | Log::LastOpnum() const 207 | { 208 | if (entries.empty()) { 209 | return start-1; 210 | } else { 211 | return entries.back().viewstamp.opnum; 212 | } 213 | } 214 | 215 | opnum_t 216 | Log::FirstOpnum() const 217 | { 218 | // XXX Not really sure what's appropriate to return here if the 219 | // log is empty 220 | return start; 221 | } 222 | 223 | bool 224 | Log::Empty() const 225 | { 226 | return entries.empty(); 227 | } 228 | 229 | const string & 230 | Log::LastHash() const 231 | { 232 | if (entries.empty()) { 233 | return initialHash; 234 | } else { 235 | return entries.back().hash; 236 | } 237 | } 238 | 239 | string 240 | Log::ComputeHash(string lastHash, const LogEntry &entry) 241 | { 242 | SHA_CTX ctx; 243 | unsigned char out[SHA_DIGEST_LENGTH]; 244 | 245 | SHA1_Init(&ctx); 246 | 247 | SHA1_Update(&ctx, lastHash.c_str(), lastHash.size()); 248 | //SHA1_Update(&ctx, &entry.viewstamp, sizeof(entry.viewstamp)); 249 | uint64_t x[2]; 250 | x[0] = entry.request.clientid(); 251 | x[1] = entry.request.clientreqid(); 252 | SHA1_Update(&ctx, x, sizeof(uint64_t)*2); 253 | // SHA1_Update(&ctx, entry.request.op().c_str(), 254 | // entry.request.op().size()); 255 | 256 | SHA1_Final(out, &ctx); 257 | 258 | return string((char *)out, SHA_DIGEST_LENGTH); 259 | } 260 | 261 | } // namespace specpaxos 262 | -------------------------------------------------------------------------------- /vr/client.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * vr/client.cc: 5 | * Viewstamped Replication clinet 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "common/client.h" 32 | #include "common/request.pb.h" 33 | #include "lib/assert.h" 34 | #include "lib/message.h" 35 | #include "lib/transport.h" 36 | #include "vr/client.h" 37 | #include "vr/vr-proto.pb.h" 38 | 39 | namespace specpaxos { 40 | namespace vr { 41 | 42 | VRClient::VRClient(const Configuration &config, 43 | Transport *transport, 44 | uint64_t clientid) 45 | : Client(config, transport, clientid) 46 | { 47 | pendingRequest = NULL; 48 | pendingUnloggedRequest = NULL; 49 | lastReqId = 0; 50 | 51 | requestTimeout = new Timeout(transport, 7000, [this]() { 52 | ResendRequest(); 53 | }); 54 | unloggedRequestTimeout = new Timeout(transport, 1000, [this]() { 55 | UnloggedRequestTimeoutCallback(); 56 | }); 57 | } 58 | 59 | VRClient::~VRClient() 60 | { 61 | if (pendingRequest) { 62 | delete pendingRequest; 63 | } 64 | if (pendingUnloggedRequest) { 65 | delete pendingUnloggedRequest; 66 | } 67 | delete requestTimeout; 68 | delete unloggedRequestTimeout; 69 | } 70 | 71 | void 72 | VRClient::Invoke(const string &request, 73 | continuation_t continuation) 74 | { 75 | // XXX Can only handle one pending request for now 76 | if (pendingRequest != NULL) { 77 | Panic("Client only supports one pending request"); 78 | } 79 | 80 | ++lastReqId; 81 | uint64_t reqId = lastReqId; 82 | pendingRequest = new PendingRequest(request, reqId, continuation); 83 | 84 | SendRequest(); 85 | } 86 | 87 | void 88 | VRClient::InvokeUnlogged(int replicaIdx, 89 | const string &request, 90 | continuation_t continuation, 91 | timeout_continuation_t timeoutContinuation, 92 | uint32_t timeout) 93 | { 94 | // XXX Can only handle one pending request for now 95 | if (pendingUnloggedRequest != NULL) { 96 | Panic("Client only supports one pending request"); 97 | } 98 | 99 | ++lastReqId; 100 | uint64_t reqId = lastReqId; 101 | 102 | pendingUnloggedRequest = new PendingRequest(request, reqId, continuation); 103 | pendingUnloggedRequest->timeoutContinuation = timeoutContinuation; 104 | 105 | proto::UnloggedRequestMessage reqMsg; 106 | reqMsg.mutable_req()->set_op(pendingUnloggedRequest->request); 107 | reqMsg.mutable_req()->set_clientid(clientid); 108 | reqMsg.mutable_req()->set_clientreqid(pendingUnloggedRequest->clientReqId); 109 | 110 | ASSERT(!unloggedRequestTimeout->Active()); 111 | unloggedRequestTimeout->SetTimeout(timeout); 112 | unloggedRequestTimeout->Start(); 113 | 114 | transport->SendMessageToReplica(this, replicaIdx, reqMsg); 115 | } 116 | 117 | void 118 | VRClient::SendRequest() 119 | { 120 | proto::RequestMessage reqMsg; 121 | reqMsg.mutable_req()->set_op(pendingRequest->request); 122 | reqMsg.mutable_req()->set_clientid(clientid); 123 | reqMsg.mutable_req()->set_clientreqid(pendingRequest->clientReqId); 124 | 125 | // XXX Try sending only to (what we think is) the leader first 126 | transport->SendMessageToAll(this, reqMsg); 127 | 128 | requestTimeout->Reset(); 129 | } 130 | 131 | void 132 | VRClient::ResendRequest() 133 | { 134 | Warning("Client timeout; resending request"); 135 | SendRequest(); 136 | } 137 | 138 | 139 | void 140 | VRClient::ReceiveMessage(const TransportAddress &remote, 141 | const string &type, 142 | const string &data, 143 | void *meta_data) 144 | { 145 | static proto::ReplyMessage reply; 146 | static proto::UnloggedReplyMessage unloggedReply; 147 | 148 | if (type == reply.GetTypeName()) { 149 | reply.ParseFromString(data); 150 | HandleReply(remote, reply); 151 | } else if (type == unloggedReply.GetTypeName()) { 152 | unloggedReply.ParseFromString(data); 153 | HandleUnloggedReply(remote, unloggedReply); 154 | } else { 155 | Client::ReceiveMessage(remote, type, data, NULL); 156 | } 157 | } 158 | 159 | void 160 | VRClient::HandleReply(const TransportAddress &remote, 161 | const proto::ReplyMessage &msg) 162 | { 163 | if (pendingRequest == NULL) { 164 | Warning("Received reply when no request was pending"); 165 | return; 166 | } 167 | if (msg.clientreqid() != pendingRequest->clientReqId) { 168 | Warning("Received reply for a different request"); 169 | return; 170 | } 171 | 172 | Debug("Client received reply"); 173 | 174 | requestTimeout->Stop(); 175 | 176 | PendingRequest *req = pendingRequest; 177 | pendingRequest = NULL; 178 | 179 | req->continuation(req->request, msg.reply()); 180 | delete req; 181 | } 182 | 183 | void 184 | VRClient::HandleUnloggedReply(const TransportAddress &remote, 185 | const proto::UnloggedReplyMessage &msg) 186 | { 187 | if (pendingUnloggedRequest == NULL) { 188 | Warning("Received unloggedReply when no request was pending"); 189 | return; 190 | } 191 | 192 | Debug("Client received unloggedReply"); 193 | 194 | unloggedRequestTimeout->Stop(); 195 | 196 | PendingRequest *req = pendingUnloggedRequest; 197 | pendingUnloggedRequest = NULL; 198 | 199 | req->continuation(req->request, msg.reply()); 200 | delete req; 201 | } 202 | 203 | void 204 | VRClient::UnloggedRequestTimeoutCallback() 205 | { 206 | PendingRequest *req = pendingUnloggedRequest; 207 | pendingUnloggedRequest = NULL; 208 | 209 | Warning("Unlogged request timed out"); 210 | 211 | unloggedRequestTimeout->Stop(); 212 | 213 | req->timeoutContinuation(req->request); 214 | } 215 | 216 | } // namespace vr 217 | } // namespace specpaxos 218 | -------------------------------------------------------------------------------- /fastpaxos/client.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * fastpaxos/client.cc: 5 | * Fast Paxos client 6 | * 7 | * Copyright 2013 Dan R. K. Ports 8 | * 9 | * Permission is hereby granted, free of charge, to any person 10 | * obtaining a copy of this software and associated documentation 11 | * files (the "Software"), to deal in the Software without 12 | * restriction, including without limitation the rights to use, copy, 13 | * modify, merge, publish, distribute, sublicense, and/or sell copies 14 | * of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be 18 | * included in all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 24 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 25 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 26 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | * SOFTWARE. 28 | * 29 | **********************************************************************/ 30 | 31 | #include "common/client.h" 32 | #include "common/request.pb.h" 33 | #include "lib/assert.h" 34 | #include "lib/message.h" 35 | #include "lib/transport.h" 36 | #include "fastpaxos/client.h" 37 | #include "fastpaxos/fastpaxos-proto.pb.h" 38 | 39 | namespace specpaxos { 40 | namespace fastpaxos { 41 | 42 | FastPaxosClient::FastPaxosClient(const Configuration &config, 43 | Transport *transport, 44 | uint64_t clientid) 45 | : Client(config, transport, clientid) 46 | { 47 | pendingRequest = NULL; 48 | pendingUnloggedRequest = NULL; 49 | lastReqId = 0; 50 | 51 | requestTimeout = new Timeout(transport, 7000, [this]() { 52 | ResendRequest(); 53 | }); 54 | unloggedRequestTimeout = new Timeout(transport, 1000, [this]() { 55 | UnloggedRequestTimeoutCallback(); 56 | }); 57 | } 58 | 59 | FastPaxosClient::~FastPaxosClient() 60 | { 61 | if (pendingRequest) { 62 | delete pendingRequest; 63 | } 64 | if (pendingUnloggedRequest) { 65 | delete pendingUnloggedRequest; 66 | } 67 | delete requestTimeout; 68 | delete unloggedRequestTimeout; 69 | } 70 | 71 | void 72 | FastPaxosClient::Invoke(const string &request, 73 | continuation_t continuation) 74 | { 75 | // XXX Can only handle one pending request for now 76 | if (pendingRequest != NULL) { 77 | Panic("Client only supports one pending request"); 78 | } 79 | 80 | ++lastReqId; 81 | uint64_t reqId = lastReqId; 82 | pendingRequest = new PendingRequest(request, reqId, continuation); 83 | 84 | SendRequest(); 85 | } 86 | 87 | void 88 | FastPaxosClient::InvokeUnlogged(int replicaIdx, 89 | const string &request, 90 | continuation_t continuation, 91 | timeout_continuation_t timeoutContinuation, 92 | uint32_t timeout) 93 | { 94 | // XXX Can only handle one pending request for now 95 | if (pendingUnloggedRequest != NULL) { 96 | Panic("Client only supports one pending request"); 97 | } 98 | 99 | ++lastReqId; 100 | uint64_t reqId = lastReqId; 101 | 102 | pendingUnloggedRequest = new PendingRequest(request, reqId, continuation); 103 | pendingUnloggedRequest->timeoutContinuation = timeoutContinuation; 104 | 105 | proto::UnloggedRequestMessage reqMsg; 106 | reqMsg.mutable_req()->set_op(pendingUnloggedRequest->request); 107 | reqMsg.mutable_req()->set_clientid(clientid); 108 | reqMsg.mutable_req()->set_clientreqid(pendingUnloggedRequest->clientReqId); 109 | 110 | ASSERT(!unloggedRequestTimeout->Active()); 111 | unloggedRequestTimeout->SetTimeout(timeout); 112 | unloggedRequestTimeout->Start(); 113 | 114 | transport->SendMessageToReplica(this, replicaIdx, reqMsg); 115 | } 116 | 117 | void 118 | FastPaxosClient::SendRequest() 119 | { 120 | proto::RequestMessage reqMsg; 121 | reqMsg.mutable_req()->set_op(pendingRequest->request); 122 | reqMsg.mutable_req()->set_clientid(clientid); 123 | reqMsg.mutable_req()->set_clientreqid(pendingRequest->clientReqId); 124 | 125 | // XXX Try sending only to (what we think is) the leader first 126 | transport->SendMessageToAll(this, reqMsg); 127 | 128 | requestTimeout->Reset(); 129 | } 130 | 131 | void 132 | FastPaxosClient::ResendRequest() 133 | { 134 | Warning("Client timeout; resending request"); 135 | SendRequest(); 136 | } 137 | 138 | 139 | void 140 | FastPaxosClient::ReceiveMessage(const TransportAddress &remote, 141 | const string &type, 142 | const string &data, 143 | void *meta_data) 144 | { 145 | static proto::ReplyMessage reply; 146 | static proto::UnloggedReplyMessage unloggedReply; 147 | 148 | if (type == reply.GetTypeName()) { 149 | reply.ParseFromString(data); 150 | HandleReply(remote, reply); 151 | } else if (type == unloggedReply.GetTypeName()) { 152 | unloggedReply.ParseFromString(data); 153 | HandleUnloggedReply(remote, unloggedReply); 154 | } else { 155 | Client::ReceiveMessage(remote, type, data, meta_data); 156 | } 157 | } 158 | 159 | void 160 | FastPaxosClient::HandleReply(const TransportAddress &remote, 161 | const proto::ReplyMessage &msg) 162 | { 163 | Debug("Client received reply for " FMT_VIEWSTAMP, msg.view(), msg.opnum()); 164 | if (pendingRequest == NULL) { 165 | Debug("Received reply when no request was pending"); 166 | return; 167 | } 168 | if (msg.clientreqid() != pendingRequest->clientReqId) { 169 | Debug("Received reply for a different request"); 170 | return; 171 | } 172 | 173 | requestTimeout->Stop(); 174 | 175 | PendingRequest *req = pendingRequest; 176 | pendingRequest = NULL; 177 | 178 | req->continuation(req->request, msg.reply()); 179 | delete req; 180 | } 181 | 182 | void 183 | FastPaxosClient::HandleUnloggedReply(const TransportAddress &remote, 184 | const proto::UnloggedReplyMessage &msg) 185 | { 186 | if (pendingUnloggedRequest == NULL) { 187 | Warning("Received unloggedReply when no request was pending"); 188 | return; 189 | } 190 | 191 | Debug("Client received unloggedReply"); 192 | 193 | unloggedRequestTimeout->Stop(); 194 | 195 | PendingRequest *req = pendingUnloggedRequest; 196 | pendingUnloggedRequest = NULL; 197 | 198 | req->continuation(req->request, msg.reply()); 199 | delete req; 200 | } 201 | 202 | void 203 | FastPaxosClient::UnloggedRequestTimeoutCallback() 204 | { 205 | PendingRequest *req = pendingUnloggedRequest; 206 | pendingUnloggedRequest = NULL; 207 | 208 | Warning("Unlogged request timed out"); 209 | 210 | unloggedRequestTimeout->Stop(); 211 | 212 | req->timeoutContinuation(req->request); 213 | } 214 | 215 | } // namespace vr 216 | } // namespace specpaxos 217 | --------------------------------------------------------------------------------