├── Makefile ├── README.md ├── bench ├── .gitignore ├── Rules.mk ├── benchmark.cc ├── benchmark.h ├── client.cc └── replica.cc ├── common ├── Rules.mk ├── client.cc ├── client.h ├── log-impl.h ├── log.cc ├── log.h ├── quorumset.h ├── replica-inl.h ├── replica.cc ├── replica.h ├── request.proto └── tests │ └── Rules.mk ├── config.txt ├── env.sh ├── fastpaxos ├── Rules.mk ├── client.cc ├── client.h ├── fastpaxos-proto.proto ├── replica.cc ├── replica.h └── tests │ ├── Rules.mk │ └── fastpaxos-test.cc ├── kernel-src-download.sh ├── kernel-src-prepare.sh ├── kernel-src-remove.sh ├── lib ├── Rules.mk ├── assert.h ├── configuration.cc ├── configuration.h ├── hash.h ├── latency-format.proto ├── latency.cc ├── latency.h ├── lookup3.cc ├── memory.cc ├── memory.h ├── message.cc ├── message.h ├── simtransport.cc ├── simtransport.h ├── tests │ ├── Rules.mk │ ├── configuration-test-1.conf │ ├── configuration-test.cc │ ├── simtransport-test.cc │ └── simtransport-testmessage.proto ├── timeval.h ├── transport.cc ├── transport.h ├── transportcommon.h ├── udptransport.cc ├── udptransport.h └── viewstamp.h ├── nistore ├── .gitignore ├── Rules.mk ├── benchClient.cc ├── client.cc ├── client.h ├── keys.txt ├── kvstore.cc ├── kvstore.h ├── lockserver.cc ├── lockserver.h ├── lockstore.cc ├── lockstore.h ├── occstore.cc ├── occstore.h ├── request.proto ├── server.cc ├── server.h ├── shard.tss.config ├── shard0.config ├── txnstore.cc ├── txnstore.h ├── versionedKVStore.cc └── versionedKVStore.h ├── spec ├── Rules.mk ├── client.cc ├── client.h ├── replica.cc ├── replica.h ├── spec-proto.proto └── tests │ ├── Rules.mk │ ├── merge-test-case.proto │ ├── merge-test.cc │ ├── merge-tests │ ├── AllCommitted │ ├── Conflict │ ├── Divergence │ ├── EmptyLogs │ ├── OneEmpty │ ├── SpeculativeNoQuorum │ ├── SpeculativeQuorum │ └── Stress │ └── spec-test.cc ├── timeserver ├── .gitignore ├── Rules.mk ├── timeserver.cc └── timeserver.h ├── unreplicated ├── Rules.mk ├── client.cc ├── client.h ├── replica.cc ├── replica.h ├── tests │ ├── Rules.mk │ └── unreplicated-test.cc └── unreplicated-proto.proto ├── vr ├── Rules.mk ├── client.cc ├── client.h ├── replica.cc ├── replica.h ├── tests │ ├── Rules.mk │ └── vr-test.cc └── vr-proto.proto └── xdp-handler ├── Makefile ├── fast_common.h ├── fast_kern.c └── fast_user.c /README.md: -------------------------------------------------------------------------------- 1 | # Electrode 2 | 3 | This is an implementation of accelerating multi-Paxos Protocol using eBPF, as described in the paper ["Electrode: Accelerating Distributed 4 | Protocols with eBPF"](https://www.usenix.org/system/files/nsdi23-zhou.pdf) from NSDI 2023. 5 | 6 | 7 | ## Contents 8 | 9 | This repository mainly contains two parts: 10 | 11 | 1. Implementation of VR(Viewstamped Replication) protocol in `vr/`, the code is from [Speculative Paxos](https://github.com/UWSysLab/specpaxos). We did some modifications to implement our functions. 12 | 2. Implementation of the three optimizations in eBPF, you can find the code in `xdp-handler/`. The structure is from the source code of [BMC](https://github.com/Orange-OpenSource/bmc-cache). 13 | 14 | ## Building and Running 15 | 16 | We did our experiment in [Cloudlab](https://cloudlab.us/) by using the `raw-pc` type machine `xl170`. The initial Disk Image is `UBUNTU20-64-STD`. 17 | 18 | Because we are using kernel version `5.8.0`, we should update this manually: 19 | 20 | wget https://raw.githubusercontent.com/pimlie/ubuntu-mainline-kernel.sh/master/ubuntu-mainline-kernel.sh 21 | sudo bash ubuntu-mainline-kernel.sh -i 5.8.0 22 | sudo reboot 23 | 24 | You can check your kernel version by `uname -r`, before rebooting, the result is `5.4.0-100-generic`. After rebooting, the result is `5.8.0-050800-generic`. 25 | 26 | Then install dependencies. 27 | 28 | sudo apt update 29 | sudo apt install llvm clang gpg curl tar xz-utils make gcc flex bison libssl-dev libelf-dev protobuf-compiler pkg-config libunwind-dev libssl-dev libprotobuf-dev libevent-dev libgtest-dev 30 | 31 | Then we should build `xdp` modules, here we should run the script `kernel-src-download.sh` and `kernel-src-prepare.sh`, from [BMC project](https://www.usenix.org/conference/nsdi21/presentation/ghigoff). We did some modifications to support `5.8.0`. 32 | 33 | bash kernel-src-download.sh 34 | bash kernel-src-prepare.sh 35 | 36 | Then you should be able to compile the code: 37 | 38 | 1. In `./xdp-handler/`, run `make clean` and `make`. 39 | 2. In `./`, run `make clean` and `make PARANOID=0`. 40 | 41 | In our experiment, we disabled the adaptive batching in NIC and the irqbalance: 42 | 43 | sudo ifconfig ens1f1np1 mtu 3000 up 44 | sudo ethtool -C ens1f1np1 adaptive-rx off adaptive-tx off rx-frames 1 rx-usecs 0 tx-frames 1 tx-usecs 0 45 | sudo ethtool -C ens1f1np1 adaptive-rx off adaptive-tx off rx-frames 1 rx-usecs 0 tx-frames 1 tx-usecs 0 46 | sudo ethtool -L ens1f1np1 combined 1 47 | sudo service irqbalance stop 48 | (let CPU=0; cd /sys/class/net/ens1f1np1/device/msi_irqs/; 49 | for IRQ in *; do 50 | echo $CPU | sudo tee /proc/irq/$IRQ/smp_affinity_list 51 | done) 52 | 53 | Then you need to create a config file like (example in `./config.txt`) 54 | 55 | f 56 | replica : 57 | replica : 58 | ... 59 | 60 | Because in `TC_BROADCAST` optimization, we need to assign the mac address of the destination server, you should write the MACADDR of the cluster in line 281 of `xdp-handler/fast_user.c`. Also you need to modify the line 17 of `xdp-handler/fast_common.h`, the `CLUSTER_SIZE` should equals to $2f + 1$. 61 | 62 | Then you are able to run the code. Because our optimizations are kind of independent, which means you can specify which optimization to add, we control this by defining variables when building the project. Three optimizations are: `TC_BROADCAST`, `FAST_QUORUM_PRUNE`, and `FAST_REPLY`. 63 | 64 | Recompile the eBPF code, in `xdp-handler/`: 65 | 66 | make clean && make EXTRA_CFLAGS="-DTC_BROADCAST -DFAST_QUORUM_PRUNE -DFAST_REPLY" 67 | 68 | Recompile the Replica code: 69 | 70 | make clean && make CXXFLAGS="-DTC_BROADCAST -DFAST_QUORUM_PRUNE -DFAST_REPLY" 71 | 72 | Run the eBPF code, in `xdp-handler/`: 73 | 74 | sudo ./fast ens1f1np1 75 | 76 | Run the Replica-idx (eg, 0, 1, and 2 when `f`=1) on different replica machines: 77 | 78 | sudo taskset -c 1 ./bench/replica -c config.txt -m vr -i {idx} 79 | 80 | Then run the client on a separate client machine, n is the number of requests(you can also specify warmup by `-w` and # of clients by `-t`): 81 | 82 | ./bench/client -c config.txt -m vr -n 10000 83 | 84 | In the end of the client run, you can get the elapsed time (which can be used to calculate throughput) and latency. 85 | 86 | **NOTICE:** our code currently doesn't handle non-critical path cases like packet loss/reorder (which we do not observe in Cloudlab machines), machine failure, and network failure. 87 | 88 | ## Cite this work 89 | BibTex: 90 | 91 | @inproceedings{zhou2023electrode, 92 | title={{Electrode: Accelerating Distributed Protocols with eBPF}}, 93 | author={Zhou, Yang and Wang, Zezhou and Dharanipragada, Sowmya and Yu, Minlan}, 94 | booktitle={20th USENIX Symposium on Networked Systems Design and Implementation (NSDI 23)}, 95 | pages={1391--1407}, 96 | year={2023} 97 | } 98 | -------------------------------------------------------------------------------- /bench/.gitignore: -------------------------------------------------------------------------------- 1 | client 2 | replica 3 | -------------------------------------------------------------------------------- /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-benchmark) $(LIB-udptransport) 10 | 11 | $(d)replica: $(o)replica.o $(OBJS-spec-replica) $(OBJS-vr-replica) $(OBJS-fastpaxos-replica) $(OBJS-unreplicated-replica) $(LIB-udptransport) 12 | 13 | BINS += $(d)client $(d)replica 14 | -------------------------------------------------------------------------------- /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-2016 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 | string latencyFilename) 51 | : client(client), transport(transport), 52 | numRequests(numRequests), delay(delay), 53 | warmupSec(warmupSec), latencyFilename(latencyFilename) 54 | { 55 | if (delay != 0) { 56 | Notice("Delay between requests: %" PRIu64 " ms", delay); 57 | } 58 | started = false; 59 | done = false; 60 | cooldownDone = false; 61 | _Latency_Init(&latency, "op"); 62 | latencies.reserve(numRequests); 63 | } 64 | 65 | void 66 | BenchmarkClient::Start() 67 | { 68 | n = 0; 69 | transport.Timer(warmupSec * 1000, 70 | std::bind(&BenchmarkClient::WarmupDone, 71 | this)); 72 | SendNext(); 73 | } 74 | 75 | void 76 | BenchmarkClient::WarmupDone() 77 | { 78 | started = true; 79 | Notice("Completed warmup period of %d seconds with %d requests", 80 | warmupSec, n); 81 | gettimeofday(&startTime, NULL); 82 | n = 0; 83 | } 84 | 85 | void 86 | BenchmarkClient::CooldownDone() 87 | { 88 | 89 | char buf[1024]; 90 | cooldownDone = true; 91 | Notice("Finished cooldown period."); 92 | std::sort(latencies.begin(), latencies.end()); 93 | 94 | uint64_t ns = latencies[latencies.size()/2]; 95 | LatencyFmtNS(ns, buf); 96 | Notice("Median latency is %" PRIu64 " ns (%s)", ns, buf); 97 | 98 | ns = latencies[latencies.size()*90/100]; 99 | LatencyFmtNS(ns, buf); 100 | Notice("90th percentile latency is %" PRIu64 " ns (%s)", ns, buf); 101 | 102 | ns = latencies[latencies.size()*95/100]; 103 | LatencyFmtNS(ns, buf); 104 | Notice("95th percentile latency is %" PRIu64 " ns (%s)", ns, buf); 105 | 106 | ns = latencies[latencies.size()*99/100]; 107 | LatencyFmtNS(ns, buf); 108 | Notice("99th percentile latency is %" PRIu64 " ns (%s)", ns, buf); 109 | } 110 | 111 | void 112 | BenchmarkClient::SendNext() 113 | { 114 | std::ostringstream msg; 115 | msg << "request" << n; 116 | 117 | Latency_Start(&latency); 118 | client.Invoke(msg.str(), std::bind(&BenchmarkClient::OnReply, 119 | this, 120 | std::placeholders::_1, 121 | std::placeholders::_2)); 122 | } 123 | 124 | void 125 | BenchmarkClient::OnReply(const string &request, const string &reply) 126 | { 127 | if (cooldownDone) { 128 | return; 129 | } 130 | 131 | if ((started) && (!done) && (n != 0)) { 132 | uint64_t ns = Latency_End(&latency); 133 | latencies.push_back(ns); 134 | if (n > numRequests) { 135 | Finish(); 136 | } 137 | } 138 | 139 | n++; 140 | if (delay == 0) { 141 | SendNext(); 142 | } else { 143 | uint64_t rdelay = rand() % delay*2; 144 | transport.Timer(rdelay, 145 | std::bind(&BenchmarkClient::SendNext, this)); 146 | } 147 | } 148 | 149 | void 150 | BenchmarkClient::Finish() 151 | { 152 | gettimeofday(&endTime, NULL); 153 | 154 | struct timeval diff = timeval_sub(endTime, startTime); 155 | 156 | Notice("Completed %d requests in " FMT_TIMEVAL_DIFF " seconds", 157 | numRequests, VA_TIMEVAL_DIFF(diff)); 158 | done = true; 159 | 160 | transport.Timer(warmupSec * 1000, 161 | std::bind(&BenchmarkClient::CooldownDone, 162 | this)); 163 | 164 | 165 | if (latencyFilename.size() > 0) { 166 | Latency_FlushTo(latencyFilename.c_str()); 167 | } 168 | } 169 | 170 | 171 | } // namespace specpaxos 172 | -------------------------------------------------------------------------------- /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-2016 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 | string latencyFilename = ""); 44 | void Start(); 45 | void OnReply(const string &request, const string &reply); 46 | struct Latency_t latency; 47 | bool started; 48 | bool done; 49 | bool cooldownDone; 50 | std::vector latencies; 51 | 52 | private: 53 | void SendNext(); 54 | void Finish(); 55 | void WarmupDone(); 56 | void CooldownDone(); 57 | Client &client; 58 | Transport &transport; 59 | int numRequests; 60 | uint64_t delay; 61 | int n; 62 | int warmupSec; 63 | struct timeval startTime; 64 | struct timeval endTime; 65 | string latencyFilename; 66 | }; 67 | 68 | } // namespace specpaxos 69 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-2016 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 | clientid_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); 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 | { 68 | Panic("Received unexpected message type: %s", 69 | type.c_str()); 70 | } 71 | 72 | } // namespace specpaxos 73 | -------------------------------------------------------------------------------- /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-2016 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 | 38 | 39 | #include 40 | #include 41 | 42 | namespace specpaxos { 43 | 44 | typedef uint64_t clientid_t; 45 | #define FMT_CLIENTID "%" PRIx64 46 | 47 | class Client : public TransportReceiver 48 | { 49 | public: 50 | // just a function pointer? 51 | typedef std::function continuation_t; 52 | typedef std::function timeout_continuation_t; 53 | 54 | static const uint32_t DEFAULT_UNLOGGED_OP_TIMEOUT = 1000; // milliseconds 55 | 56 | Client(const Configuration &config, Transport *transport, 57 | clientid_t clientid = 0); 58 | virtual ~Client(); 59 | virtual void Invoke(const string &request, 60 | continuation_t continuation) = 0; 61 | virtual void InvokeUnlogged(int replicaIdx, 62 | const string &request, 63 | continuation_t continuation, 64 | timeout_continuation_t timeoutContinuation = nullptr, 65 | uint32_t timeout = DEFAULT_UNLOGGED_OP_TIMEOUT) = 0; 66 | virtual void ReceiveMessage(const TransportAddress &remote, 67 | const string &type, 68 | const string &data); 69 | 70 | protected: 71 | Configuration config; 72 | Transport *transport; 73 | 74 | clientid_t clientid; 75 | }; 76 | 77 | } // namespace specpaxos 78 | 79 | #endif /* _COMMON_CLIENT_H_ */ 80 | -------------------------------------------------------------------------------- /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-2016 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_LOG_IMPL_H_ 32 | #define _COMMON_LOG_IMPL_H_ 33 | 34 | template void 35 | Log::Dump(opnum_t from, T out) 36 | { 37 | for (opnum_t i = std::max(from, start); 38 | i <= LastOpnum(); i++) { 39 | 40 | const LogEntry *entry = Find(i); 41 | ASSERT(entry != NULL); 42 | 43 | auto elem = out->Add(); 44 | elem->set_view(entry->viewstamp.view); 45 | elem->set_opnum(entry->viewstamp.opnum); 46 | elem->set_state(entry->state); 47 | elem->set_hash(entry->hash); 48 | *(elem->mutable_request()) = entry->request; 49 | } 50 | } 51 | 52 | template void 53 | Log::Install(iter start, iter end) 54 | { 55 | // Find the first divergence in the log 56 | iter it = start; 57 | for (it = start; it != end; it++) { 58 | const LogEntry *oldEntry = Find(it->opnum()); 59 | if (oldEntry == NULL) { 60 | break; 61 | } 62 | if (it->view() != oldEntry->viewstamp.view) { 63 | RemoveAfter(it->opnum()); 64 | break; 65 | } 66 | } 67 | 68 | if (it == end) { 69 | // We didn't find a divergence. This means that the logs 70 | // should be identical. If the existing log is longer, 71 | // something is wrong. 72 | // it--; 73 | // ASSERT(it->opnum() == lastViewstamp.opnum); 74 | // ASSERT(it->view() == lastViewstamp.view); 75 | // ASSERT(Find(it->opnum()+1) == NULL); 76 | } 77 | 78 | // Install the new log entries 79 | for (; it != end; it++) { 80 | viewstamp_t vs = { it->view(), it->opnum() }; 81 | Append(vs, it->request(), LOG_STATE_PREPARED); 82 | } 83 | } 84 | 85 | #endif /* _COMMON_LOG_IMPL_H_ */ 86 | -------------------------------------------------------------------------------- /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-2016 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 | 51 | 52 | LogEntry & 53 | Log::Append(viewstamp_t vs, const Request &req, LogEntryState state) 54 | { 55 | if (entries.empty()) { 56 | ASSERT(vs.opnum == start); 57 | } else { 58 | ASSERT(vs.opnum == LastOpnum()+1); 59 | } 60 | 61 | string prevHash = LastHash(); 62 | entries.push_back(LogEntry(vs, state, req)); 63 | if (useHash) { 64 | entries.back().hash = ComputeHash(prevHash, entries.back()); 65 | } 66 | 67 | return entries.back(); 68 | } 69 | 70 | // This really ought to be const 71 | LogEntry * 72 | Log::Find(opnum_t opnum) 73 | { 74 | if (entries.empty()) { 75 | return NULL; 76 | } 77 | 78 | if (opnum < start) { 79 | return NULL; 80 | } 81 | 82 | if (opnum-start > entries.size()-1) { 83 | return NULL; 84 | } 85 | 86 | LogEntry *entry = &entries[opnum-start]; 87 | ASSERT(entry->viewstamp.opnum == opnum); 88 | return entry; 89 | } 90 | 91 | 92 | bool 93 | Log::SetStatus(opnum_t op, LogEntryState state) 94 | { 95 | LogEntry *entry = Find(op); 96 | if (entry == NULL) { 97 | return false; 98 | } 99 | 100 | entry->state = state; 101 | return true; 102 | } 103 | 104 | bool 105 | Log::SetRequest(opnum_t op, const Request &req) 106 | { 107 | if (useHash) { 108 | Panic("Log::SetRequest on hashed log not supported."); 109 | } 110 | 111 | LogEntry *entry = Find(op); 112 | if (entry == NULL) { 113 | return false; 114 | } 115 | 116 | entry->request = req; 117 | return true; 118 | } 119 | 120 | void 121 | Log::RemoveAfter(opnum_t op) 122 | { 123 | #if PARANOID 124 | // We'd better not be removing any committed entries. 125 | for (opnum_t i = op; i <= LastOpnum(); i++) { 126 | ASSERT(Find(i)->state != LOG_STATE_COMMITTED); 127 | } 128 | #endif 129 | 130 | if (op > LastOpnum()) { 131 | return; 132 | } 133 | 134 | Debug("Removing log entries after " FMT_OPNUM, op); 135 | 136 | ASSERT(op-start < entries.size()); 137 | entries.resize(op-start); 138 | 139 | ASSERT(LastOpnum() == op-1); 140 | } 141 | 142 | LogEntry * 143 | Log::Last() 144 | { 145 | if (entries.empty()) { 146 | return NULL; 147 | } 148 | 149 | return &entries.back(); 150 | } 151 | 152 | viewstamp_t 153 | Log::LastViewstamp() const 154 | { 155 | if (entries.empty()) { 156 | return viewstamp_t(0, start-1); 157 | } else { 158 | return entries.back().viewstamp; 159 | } 160 | } 161 | 162 | opnum_t 163 | Log::LastOpnum() const 164 | { 165 | if (entries.empty()) { 166 | return start-1; 167 | } else { 168 | return entries.back().viewstamp.opnum; 169 | } 170 | } 171 | 172 | opnum_t 173 | Log::FirstOpnum() const 174 | { 175 | // XXX Not really sure what's appropriate to return here if the 176 | // log is empty 177 | return start; 178 | } 179 | 180 | bool 181 | Log::Empty() const 182 | { 183 | return entries.empty(); 184 | } 185 | 186 | const string & 187 | Log::LastHash() const 188 | { 189 | if (entries.empty()) { 190 | return initialHash; 191 | } else { 192 | return entries.back().hash; 193 | } 194 | } 195 | 196 | string 197 | Log::ComputeHash(string lastHash, const LogEntry &entry) 198 | { 199 | SHA_CTX ctx; 200 | unsigned char out[SHA_DIGEST_LENGTH]; 201 | 202 | SHA1_Init(&ctx); 203 | 204 | SHA1_Update(&ctx, lastHash.c_str(), lastHash.size()); 205 | //SHA1_Update(&ctx, &entry.viewstamp, sizeof(entry.viewstamp)); 206 | uint64_t x[2]; 207 | x[0] = entry.request.clientid(); 208 | x[1] = entry.request.clientreqid(); 209 | SHA1_Update(&ctx, x, sizeof(uint64_t)*2); 210 | // SHA1_Update(&ctx, entry.request.op().c_str(), 211 | // entry.request.op().size()); 212 | 213 | SHA1_Final(out, &ctx); 214 | 215 | return string((char *)out, SHA_DIGEST_LENGTH); 216 | } 217 | 218 | } // namespace specpaxos 219 | -------------------------------------------------------------------------------- /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-2016 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_LOG_H_ 32 | #define _COMMON_LOG_H_ 33 | 34 | #include "common/request.pb.h" 35 | #include "lib/assert.h" 36 | #include "lib/message.h" 37 | #include "lib/transport.h" 38 | #include "lib/viewstamp.h" 39 | 40 | #include 41 | #include 42 | 43 | namespace specpaxos { 44 | 45 | enum LogEntryState { 46 | LOG_STATE_COMMITTED, 47 | LOG_STATE_PREPARED, 48 | LOG_STATE_SPECULATIVE, // specpaxos only 49 | LOG_STATE_FASTPREPARED // fastpaxos only 50 | }; 51 | 52 | 53 | class Log 54 | { 55 | 56 | public: 57 | struct LogEntry 58 | { 59 | viewstamp_t viewstamp; 60 | LogEntryState state; 61 | Request request; 62 | string hash; 63 | // Speculative client table stuff 64 | opnum_t prevClientReqOpnum; 65 | ::google::protobuf::Message *replyMessage; 66 | 67 | LogEntry() { replyMessage = NULL; } 68 | LogEntry(const LogEntry &x) 69 | : viewstamp(x.viewstamp), state(x.state), request(x.request), 70 | hash(x.hash), prevClientReqOpnum(x.prevClientReqOpnum) 71 | { 72 | if (x.replyMessage) { 73 | replyMessage = x.replyMessage->New(); 74 | replyMessage->CopyFrom(*x.replyMessage); 75 | } else { 76 | replyMessage = NULL; 77 | } 78 | } 79 | LogEntry(viewstamp_t viewstamp, LogEntryState state, 80 | const Request &request, const string &hash=Log::EMPTY_HASH) 81 | : viewstamp(viewstamp), state(state), request(request), 82 | hash(hash), replyMessage(NULL) { } 83 | virtual ~LogEntry() 84 | { 85 | if (replyMessage) { 86 | delete replyMessage; 87 | } 88 | } 89 | }; 90 | 91 | Log(bool useHash, opnum_t start = 1, string initialHash = EMPTY_HASH); 92 | LogEntry & Append(viewstamp_t vs, const Request &req, LogEntryState state); 93 | LogEntry * Find(opnum_t opnum); 94 | bool SetStatus(opnum_t opnum, LogEntryState state); 95 | bool SetRequest(opnum_t op, const Request &req); 96 | void RemoveAfter(opnum_t opnum); 97 | LogEntry * Last(); 98 | viewstamp_t LastViewstamp() const; // deprecated 99 | opnum_t LastOpnum() const; 100 | opnum_t FirstOpnum() const; 101 | bool Empty() const; 102 | template void Dump(opnum_t from, T out); 103 | template void Install(iter start, iter end); 104 | const string &LastHash() const; 105 | 106 | static string ComputeHash(string lastHash, const LogEntry &entry); 107 | static const string EMPTY_HASH; 108 | 109 | 110 | private: 111 | std::vector entries; 112 | string initialHash; 113 | opnum_t start; 114 | bool useHash; 115 | }; 116 | 117 | typedef Log::LogEntry LogEntry; 118 | 119 | #include "common/log-impl.h" 120 | 121 | } // namespace specpaxos 122 | 123 | #endif /* _COMMON_LOG_H_ */ 124 | -------------------------------------------------------------------------------- /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-2016 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 | -------------------------------------------------------------------------------- /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-2016 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 | { 40 | string res; 41 | ReplicaUpcall(opnum, msg.op(), res); 42 | 43 | reply.set_reply(res); 44 | } 45 | 46 | template 47 | void 48 | Replica::ExecuteUnlogged(const UnloggedRequest &msg, 49 | MSG &reply) 50 | { 51 | string res; 52 | UnloggedUpcall(msg.op(), res); 53 | 54 | reply.set_reply(res); 55 | } 56 | 57 | #endif // _COMMON_REPLICA_INL_H_ 58 | -------------------------------------------------------------------------------- /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-2016 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 myIdx, 42 | bool initialize, 43 | Transport *transport, AppReplica *app) 44 | : configuration(configuration), myIdx(myIdx), 45 | transport(transport), app(app) 46 | { 47 | transport->Register(this, configuration, myIdx); 48 | } 49 | 50 | Replica::~Replica() 51 | { 52 | 53 | } 54 | 55 | void 56 | Replica::LeaderUpcall(opnum_t opnum, const string &op, bool &replicate, string &res) 57 | { 58 | app->LeaderUpcall(opnum, op, replicate, res); 59 | } 60 | 61 | void 62 | Replica::ReplicaUpcall(opnum_t opnum, const string &op, string &res) 63 | { 64 | Debug("Making upcall for operation %s", op.c_str()); 65 | app->ReplicaUpcall(opnum, op, res); 66 | 67 | Debug("Upcall result: %s", res.c_str()); 68 | } 69 | 70 | void 71 | Replica::Rollback(opnum_t current, opnum_t to, Log &log) 72 | { 73 | Debug("Making rollback-upcall from " FMT_OPNUM " to " FMT_OPNUM, 74 | current, to); 75 | 76 | std::map reqs; 77 | for (opnum_t x = current; x > to; x--) { 78 | reqs.insert(std::pair(x, 79 | log.Find(x)->request.op())); 80 | } 81 | 82 | app->RollbackUpcall(current, to, reqs); 83 | } 84 | 85 | void 86 | Replica::Commit(opnum_t op) 87 | { 88 | app->CommitUpcall(op); 89 | } 90 | 91 | void 92 | Replica::UnloggedUpcall(const string &op, string &res) 93 | { 94 | app->UnloggedUpcall(op, res); 95 | } 96 | 97 | } // namespace specpaxos 98 | -------------------------------------------------------------------------------- /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-2016 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/client.h" 37 | #include "common/log.h" 38 | #include "common/request.pb.h" 39 | #include "lib/transport.h" 40 | #include "lib/viewstamp.h" 41 | 42 | namespace specpaxos { 43 | 44 | class Replica; 45 | 46 | enum ReplicaStatus { 47 | STATUS_NORMAL, 48 | STATUS_VIEW_CHANGE, 49 | STATUS_RECOVERING 50 | }; 51 | 52 | class AppReplica 53 | { 54 | public: 55 | AppReplica() { }; 56 | virtual ~AppReplica() { }; 57 | // Invoke callback on the leader, with the option to replicate on success 58 | virtual void LeaderUpcall(opnum_t opnum, const string &str1, bool &replicate, string &str2) { replicate = true; str2 = str1; }; 59 | // Invoke callback on all replicas 60 | virtual void ReplicaUpcall(opnum_t opnum, const string &str1, string &str2) { }; 61 | // Rollback callback on failed speculative operations 62 | virtual void RollbackUpcall(opnum_t current, opnum_t to, const std::map &opMap) { }; 63 | // Commit callback to commit speculative operations 64 | virtual void CommitUpcall(opnum_t) { }; 65 | // Invoke call back for unreplicated operations run on only one replica 66 | virtual void UnloggedUpcall(const string &str1, string &str2) { }; 67 | }; 68 | 69 | class Replica : public TransportReceiver 70 | { 71 | public: 72 | Replica(const Configuration &config, int myIdx, bool initialize, 73 | Transport *transport, AppReplica *app); 74 | virtual ~Replica(); 75 | 76 | protected: 77 | void LeaderUpcall(opnum_t opnum, const string &op, bool &replicate, string &res); 78 | void ReplicaUpcall(opnum_t opnum, const string &op, string &res); 79 | template void Execute(opnum_t opnum, 80 | const Request & msg, 81 | MSG &reply); 82 | void Rollback(opnum_t current, opnum_t to, Log &log); 83 | void Commit(opnum_t op); 84 | void UnloggedUpcall(const string &op, string &res); 85 | template void ExecuteUnlogged(const UnloggedRequest & msg, 86 | MSG &reply); 87 | 88 | protected: 89 | Configuration configuration; 90 | int myIdx; 91 | Transport *transport; 92 | AppReplica *app; 93 | ReplicaStatus status; 94 | }; 95 | 96 | #include "replica-inl.h" 97 | 98 | } // namespace specpaxos 99 | 100 | #endif /* _COMMON_REPLICA_H */ 101 | -------------------------------------------------------------------------------- /common/request.proto: -------------------------------------------------------------------------------- 1 | package specpaxos; 2 | 3 | message Request { 4 | required bytes op = 1; 5 | required uint64 clientid = 2; 6 | required uint64 clientreqid = 3; 7 | } 8 | 9 | message UnloggedRequest { 10 | required bytes op = 1; 11 | required uint64 clientid = 2; 12 | required uint64 clientreqid = 3; 13 | } 14 | -------------------------------------------------------------------------------- /common/tests/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | -------------------------------------------------------------------------------- /config.txt: -------------------------------------------------------------------------------- 1 | f 1 2 | replica 10.10.1.3:12345 3 | replica 10.10.1.4:12345 4 | replica 10.10.1.1:12345 -------------------------------------------------------------------------------- /env.sh: -------------------------------------------------------------------------------- 1 | BMCCACHE_BASE_PATH="$(readlink -f $( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd ))" 2 | BMCCACHE_KERNEL_VERSION="5.8" 3 | BMCCACHE_KERNEL_TARXZ="${BMCCACHE_BASE_PATH}/linux-${BMCCACHE_KERNEL_VERSION}.tar.xz" 4 | BMCCACHE_BMC_PATH="${BMCCACHE_BASE_PATH}/xdp-handler" 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-2016 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 | 58 | protected: 59 | int view; 60 | int opnumber; 61 | uint64_t lastReqId; 62 | 63 | struct PendingRequest 64 | { 65 | string request; 66 | uint64_t clientReqId; 67 | continuation_t continuation; 68 | timeout_continuation_t timeoutContinuation; 69 | inline PendingRequest(string request, uint64_t clientReqId, 70 | continuation_t continuation) 71 | : request(request), clientReqId(clientReqId), 72 | continuation(continuation) { } 73 | }; 74 | PendingRequest *pendingRequest; 75 | PendingRequest *pendingUnloggedRequest; 76 | Timeout *requestTimeout; 77 | Timeout *unloggedRequestTimeout; 78 | 79 | void SendRequest(); 80 | void ResendRequest(); 81 | void HandleReply(const TransportAddress &remote, 82 | const proto::ReplyMessage &msg); 83 | void HandleUnloggedReply(const TransportAddress &remote, 84 | const proto::UnloggedReplyMessage &msg); 85 | void UnloggedRequestTimeoutCallback(); 86 | }; 87 | 88 | } // namespace specpaxos::fastpaxos 89 | } // namespace specpaxos 90 | 91 | #endif /* _FASTPAXOS_CLIENT_H_ */ 92 | -------------------------------------------------------------------------------- /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 | message LogEntry { 51 | required uint64 view = 1; 52 | required uint64 opnum = 2; 53 | required specpaxos.Request request = 3; 54 | optional uint32 state = 4; 55 | optional bytes hash = 5; 56 | } 57 | required uint64 view = 1; 58 | required uint64 opnum = 2; 59 | repeated LogEntry entries = 3; 60 | required uint64 lastop = 4; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /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-2016 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 | 57 | private: 58 | view_t view; 59 | opnum_t lastCommitted; 60 | opnum_t lastFastPath; 61 | opnum_t lastSlowPath; 62 | view_t lastRequestStateTransferView; 63 | opnum_t lastRequestStateTransferOpnum; 64 | std::list > pendingPrepares; 66 | std::list > pendingPrepareOKs; 68 | proto::PrepareMessage lastPrepare; 69 | 70 | Log log; 71 | std::map > clientAddresses; 72 | struct ClientTableEntry 73 | { 74 | uint64_t lastReqId; 75 | bool replied; 76 | proto::ReplyMessage reply; 77 | }; 78 | std::map clientTable; 79 | 80 | QuorumSet slowPrepareOKQuorum; 81 | QuorumSet fastPrepareOKQuorum; 82 | 83 | Timeout *stateTransferTimeout; 84 | Timeout *resendPrepareTimeout; 85 | 86 | bool AmLeader() const; 87 | void CommitUpTo(opnum_t upto); 88 | void SendPrepareOKs(opnum_t oldLastOp); 89 | void RequestStateTransfer(); 90 | void EnterView(view_t newview); 91 | void UpdateClientTable(const Request &req); 92 | void ResendPrepare(); 93 | 94 | void HandleRequest(const TransportAddress &remote, 95 | const proto::RequestMessage &msg); 96 | void HandleUnloggedRequest(const TransportAddress &remote, 97 | const proto::UnloggedRequestMessage &msg); 98 | 99 | void HandlePrepare(const TransportAddress &remote, 100 | const proto::PrepareMessage &msg); 101 | void HandlePrepareOK(const TransportAddress &remote, 102 | const proto::PrepareOKMessage &msg); 103 | void HandleCommit(const TransportAddress &remote, 104 | const proto::CommitMessage &msg); 105 | void HandleRequestStateTransfer(const TransportAddress &remote, 106 | const proto::RequestStateTransferMessage &msg); 107 | void HandleStateTransfer(const TransportAddress &remote, 108 | const proto::StateTransferMessage &msg); 109 | }; 110 | 111 | } // namespace specpaxos::vr 112 | } // namespace specpaxos 113 | 114 | #endif /* _FASTPAXOS_REPLICA_H_ */ 115 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /kernel-src-prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -------------------- 3 | # From BMC: https://github.com/Orange-OpenSource/bmc-cache 4 | # 5 | # Run this script to extract and generate kernel sources files required to compile BMC 6 | # -------------------- 7 | source "$(dirname "$(readlink -f "$0")")/env.sh" 8 | 9 | echo "Extracting kernel sources to ${BMCCACHE_BMC_PATH}/linux" 10 | if tar xf ${BMCCACHE_KERNEL_TARXZ} -C ${BMCCACHE_BMC_PATH} && mv ${BMCCACHE_BMC_PATH}/linux-${BMCCACHE_KERNEL_VERSION} ${BMCCACHE_BMC_PATH}/linux; then 11 | echo "Successfully extracted kernel sources to ${BMCCACHE_BMC_PATH}/linux" 12 | else 13 | echo "Failed to extract kernel sources" 14 | exit 1 15 | fi 16 | 17 | echo "Preparing kernel sources" 18 | if make -C ${BMCCACHE_BMC_PATH}/linux defconfig && make -C ${BMCCACHE_BMC_PATH}/linux prepare; then 19 | echo "Done preparing kernel sources" 20 | else 21 | echo "Failed to prepare kernel sources" 22 | exit 1 23 | fi -------------------------------------------------------------------------------- /kernel-src-remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # -------------------- 3 | # From BMC: https://github.com/Orange-OpenSource/bmc-cache 4 | # 5 | # Run this script to delete downloaded kernel sources 6 | # -------------------- 7 | source "$(dirname "$(readlink -f "$0")")/env.sh" 8 | 9 | if [[ -f ${BMCCACHE_KERNEL_TARXZ} ]]; then 10 | echo "Deleting ${BMCCACHE_KERNEL_TARXZ}" 11 | rm -rf ${BMCCACHE_KERNEL_TARXZ} 12 | fi 13 | 14 | if [[ -d "${BMCCACHE_BMC_PATH}/linux" ]]; then 15 | echo "Deleting ${BMCCACHE_BMC_PATH}/linux" 16 | rm -rf "${BMCCACHE_BMC_PATH}/linux" 17 | fi 18 | 19 | echo "Finished cleaning up." 20 | -------------------------------------------------------------------------------- /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 | 7 | PROTOS += $(addprefix $(d), \ 8 | latency-format.proto) 9 | 10 | LIB-hash := $(o)lookup3.o 11 | 12 | LIB-message := $(o)message.o $(LIB-hash) 13 | 14 | LIB-hashtable := $(LIB-hash) $(LIB-message) 15 | 16 | LIB-memory := $(o)memory.o 17 | 18 | LIB-latency := $(o)latency.o $(o)latency-format.o $(LIB-message) 19 | 20 | LIB-configuration := $(o)configuration.o $(LIB-message) 21 | 22 | LIB-transport := $(o)transport.o $(LIB-message) $(LIB-configuration) 23 | 24 | LIB-simtransport := $(o)simtransport.o $(LIB-transport) 25 | 26 | LIB-udptransport := $(o)udptransport.o $(LIB-transport) 27 | 28 | 29 | include $(d)tests/Rules.mk 30 | -------------------------------------------------------------------------------- /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-2016 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/configuration.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * configuration.cc: 5 | * Representation of a replica group configuration, i.e. the number 6 | * and list of replicas in the group 7 | * 8 | * Copyright 2013-2016 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 "lib/assert.h" 33 | #include "lib/configuration.h" 34 | #include "lib/message.h" 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | namespace specpaxos { 42 | 43 | ReplicaAddress::ReplicaAddress(const string &host, const string &port) 44 | : host(host), port(port) 45 | { 46 | 47 | } 48 | 49 | bool 50 | ReplicaAddress::operator==(const ReplicaAddress &other) const { 51 | return ((host == other.host) && 52 | (port == other.port)); 53 | } 54 | 55 | 56 | Configuration::Configuration(const Configuration &c) 57 | : n(c.n), f(c.f), replicas(c.replicas), hasMulticast(c.hasMulticast) 58 | { 59 | multicastAddress = NULL; 60 | if (hasMulticast) { 61 | multicastAddress = new ReplicaAddress(*c.multicastAddress); 62 | } 63 | } 64 | 65 | Configuration::Configuration(int n, int f, 66 | std::vector replicas, 67 | ReplicaAddress *multicastAddress) 68 | : n(n), f(f), replicas(replicas) 69 | { 70 | if (multicastAddress) { 71 | hasMulticast = true; 72 | this->multicastAddress = 73 | new ReplicaAddress(*multicastAddress); 74 | } else { 75 | hasMulticast = false; 76 | multicastAddress = NULL; 77 | } 78 | } 79 | 80 | Configuration::Configuration(std::ifstream &file) 81 | { 82 | f = -1; 83 | hasMulticast = false; 84 | multicastAddress = NULL; 85 | 86 | while (!file.eof()) { 87 | // Read a line 88 | string line; 89 | getline(file, line);; 90 | 91 | // Ignore comments 92 | if ((line.size() == 0) || (line[0] == '#')) { 93 | continue; 94 | } 95 | 96 | // Get the command 97 | // This is pretty horrible, but C++ does promise that &line[0] 98 | // is going to be a mutable contiguous buffer... 99 | char *cmd = strtok(&line[0], " \t"); 100 | 101 | if (strcasecmp(cmd, "f") == 0) { 102 | char *arg = strtok(NULL, " \t"); 103 | if (!arg) { 104 | Panic ("'f' configuration line requires an argument"); 105 | } 106 | char *strtolPtr; 107 | f = strtoul(arg, &strtolPtr, 0); 108 | if ((*arg == '\0') || (*strtolPtr != '\0')) { 109 | Panic("Invalid argument to 'f' configuration line"); 110 | } 111 | } else if (strcasecmp(cmd, "replica") == 0) { 112 | char *arg = strtok(NULL, " \t"); 113 | if (!arg) { 114 | Panic ("'replica' configuration line requires an argument"); 115 | } 116 | 117 | char *host = strtok(arg, ":"); 118 | char *port = strtok(NULL, ""); 119 | 120 | if (!host || !port) { 121 | Panic("Configuration line format: 'replica host:port'"); 122 | } 123 | 124 | replicas.push_back(ReplicaAddress(string(host), string(port))); 125 | } else if (strcasecmp(cmd, "multicast") == 0) { 126 | char *arg = strtok(NULL, " \t"); 127 | if (!arg) { 128 | Panic ("'multicast' configuration line requires an argument"); 129 | } 130 | 131 | char *host = strtok(arg, ":"); 132 | char *port = strtok(NULL, ""); 133 | 134 | if (!host || !port) { 135 | Panic("Configuration line format: 'multicast host:port'"); 136 | } 137 | 138 | multicastAddress = new ReplicaAddress(string(host), 139 | string(port)); 140 | hasMulticast = true; 141 | } else { 142 | Panic("Unknown configuration directive: %s", cmd); 143 | } 144 | } 145 | 146 | n = replicas.size(); 147 | if (n == 0) { 148 | Panic("Configuration did not specify any replicas"); 149 | } 150 | 151 | if (f == -1) { 152 | Panic("Configuration did not specify a 'f' parameter"); 153 | } 154 | } 155 | 156 | Configuration::~Configuration() 157 | { 158 | if (hasMulticast) { 159 | delete multicastAddress; 160 | } 161 | } 162 | 163 | ReplicaAddress 164 | Configuration::replica(int idx) const 165 | { 166 | return replicas[idx]; 167 | } 168 | 169 | const ReplicaAddress * 170 | Configuration::multicast() const 171 | { 172 | if (hasMulticast) { 173 | return multicastAddress; 174 | } else { 175 | return nullptr; 176 | } 177 | } 178 | 179 | int 180 | Configuration::QuorumSize() const 181 | { 182 | return f+1; 183 | } 184 | 185 | int 186 | Configuration::FastQuorumSize() const 187 | { 188 | return f + (f+1)/2 + 1; 189 | } 190 | 191 | bool 192 | Configuration::operator==(const Configuration &other) const 193 | { 194 | if ((n != other.n) || 195 | (f != other.f) || 196 | (replicas != other.replicas) || 197 | (hasMulticast != other.hasMulticast)) { 198 | return false; 199 | } 200 | 201 | if (hasMulticast) { 202 | if (*multicastAddress != *other.multicastAddress) { 203 | return false; 204 | } 205 | } 206 | 207 | return true; 208 | } 209 | 210 | } // namespace specpaxos 211 | -------------------------------------------------------------------------------- /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-2016 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 | 42 | using std::string; 43 | 44 | namespace specpaxos { 45 | 46 | struct ReplicaAddress 47 | { 48 | string host; 49 | string port; 50 | ReplicaAddress(const string &host, const string &port); 51 | bool operator==(const ReplicaAddress &other) const; 52 | inline bool operator!=(const ReplicaAddress &other) const { 53 | return !(*this == other); 54 | } 55 | }; 56 | 57 | 58 | class Configuration 59 | { 60 | public: 61 | Configuration(const Configuration &c); 62 | Configuration(int n, int f, std::vector replicas, 63 | ReplicaAddress *multicastAddress = nullptr); 64 | Configuration(std::ifstream &file); 65 | virtual ~Configuration(); 66 | ReplicaAddress replica(int idx) const; 67 | const ReplicaAddress *multicast() const; 68 | inline int GetLeaderIndex(view_t view) const { 69 | return (view % n); 70 | }; 71 | int QuorumSize() const; 72 | int FastQuorumSize() const; 73 | bool operator==(const Configuration &other) const; 74 | inline bool operator!= (const Configuration &other) const { 75 | return !(*this == other); 76 | } 77 | 78 | public: 79 | int n; // number of replicas 80 | int f; // number of failures tolerated 81 | private: 82 | std::vector replicas; 83 | ReplicaAddress *multicastAddress; 84 | bool hasMulticast; 85 | }; 86 | 87 | } // namespace specpaxos 88 | 89 | namespace std { 90 | template <> struct hash 91 | { 92 | size_t operator()(const specpaxos::ReplicaAddress & x) const 93 | { 94 | return hash()(x.host) * 37 + hash()(x.port); 95 | } 96 | }; 97 | } 98 | 99 | namespace std { 100 | template <> struct hash 101 | { 102 | size_t operator()(const specpaxos::Configuration & x) const 103 | { 104 | size_t out = 0; 105 | out = x.n * 37 + x.f; 106 | for (int i = 0; i < x.n; i++) { 107 | out *= 37; 108 | out += hash()(x.replica(i)); 109 | } 110 | return out; 111 | } 112 | }; 113 | } 114 | 115 | 116 | #endif /* _LIB_CONFIGURATION_H_ */ 117 | -------------------------------------------------------------------------------- /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-2016 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-2016 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 | -------------------------------------------------------------------------------- /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-2016 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/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-2016 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 | -------------------------------------------------------------------------------- /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-2016 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 | -------------------------------------------------------------------------------- /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-2016 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_SIMTRANSPORT_H_ 32 | #define _LIB_SIMTRANSPORT_H_ 33 | 34 | #include "lib/transport.h" 35 | #include "lib/transportcommon.h" 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | class SimulatedTransportAddress : public TransportAddress 42 | { 43 | public: 44 | SimulatedTransportAddress * clone() const; 45 | int GetAddr() const; 46 | bool operator==(const SimulatedTransportAddress &other) const; 47 | inline bool operator!=(const SimulatedTransportAddress &other) const 48 | { 49 | return !(*this == other); 50 | } 51 | private: 52 | SimulatedTransportAddress(int addr); 53 | 54 | int addr; 55 | friend class SimulatedTransport; 56 | }; 57 | 58 | class SimulatedTransport : 59 | public TransportCommon 60 | { 61 | typedef std::function filter_t; 64 | public: 65 | SimulatedTransport(); 66 | ~SimulatedTransport(); 67 | void Register(TransportReceiver *receiver, 68 | const specpaxos::Configuration &config, 69 | int replicaIdx); 70 | void Run(); 71 | void AddFilter(int id, filter_t filter); 72 | void RemoveFilter(int id); 73 | int Timer(uint64_t ms, timer_callback_t cb); 74 | bool CancelTimer(int id); 75 | void CancelAllTimers(); 76 | 77 | protected: 78 | bool SendMessageInternal(TransportReceiver *src, 79 | const SimulatedTransportAddress &dstAddr, 80 | const Message &m, 81 | bool multicast); 82 | 83 | SimulatedTransportAddress 84 | LookupAddress(const specpaxos::Configuration &cfg, int idx); 85 | const SimulatedTransportAddress * 86 | LookupMulticastAddress(const specpaxos::Configuration *cfg); 87 | 88 | private: 89 | struct QueuedMessage { 90 | int dst; 91 | int src; 92 | string type; 93 | string msg; 94 | inline QueuedMessage(int dst, int src, 95 | const string &type, const string &msg) : 96 | dst(dst), src(src), type(type), msg(msg) { } 97 | }; 98 | struct PendingTimer { 99 | uint64_t when; 100 | int id; 101 | timer_callback_t cb; 102 | }; 103 | 104 | std::deque queue; 105 | std::map endpoints; 106 | int lastAddr; 107 | // std::map replicas; 108 | std::map replicaIdxs; 109 | std::multimap filters; 110 | std::multimap timers; 111 | int lastTimerId; 112 | uint64_t vtime; 113 | bool processTimers; 114 | }; 115 | 116 | #endif // _LIB_SIMTRANSPORT_H_ 117 | -------------------------------------------------------------------------------- /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 | 10 | PROTOS += $(d)simtransport-testmessage.proto 11 | 12 | $(d)configuration-test: $(o)configuration-test.o $(LIB-configuration) $(GTEST_MAIN) 13 | 14 | TEST_BINS += $(d)configuration-test 15 | 16 | $(d)simtransport-test: $(o)simtransport-test.o $(LIB-simtransport) $(o)simtransport-testmessage.o $(GTEST_MAIN) 17 | 18 | TEST_BINS += $(d)simtransport-test 19 | -------------------------------------------------------------------------------- /lib/tests/configuration-test-1.conf: -------------------------------------------------------------------------------- 1 | # This is a test configuration file 2 | f 1 3 | replica localhost:12345 4 | replica localhost:12346 5 | replica localhost:12347 6 | multicast localhost:12348 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/tests/simtransport-testmessage.proto: -------------------------------------------------------------------------------- 1 | package specpaxos.test; 2 | 3 | message TestMessage { 4 | required string test = 1; 5 | } 6 | -------------------------------------------------------------------------------- /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-2016 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", (long) tv.tv_usec); 83 | return buf; 84 | } 85 | 86 | #define FMT_TIMEVAL_DIFF "%lld.%06ld" 87 | #define VA_TIMEVAL_DIFF(t) (long long)t.tv_sec, (long) t.tv_usec 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /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-2016 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 | -------------------------------------------------------------------------------- /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-2016 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 | 39 | class TransportAddress 40 | { 41 | public: 42 | virtual ~TransportAddress() { } 43 | virtual TransportAddress *clone() const = 0; 44 | }; 45 | 46 | class TransportReceiver 47 | { 48 | protected: 49 | typedef ::google::protobuf::Message Message; 50 | 51 | public: 52 | virtual ~TransportReceiver(); 53 | virtual void SetAddress(const TransportAddress *addr); 54 | virtual const TransportAddress& GetAddress(); 55 | 56 | virtual void ReceiveMessage(const TransportAddress &remote, 57 | const string &type, const string &data) = 0; 58 | 59 | 60 | protected: 61 | const TransportAddress *myAddress; 62 | }; 63 | 64 | typedef std::function timer_callback_t; 65 | 66 | class Transport 67 | { 68 | protected: 69 | typedef ::google::protobuf::Message Message; 70 | public: 71 | virtual ~Transport() {} 72 | virtual void Register(TransportReceiver *receiver, 73 | const specpaxos::Configuration &config, 74 | int replicaIdx) = 0; 75 | virtual bool SendMessage(TransportReceiver *src, const TransportAddress &dst, 76 | const Message &m) = 0; 77 | virtual bool SendMessageToReplica(TransportReceiver *src, int replicaIdx, const Message &m, 78 | const void *my_buf = NULL) = 0; 79 | virtual bool SendMessageToAll(TransportReceiver *src, const Message &m, 80 | const void *my_buf = NULL) = 0; //asd123www: myadd. 81 | virtual int Timer(uint64_t ms, timer_callback_t cb) = 0; 82 | virtual bool CancelTimer(int id) = 0; 83 | virtual void CancelAllTimers() = 0; 84 | }; 85 | 86 | class Timeout 87 | { 88 | public: 89 | Timeout(Transport *transport, uint64_t ms, timer_callback_t cb); 90 | virtual ~Timeout(); 91 | virtual void SetTimeout(uint64_t ms); 92 | virtual uint64_t Start(); 93 | virtual uint64_t Reset(); 94 | virtual void Stop(); 95 | virtual bool Active() const; 96 | 97 | private: 98 | Transport *transport; 99 | uint64_t ms; 100 | timer_callback_t cb; 101 | int timerId; 102 | }; 103 | 104 | #endif // _LIB_TRANSPORT_H_ 105 | -------------------------------------------------------------------------------- /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-2016 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 | 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | class UDPTransportAddress : public TransportAddress 49 | { 50 | public: 51 | UDPTransportAddress(const sockaddr_in &addr); 52 | UDPTransportAddress * clone() const; 53 | private: 54 | sockaddr_in addr; 55 | friend class UDPTransport; 56 | friend bool operator==(const UDPTransportAddress &a, 57 | const UDPTransportAddress &b); 58 | friend bool operator!=(const UDPTransportAddress &a, 59 | const UDPTransportAddress &b); 60 | friend bool operator<(const UDPTransportAddress &a, 61 | const UDPTransportAddress &b); 62 | }; 63 | 64 | class UDPTransport : public TransportCommon 65 | { 66 | public: 67 | UDPTransport(double dropRate = 0.0, double reorderRate = 0.0, 68 | int dscp = 0, event_base *evbase = nullptr); 69 | virtual ~UDPTransport(); 70 | void Register(TransportReceiver *receiver, 71 | const specpaxos::Configuration &config, 72 | int replicaIdx); 73 | void Run(); 74 | int Timer(uint64_t ms, timer_callback_t cb); 75 | bool CancelTimer(int id); 76 | void CancelAllTimers(); 77 | 78 | private: 79 | struct UDPTransportTimerInfo 80 | { 81 | UDPTransport *transport; 82 | timer_callback_t cb; 83 | event *ev; 84 | int id; 85 | }; 86 | 87 | double dropRate; 88 | double reorderRate; 89 | std::uniform_real_distribution uniformDist; 90 | std::default_random_engine randomEngine; 91 | struct 92 | { 93 | bool valid; 94 | UDPTransportAddress *addr; 95 | string msgType; 96 | string message; 97 | int fd; 98 | } reorderBuffer; 99 | int dscp; 100 | 101 | event_base *libeventBase; 102 | std::vector listenerEvents; 103 | std::vector signalEvents; 104 | std::map receivers; // fd -> receiver 105 | std::map fds; // receiver -> fd 106 | std::map multicastFds; 107 | std::map multicastConfigs; 108 | int lastTimerId; 109 | std::map timers; 110 | uint64_t lastFragMsgId; 111 | struct UDPTransportFragInfo 112 | { 113 | uint64_t msgId; 114 | string data; 115 | }; 116 | std::map fragInfo; 117 | 118 | bool SendMessageInternal(TransportReceiver *src, 119 | const UDPTransportAddress &dst, 120 | const Message &m, bool multicast = false, 121 | const void *my_buf = NULL); 122 | 123 | UDPTransportAddress 124 | LookupAddress(const specpaxos::ReplicaAddress &addr); 125 | UDPTransportAddress 126 | LookupAddress(const specpaxos::Configuration &cfg, 127 | int replicaIdx); 128 | const UDPTransportAddress * 129 | LookupMulticastAddress(const specpaxos::Configuration *cfg); 130 | void ListenOnMulticastPort(const specpaxos::Configuration 131 | *canonicalConfig); 132 | void OnReadable(int fd); 133 | void OnTimer(UDPTransportTimerInfo *info); 134 | static void SocketCallback(evutil_socket_t fd, 135 | short what, void *arg); 136 | static void TimerCallback(evutil_socket_t fd, 137 | short what, void *arg); 138 | static void LogCallback(int severity, const char *msg); 139 | static void FatalCallback(int err); 140 | static void SignalCallback(evutil_socket_t fd, 141 | short what, void *arg); 142 | }; 143 | 144 | #endif // _LIB_UDPTRANSPORT_H_ 145 | -------------------------------------------------------------------------------- /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-2016 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 | 41 | struct viewstamp_t 42 | { 43 | view_t view; 44 | opnum_t opnum; 45 | 46 | viewstamp_t() : view(0), opnum(0) {} 47 | viewstamp_t(view_t view, opnum_t opnum) : view(view), opnum(opnum) {} 48 | }; 49 | 50 | #define FMT_VIEW "%" PRIu64 51 | #define FMT_OPNUM "%" PRIu64 52 | 53 | #define FMT_VIEWSTAMP "<" FMT_VIEW "," FMT_OPNUM ">" 54 | #define VA_VIEWSTAMP(x) x.view, x.opnum 55 | 56 | static inline int 57 | Viewstamp_Compare(viewstamp_t a, viewstamp_t b) 58 | { 59 | if (a.view < b.view) return -1; 60 | if (a.view > b.view) return 1; 61 | if (a.opnum < b.opnum) return -1; 62 | if (a.opnum > b.opnum) return 1; 63 | return 0; 64 | } 65 | 66 | inline bool operator==(const viewstamp_t& lhs, const viewstamp_t& rhs){ return Viewstamp_Compare(lhs,rhs) == 0; } 67 | inline bool operator!=(const viewstamp_t& lhs, const viewstamp_t& rhs){return !operator==(lhs,rhs);} 68 | inline bool operator< (const viewstamp_t& lhs, const viewstamp_t& rhs){ return Viewstamp_Compare(lhs,rhs) < 0; } 69 | inline bool operator> (const viewstamp_t& lhs, const viewstamp_t& rhs){return operator< (rhs,lhs);} 70 | inline bool operator<=(const viewstamp_t& lhs, const viewstamp_t& rhs){return !operator> (lhs,rhs);} 71 | inline bool operator>=(const viewstamp_t& lhs, const viewstamp_t& rhs){return !operator< (lhs,rhs);} 72 | 73 | #endif /* _LIB_VIEWSTAMP_H_ */ 74 | -------------------------------------------------------------------------------- /nistore/.gitignore: -------------------------------------------------------------------------------- 1 | benchClient 2 | replica 3 | -------------------------------------------------------------------------------- /nistore/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), \ 4 | client.cc txnstore.cc server.cc \ 5 | lockstore.cc lockserver.cc kvstore.cc \ 6 | benchClient.cc versionedKVStore.cc occstore.cc) 7 | 8 | PROTOS += $(addprefix $(d), \ 9 | request.proto) 10 | 11 | LIB-kvstore := $(o)kvstore.o 12 | 13 | LIB-stores := $(o)lockserver.o $(o)versionedKVStore.o 14 | 15 | OBJS-ni-store := $(o)server.o $(o)txnstore.o $(o)lockstore.o $(o)occstore.o 16 | 17 | OBJS-ni-client := $(o)request.o $(o)client.o \ 18 | $(OBJS-spec-client) $(OBJS-vr-client) $(OBJS-fastpaxos-client) $(LIB-udptransport) 19 | 20 | $(d)benchClient: $(OBJS-ni-client) $(o)benchClient.o 21 | 22 | $(d)replica: $(o)request.o $(OBJS-ni-store) $(LIB-kvstore) $(LIB-stores) \ 23 | $(OBJS-spec-replica) $(OBJS-vr-replica) $(OBJS-fastpaxos-replica) $(LIB-udptransport) 24 | 25 | BINS += $(d)benchClient $(d)replica 26 | -------------------------------------------------------------------------------- /nistore/client.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/client.h: 6 | * NiStore client-side logic and APIs 7 | * 8 | **********************************************************************/ 9 | 10 | #ifndef _NI_CLIENT_H_ 11 | #define _NI_CLIENT_H_ 12 | 13 | #include "lib/assert.h" 14 | #include "lib/message.h" 15 | #include "lib/udptransport.h" 16 | #include "common/client.h" 17 | #include "lib/configuration.h" 18 | #include "spec/client.h" 19 | #include "vr/client.h" 20 | #include "fastpaxos/client.h" 21 | #include "nistore/request.pb.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace nistore { 32 | 33 | using namespace std; 34 | 35 | enum Proto { 36 | PROTO_UNKNOWN, 37 | PROTO_VR, 38 | PROTO_SPEC, 39 | PROTO_FAST 40 | }; 41 | 42 | class Client 43 | { 44 | public: 45 | /* Constructor needs path to shard configs and number of shards. */ 46 | Client(Proto mode, string configPath, int nshards); 47 | ~Client(); 48 | 49 | /* API Calls for NiStore. */ 50 | void Begin(); 51 | bool Get(const string &key, string &value); 52 | void Put(const string &key, const string &value); 53 | bool Commit(); 54 | void Abort(); 55 | 56 | private: 57 | long client_id; // Unique ID for this client. 58 | long nshards; // Number of shards in niStore 59 | 60 | UDPTransport transport; // Transport used by paxos client proxies. 61 | thread *clientTransport; // Thread running the transport event loop. 62 | 63 | vector shard; // List of shard client proxies. 64 | specpaxos::Client *tss; // Timestamp server shard. 65 | 66 | mutex cv_m; // Synchronize access to all state in this class and cv. 67 | condition_variable cv; // To block api calls till a replica reply. 68 | 69 | /* Transaction specific variables. */ 70 | bool op_pending; // True if a transaction is ongoing. 71 | bool status; // Whether to commit transaction & reply status. 72 | unsigned int nreplies; // Number of replies received back in 2PC. 73 | set all_participants; // Participants in ongoing transaction. 74 | set yes_participants; // Participants who replies YES. 75 | string replica_reply; // Reply back from a shard. 76 | 77 | /* Private helper functions. */ 78 | void run_client(); // Runs the transport event loop. 79 | void send_begin(unsigned int); // Sends BEGIN message to shard[i]. 80 | 81 | /* Callbacks for hearing back from a shard for an operation. */ 82 | void beginCallback(const int, const string &, const string &); 83 | void getCallback(const int, const string &, const string &); 84 | void putCallback(const int, const string &, const string &); 85 | void prepareCallback(const int, const string &, const string &); 86 | void commitCallback(const int, const string &, const string &); 87 | void abortCallback(const int, const string &, const string &); 88 | 89 | void tssCallback(const string &request, const string &reply); 90 | 91 | // Sharding logic: Given key, generates a number b/w 0 to nshards-1 92 | long key_to_shard(const string &key); 93 | }; 94 | 95 | } // namespace nistore 96 | 97 | #endif /* _NI_CLIENT_H_ */ 98 | -------------------------------------------------------------------------------- /nistore/kvstore.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/kvstore.cc: 6 | * Simple versioned key-value store 7 | * 8 | **********************************************************************/ 9 | 10 | #include "nistore/kvstore.h" 11 | #include "lib/assert.h" 12 | #include "lib/message.h" 13 | 14 | namespace nistore { 15 | using namespace std; 16 | 17 | KVStore::KVStore() { } 18 | 19 | KVStore::~KVStore() { } 20 | 21 | 22 | bool 23 | KVStore::get(const string &key, string &value) 24 | { 25 | // check for existence of key in store 26 | if (store.find(key) == store.end() || store[key].empty()) { 27 | return false; 28 | } else { 29 | value = store[key].back(); 30 | return true; 31 | } 32 | } 33 | 34 | 35 | bool 36 | KVStore::put(const string &key, const string &value) 37 | { 38 | store[key].push_back(value); 39 | return true; 40 | } 41 | 42 | /* Delete the latest version of this key. */ 43 | bool 44 | KVStore::remove(const string &key, string &value) 45 | { 46 | if (store.find(key) == store.end() || store[key].empty()) { 47 | return false; 48 | } 49 | 50 | store[key].pop_back(); 51 | return true; 52 | } 53 | 54 | } // namespace nistore 55 | -------------------------------------------------------------------------------- /nistore/kvstore.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/kvstore.h: 6 | * Simple historied key-value store 7 | * 8 | **********************************************************************/ 9 | 10 | #ifndef _KV_STORE_H_ 11 | #define _KV_STORE_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace nistore { 22 | using namespace std; 23 | 24 | class KVStore 25 | { 26 | 27 | public: 28 | KVStore(); 29 | ~KVStore(); 30 | 31 | bool get(const string &key, string &value); 32 | bool put(const string &key, const string &value); 33 | bool remove(const string &key, string &value); 34 | 35 | private: 36 | /* Global store which keep key -> (timestamp, value) list. */ 37 | unordered_map> store; 38 | }; 39 | 40 | } // namespace nistore 41 | 42 | #endif /* _KV_STORE_H_ */ 43 | -------------------------------------------------------------------------------- /nistore/lockserver.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/lockserver.h: 6 | * Simple multi-reader, single-writer lock server 7 | * 8 | **********************************************************************/ 9 | 10 | #ifndef _LOCK_SERVER_H_ 11 | #define _LOCK_SERVER_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace nistore { 25 | using namespace std; 26 | 27 | #define LOCK_WAIT_TIMEOUT 5000 28 | 29 | class LockServer 30 | { 31 | 32 | public: 33 | LockServer(); 34 | ~LockServer(); 35 | 36 | bool lockForRead(const string &lock, uint64_t requester); 37 | bool lockForWrite(const string &lock, uint64_t requester); 38 | void releaseForRead(const string &lock, uint64_t holder); 39 | void releaseForWrite(const string &lock, uint64_t holder); 40 | 41 | private: 42 | enum LockState { 43 | UNLOCKED, 44 | LOCKED_FOR_READ, 45 | LOCKED_FOR_WRITE, 46 | LOCKED_FOR_READ_WRITE 47 | }; 48 | 49 | struct Waiter { 50 | bool write; 51 | struct timeval waitTime; 52 | 53 | Waiter() {write = false;} 54 | Waiter(bool w) { 55 | gettimeofday(&waitTime, NULL); 56 | write = w; 57 | } 58 | 59 | bool checkTimeout(const struct timeval &now); 60 | }; 61 | 62 | struct Lock { 63 | LockState state; 64 | unordered_set holders; 65 | queue waitQ; 66 | map waiters; 67 | 68 | Lock() { 69 | state = UNLOCKED; 70 | }; 71 | void waitForLock(uint64_t requester, bool write); 72 | bool tryAcquireLock(uint64_t requester, bool write); 73 | bool isWriteNext(); 74 | }; 75 | 76 | 77 | /* Global store which keep key -> (timestamp, value) list. */ 78 | unordered_map locks; 79 | 80 | uint64_t readers; 81 | uint64_t writers; 82 | }; 83 | 84 | } // namespace nistore 85 | 86 | #endif /* _LOCK_SERVER_H_ */ 87 | -------------------------------------------------------------------------------- /nistore/lockstore.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/lockstore.h 6 | * Key-value store with support for transactions using S2PL 7 | * 8 | **********************************************************************/ 9 | 10 | #ifndef _NI_LOCK_STORE_H_ 11 | #define _NI_LOCK_STORE_H_ 12 | 13 | #include "nistore/kvstore.h" 14 | #include "nistore/lockserver.h" 15 | #include "nistore/txnstore.h" 16 | #include "lib/viewstamp.h" 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace nistore { 24 | 25 | using namespace std; 26 | 27 | class LockStore : public TxnStore 28 | { 29 | public: 30 | LockStore(); 31 | ~LockStore(); 32 | 33 | // begin a transaction 34 | virtual void begin(uint64_t id); 35 | // add key to read set 36 | virtual int get(uint64_t id, const string &key, string &value); 37 | // add key to write set 38 | virtual int put(uint64_t id, const string &key, const string &value); 39 | // check whether we can commit or abort this transaction 40 | // and lock the read/write set 41 | virtual int prepare(uint64_t id, opnum_t op); 42 | // commit the transaction 43 | virtual void commit(uint64_t id, uint64_t timestamp, opnum_t op); 44 | // abort a running transaction 45 | virtual void abortTxn(uint64_t id, opnum_t op); 46 | 47 | // undo operations from Spec Paxos 48 | virtual void unbegin(uint64_t id); 49 | virtual void unget(uint64_t id, const string &key); 50 | virtual void unput(uint64_t id, const string &key, const string &value); 51 | virtual void unprepare(uint64_t id, opnum_t op); 52 | virtual void uncommit(uint64_t id, uint64_t timestamp, opnum_t op); 53 | virtual void unabort(uint64_t id, opnum_t op); 54 | 55 | // upcall from Spec Paxos to clean up 56 | virtual void specCommit(opnum_t op); 57 | 58 | private: 59 | // data store 60 | KVStore store; 61 | // locks 62 | LockServer locks; 63 | 64 | // Currently active transaction 65 | // may be running or prepared 66 | struct Transaction { 67 | uint64_t id; 68 | // list of keys read and number of times each has been read 69 | map readSet; 70 | // map between key and value(s) 71 | map> writeSet; 72 | 73 | Transaction() : id(0) { }; 74 | Transaction(uint64_t i) : id(i) { }; 75 | 76 | bool operator== (const Transaction &t); 77 | }; 78 | 79 | enum RetiredState { 80 | COMMITTED, 81 | ABORTED_PREPARED, 82 | ABORTED_RUNNING 83 | }; 84 | 85 | struct RetiredTxn { 86 | Transaction txn; 87 | RetiredState state; 88 | 89 | RetiredTxn(Transaction t, RetiredState s) : 90 | txn(t), state(s) { }; 91 | }; 92 | 93 | map running; 94 | map prepared; 95 | list> retired; 96 | 97 | Transaction& getTxn(uint64_t id); 98 | Transaction getRetiredTxn(opnum_t op, uint64_t id, RetiredState state); 99 | void dropLocks(const Transaction &txn); 100 | void getLocks(const Transaction &txn); 101 | }; 102 | 103 | } // namespace nistore 104 | 105 | #endif /* _NI_LOCK_STORE_H_ */ 106 | -------------------------------------------------------------------------------- /nistore/occstore.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/occstore.h: 6 | * Key-value store with support for transactions using OCC 7 | * 8 | **********************************************************************/ 9 | 10 | #ifndef _NI_OCC_STORE_H_ 11 | #define _NI_OCC_STORE_H_ 12 | 13 | #include "nistore/versionedKVStore.h" 14 | #include "nistore/txnstore.h" 15 | #include "lib/viewstamp.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace nistore { 23 | 24 | using namespace std; 25 | 26 | class OCCStore : public TxnStore 27 | { 28 | public: 29 | OCCStore(); 30 | ~OCCStore(); 31 | 32 | // begin a transaction 33 | virtual void begin(uint64_t id); 34 | // add key to read set 35 | virtual int get(uint64_t id, const string &key, string &value); 36 | // add key to write set 37 | virtual int put(uint64_t id, const string &key, const string &value); 38 | // check whether we can commit or abort this transaction 39 | // and lock the read/write set 40 | virtual int prepare(uint64_t id, opnum_t op); 41 | // commit the transaction 42 | virtual void commit(uint64_t id, uint64_t timestamp, opnum_t op); 43 | // abort a running transaction 44 | virtual void abortTxn(uint64_t id, opnum_t op); 45 | 46 | // undo operations from Spec Paxos 47 | virtual void unbegin(uint64_t id); 48 | virtual void unget(uint64_t id, const string &key); 49 | virtual void unput(uint64_t id, const string &key, const string &value); 50 | virtual void unprepare(uint64_t id, opnum_t op); 51 | virtual void uncommit(uint64_t id, uint64_t timestamp, opnum_t op); 52 | virtual void unabort(uint64_t id, opnum_t op); 53 | 54 | // upcall from Spec Paxos to clean up 55 | virtual void specCommit(opnum_t op); 56 | 57 | private: 58 | // data store 59 | VersionedKVStore store; 60 | 61 | // Currently active transaction 62 | // may be running or prepared 63 | struct Transaction { 64 | uint64_t id; 65 | // map between key and timestamp at 66 | // which the read happened and how 67 | // many times this key has been read 68 | map> readSet; 69 | // map between key and value(s) 70 | map> writeSet; 71 | 72 | Transaction() : id(0) { }; 73 | Transaction(uint64_t i) : id(i) { }; 74 | 75 | bool operator== (const Transaction &t); 76 | }; 77 | 78 | enum RetiredState { 79 | COMMITTED, 80 | ABORTED_PREPARED, 81 | ABORTED_RUNNING 82 | }; 83 | 84 | struct RetiredTxn { 85 | Transaction txn; 86 | RetiredState state; 87 | 88 | RetiredTxn(Transaction t, RetiredState s) : 89 | txn(t), state(s) { }; 90 | }; 91 | 92 | map running; 93 | map prepared; 94 | list> retired; 95 | 96 | set getPreparedWrites(); 97 | set getPreparedReadWrites(); 98 | Transaction& getTxn(uint64_t id); 99 | Transaction getRetiredTxn(opnum_t op, uint64_t id, RetiredState state); 100 | }; 101 | 102 | } // namespace nistore 103 | 104 | #endif /* _NI_OCC_STORE_H_ */ 105 | -------------------------------------------------------------------------------- /nistore/request.proto: -------------------------------------------------------------------------------- 1 | package nistore; 2 | 3 | message Request { 4 | enum Operation { 5 | BEGIN = 1; 6 | GET = 2; 7 | PUT = 3; 8 | PREPARE = 4; 9 | COMMIT = 5; 10 | ABORT = 6; 11 | } 12 | 13 | required Operation op = 1; 14 | required uint64 txnid = 2; 15 | optional string arg0 = 3; 16 | optional string arg1 = 4; 17 | } 18 | 19 | message Reply { 20 | // 0 = OK 21 | // -1 = failed 22 | // -2 = retry 23 | // -3 = abstain/no reply 24 | required int32 status = 1; 25 | optional string value = 2; 26 | } 27 | -------------------------------------------------------------------------------- /nistore/server.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/server.h: 6 | * NiStore application server logic 7 | * 8 | **********************************************************************/ 9 | 10 | #ifndef _NI_SERVER_H_ 11 | #define _NI_SERVER_H_ 12 | 13 | #include "lib/configuration.h" 14 | #include "common/replica.h" 15 | #include "lib/udptransport.h" 16 | #include "spec/replica.h" 17 | #include "vr/replica.h" 18 | #include "fastpaxos/replica.h" 19 | #include "nistore/lockstore.h" 20 | #include "nistore/occstore.h" 21 | #include 22 | 23 | namespace nistore { 24 | 25 | using namespace std; 26 | 27 | class Server : public specpaxos::AppReplica 28 | { 29 | public: 30 | // set up the store 31 | Server() {store = OCCStore(); }; 32 | Server(bool locking) {locking ? store = LockStore() : OCCStore();}; 33 | ~Server() { }; 34 | void ReplicaUpcall(opnum_t opnum, const string &str1, string &str2); 35 | void RollbackUpcall(opnum_t current, opnum_t to, const std::map &opMap); 36 | void CommitUpcall(opnum_t opnum); 37 | 38 | private: 39 | // data store 40 | TxnStore store; 41 | 42 | struct Operation 43 | { 44 | long id; // client ID 45 | string op; // requested operation 46 | std::vector args; // arguments 47 | }; 48 | 49 | Operation parse(string str); 50 | vector split(string str); 51 | }; 52 | 53 | } // namespace nistore 54 | 55 | #endif /* _NI_SERVER_H_ */ 56 | -------------------------------------------------------------------------------- /nistore/shard.tss.config: -------------------------------------------------------------------------------- 1 | f 1 2 | replica 10.10.1.3:12345 3 | replica 10.10.1.4:12345 4 | replica 10.10.1.1:12345 -------------------------------------------------------------------------------- /nistore/shard0.config: -------------------------------------------------------------------------------- 1 | f 1 2 | replica 10.10.1.9:12345 3 | replica 10.10.1.10:12345 4 | replica 10.10.1.11:12345 -------------------------------------------------------------------------------- /nistore/txnstore.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/txnstore.cc: 6 | * Transactional Key-value store interface 7 | * 8 | **********************************************************************/ 9 | #include "nistore/txnstore.h" 10 | #include "lib/assert.h" 11 | #include "lib/message.h" 12 | 13 | namespace nistore { 14 | 15 | using namespace std; 16 | 17 | TxnStore::TxnStore() { } 18 | TxnStore::~TxnStore() { } 19 | 20 | void 21 | TxnStore::begin(uint64_t id) 22 | { 23 | Debug("[%" PRIu64 "] BEGIN", id); 24 | } 25 | 26 | void 27 | TxnStore::unbegin(uint64_t id) 28 | { 29 | Debug("[%" PRIu64 "] UNDO BEGIN", id); 30 | } 31 | 32 | int 33 | TxnStore::get(uint64_t id, const string &key, string &value) 34 | { 35 | Debug("[%" PRIu64 "] GET %s", id, key.c_str()); 36 | return 0; 37 | } 38 | 39 | void 40 | TxnStore::unget(uint64_t id, const string &key) 41 | { 42 | Debug("[%" PRIu64 "] UNDO GET %s", id, key.c_str()); 43 | } 44 | 45 | int 46 | TxnStore::put(uint64_t id, const string &key, const string &value) 47 | { 48 | Debug("[%" PRIu64 "] PUT %s %s", id, key.c_str(), value.c_str()); 49 | return 0; 50 | } 51 | 52 | void 53 | TxnStore::unput(uint64_t id, const string &key, const string &value) 54 | { 55 | Debug("[%" PRIu64 "] UNDO PUT %s %s", id, key.c_str(), value.c_str()); 56 | } 57 | 58 | int 59 | TxnStore::prepare(uint64_t id, opnum_t op) 60 | { 61 | Debug("[%" PRIu64 "] START PREPARE", id); 62 | return 0; 63 | } 64 | 65 | void 66 | TxnStore::unprepare(uint64_t id, opnum_t op) 67 | { 68 | Debug("[%" PRIu64 "] UNDO PREPARE", id); 69 | } 70 | 71 | void 72 | TxnStore::commit(uint64_t id, uint64_t timestamp, opnum_t op) 73 | { 74 | Debug("[%" PRIu64 "] COMMIT", id); 75 | } 76 | 77 | void 78 | TxnStore::uncommit(uint64_t id, uint64_t timestamp, opnum_t op) 79 | { 80 | // do some uncommit stuff 81 | Debug("[%" PRIu64 "] UNDO COMMIT", id); 82 | 83 | } 84 | 85 | void 86 | TxnStore::abortTxn(uint64_t id, opnum_t op) 87 | { 88 | Debug("[%" PRIu64 "] ABORT", id); 89 | } 90 | 91 | void 92 | TxnStore::unabort(uint64_t id, opnum_t op) 93 | { 94 | Debug("[%" PRIu64 "] UNDO ABORT", id); 95 | } 96 | 97 | void 98 | TxnStore::specCommit(opnum_t op) 99 | { 100 | Debug("SPEC COMMIT"); 101 | } 102 | 103 | } // namespace nistore 104 | -------------------------------------------------------------------------------- /nistore/txnstore.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/txnstore.h: 6 | * Interface for a single node transactional store serving as a 7 | * server-side backend for NiStore 8 | * 9 | **********************************************************************/ 10 | 11 | #ifndef _TXN_STORE_H_ 12 | #define _TXN_STORE_H_ 13 | 14 | #include "lib/viewstamp.h" 15 | #include 16 | 17 | namespace nistore { 18 | 19 | using namespace std; 20 | 21 | class TxnStore 22 | { 23 | public: 24 | 25 | TxnStore(); 26 | ~TxnStore(); 27 | 28 | // begin a transaction 29 | virtual void begin(uint64_t id); 30 | // add key to read set 31 | virtual int get(uint64_t id, const string &key, string &value); 32 | // add key to write set 33 | virtual int put(uint64_t id, const string &key, const string &value); 34 | // check whether we can commit or abort this transaction 35 | // and lock the read/write set 36 | virtual int prepare(uint64_t id, opnum_t op); 37 | // commit the transaction 38 | virtual void commit(uint64_t id, uint64_t timestamp, opnum_t op); 39 | // abort a running transaction 40 | virtual void abortTxn(uint64_t id, opnum_t op); 41 | 42 | // undo operations from Spec Paxos 43 | virtual void unbegin(uint64_t id); 44 | virtual void unget(uint64_t id, const string &key); 45 | virtual void unput(uint64_t id, const string &key, const string &value); 46 | virtual void unprepare(uint64_t id, opnum_t op); 47 | virtual void uncommit(uint64_t id, uint64_t timestamp, opnum_t op); 48 | virtual void unabort(uint64_t id, opnum_t op); 49 | 50 | // upcall from Spec Paxos to clean up 51 | virtual void specCommit(opnum_t op); 52 | }; 53 | 54 | } // namespace nistore 55 | 56 | #endif /* _TXN_STORE_H_ */ 57 | -------------------------------------------------------------------------------- /nistore/versionedKVStore.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/versionedKVStore.cc: 6 | * Simple versioned key-value store 7 | * 8 | **********************************************************************/ 9 | 10 | #include "nistore/versionedKVStore.h" 11 | #include "lib/assert.h" 12 | #include "lib/message.h" 13 | 14 | namespace nistore { 15 | using namespace std; 16 | 17 | VersionedKVStore::VersionedKVStore() { } 18 | 19 | VersionedKVStore::~VersionedKVStore() { } 20 | 21 | 22 | /* Returns the most recent value and timestamp for given key. 23 | * Error if key does not exist. */ 24 | bool 25 | VersionedKVStore::get(const string &key, pair &value) 26 | { 27 | // check for existence of key in store 28 | if (store.find(key) == store.end()) { 29 | return false; 30 | } else { 31 | value = store[key].front(); 32 | return true; 33 | } 34 | } 35 | 36 | /* Returns the value valid at given timestamp. 37 | * Error if key did not exist at the timestamp. */ 38 | bool 39 | VersionedKVStore::get(const string &key, uint64_t timestamp, string &value) 40 | { 41 | // check for existence of key in store 42 | if (store.find(key) == store.end()) { 43 | return false; 44 | } else { 45 | list >::iterator it = store[key].begin(); 46 | while (it != store[key].end()) { 47 | if ( timestamp >= (*it).first ) { 48 | value = (*it).second; 49 | return true; 50 | } 51 | it++; 52 | } 53 | } 54 | return false; 55 | } 56 | 57 | bool 58 | VersionedKVStore::put(const string &key, const string &value, uint64_t timestamp) 59 | { 60 | // Key does not exist. Create a list and an entry. 61 | if (store.find(key) == store.end()) { 62 | list > l; 63 | l.push_front(make_pair(timestamp, value)); 64 | store[key] = l; 65 | return true; 66 | } 67 | 68 | // Key exists, add it to list of values if newer timestamp. 69 | if (timestamp > store[key].front().first) { 70 | store[key].push_front(make_pair(timestamp, value)); 71 | return true; 72 | } else { 73 | // newer version exists, insert older version 74 | list >::iterator it = store[key].begin(); 75 | while (it != store[key].end()) { 76 | if ( timestamp > (*it).first ) { 77 | store[key].insert(it, make_pair(timestamp, value)); 78 | return true; 79 | } 80 | it++; 81 | } 82 | return true; 83 | } 84 | 85 | return false; 86 | } 87 | 88 | /* Delete the latest version of this key. */ 89 | bool 90 | VersionedKVStore::remove(const string &key, pair &value) 91 | { 92 | if (store.find(key) == store.end()) { 93 | return false; 94 | } 95 | 96 | value = store[key].front(); 97 | store[key].pop_front(); 98 | return true; 99 | } 100 | 101 | } // namespace nistore 102 | -------------------------------------------------------------------------------- /nistore/versionedKVStore.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | // vim: set ts=4 sw=4: 3 | /*********************************************************************** 4 | * 5 | * nistore/versionedKVStore.h: 6 | * Simple versioned key-value store 7 | * 8 | **********************************************************************/ 9 | 10 | #ifndef _NI_VERSIONED_KV_STORE_H_ 11 | #define _NI_VERSIONED_KV_STORE_H_ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace nistore { 22 | using namespace std; 23 | 24 | class VersionedKVStore 25 | { 26 | 27 | public: 28 | VersionedKVStore(); 29 | ~VersionedKVStore(); 30 | 31 | bool get(const string &key, pair &value); 32 | bool get(const string &key, uint64_t timestamp, string &value); 33 | bool put(const string &key, const string &value, uint64_t timestamp); 34 | bool remove(const string &key, pair &value); 35 | 36 | private: 37 | /* Global store which keep key -> (timestamp, value) list. */ 38 | unordered_map > > store; 39 | }; 40 | 41 | } // namespace nistore 42 | 43 | #endif /* _NI_VERSIONED_KV_STORE_H_ */ 44 | -------------------------------------------------------------------------------- /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 | 19 | -------------------------------------------------------------------------------- /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-2016 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 | 59 | protected: 60 | view_t view; 61 | opnum_t opnum; 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 | QuorumSet speculativeReplyQuorum; 80 | 81 | void SendRequest(); 82 | void ResendRequest(); 83 | void CompleteOperation(const proto::SpeculativeReplyMessage &msg); 84 | void HandleReply(const TransportAddress &remote, 85 | const proto::SpeculativeReplyMessage &msg); 86 | void HandleUnloggedReply(const TransportAddress &remote, 87 | const proto::UnloggedReplyMessage &msg); 88 | void UnloggedRequestTimeoutCallback(); 89 | }; 90 | 91 | } // namespace specpaxos::spec 92 | } // namespace specpaxos 93 | 94 | #endif /* _SPEC_CLIENT_H_ */ 95 | -------------------------------------------------------------------------------- /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-2016 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 | #define FMT_CLIENTREQID "%" PRIu64 53 | 54 | class SpecReplica : public Replica 55 | { 56 | public: 57 | SpecReplica(Configuration config, int myIdx, bool initialize, 58 | Transport *transport, AppReplica *app); 59 | ~SpecReplica(); 60 | 61 | void ReceiveMessage(const TransportAddress &remote, 62 | const string &type, const string &data); 63 | 64 | public: // XXX public for unit testing 65 | Log log; 66 | private: 67 | view_t view; 68 | opnum_t lastCommitted; 69 | opnum_t lastCommittedSent; 70 | opnum_t lastSpeculative; 71 | opnum_t pendingSync; 72 | opnum_t lastSync; 73 | view_t sentDoViewChange; 74 | view_t needFillDVC; 75 | std::map > clientAddresses; 76 | struct ClientTableEntry 77 | { 78 | uint64_t lastReqId; 79 | // We need the opnum to identify the correct entry in the 80 | // log. What we really want is the SpeculativeReplyMessage 81 | // corresponding to the last request, but we need to stuff 82 | // that in the log instead of keeping it here -- in order to 83 | // keep this up to date even if we roll back the log. 84 | opnum_t lastReqOpnum; 85 | }; 86 | std::map clientTable; 87 | std::list > pendingRequests; 89 | 90 | QuorumSet syncReplyQuorum; 91 | QuorumSet startViewChangeQuorum; 92 | QuorumSet doViewChangeQuorum; 93 | QuorumSet inViewQuorum; 94 | 95 | Timeout *syncTimeout; 96 | Timeout *failedSyncTimeout; 97 | Timeout *viewChangeTimeout; 98 | 99 | Latency_t reconciliationLatency; 100 | Latency_t mergeLatency; 101 | Latency_t requestLatency; 102 | 103 | bool AmLeader() const; 104 | void SendSync(); 105 | void CommitUpTo(opnum_t upto); 106 | void RollbackTo(opnum_t backto); 107 | void UpdateClientTable(const Request &req, 108 | LogEntry &entry, 109 | const proto::SpeculativeReplyMessage &reply); 110 | void EnterView(view_t newview); 111 | void StartViewChange(view_t newview); 112 | void MergeLogs(view_t newView, opnum_t maxStart, 113 | const std::map &dvcs, 114 | std::vector &out); 115 | void InstallLog(const std::vector &entries); 116 | void SendFillDVCGapMessage(int replicaIdx, view_t view); 117 | void NeedFillDVCGap(view_t view); 118 | void SendSyncReply(opnum_t opnum); 119 | 120 | void HandleRequest(const TransportAddress &remote, 121 | const proto::RequestMessage &msg); 122 | void HandleUnloggedRequest(const TransportAddress &remote, 123 | const proto::UnloggedRequestMessage &msg); 124 | void HandleSync(const TransportAddress &remote, 125 | const proto::SyncMessage &msg); 126 | void HandleSyncReply(const TransportAddress &remote, 127 | const proto::SyncReplyMessage &msg); 128 | void HandleRequestViewChange(const TransportAddress &remote, 129 | const proto::RequestViewChangeMessage &msg); 130 | void HandleStartViewChange(const TransportAddress &remote, 131 | const proto::StartViewChangeMessage &msg); 132 | void HandleDoViewChange(const TransportAddress &remote, 133 | const proto::DoViewChangeMessage &msg); 134 | void HandleStartView(const TransportAddress &remote, 135 | const proto::StartViewMessage &msg); 136 | void HandleInView(const TransportAddress &remote, 137 | const proto::InViewMessage &msg); 138 | void HandleFillLogGap(const TransportAddress &remote, 139 | const proto::FillLogGapMessage &msg); 140 | void HandleFillDVCGap(const TransportAddress &remote, 141 | const proto::FillDVCGapMessage &msg); 142 | 143 | friend class ::LogMergeTest; 144 | }; 145 | 146 | 147 | } // namespace specpaxos::spec 148 | } // namespace specpaxos 149 | 150 | #endif /* _SPEC_REPLICA_H_ */ 151 | -------------------------------------------------------------------------------- /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 | message LogEntry { 57 | required uint64 view = 1; 58 | required uint64 opnum = 2; 59 | required specpaxos.Request request = 3; 60 | required uint32 state = 4; 61 | optional bytes hash = 5; 62 | } 63 | required uint64 view = 1; 64 | required uint64 lastNormalView = 2; 65 | required uint64 lastSpeculative = 3; 66 | required uint64 lastCommitted = 4; 67 | repeated LogEntry entries = 5; 68 | required uint32 replicaIdx = 6; 69 | } 70 | 71 | message StartViewMessage { 72 | message LogEntry { 73 | required uint64 view = 1; 74 | required uint64 opnum = 2; 75 | required specpaxos.Request request = 3; 76 | required uint32 state = 4; 77 | required bytes hash = 5; 78 | } 79 | required uint64 view = 1; 80 | required uint64 lastSpeculative = 2; 81 | required uint64 lastCommitted = 3; 82 | repeated LogEntry entries = 4; 83 | } 84 | 85 | message InViewMessage { 86 | required uint64 view = 1; 87 | required uint64 lastSpeculative = 2; 88 | required uint32 replicaIdx = 3; 89 | } 90 | 91 | message FillLogGapMessage { 92 | required uint64 view = 1; 93 | required uint64 lastCommitted = 2; 94 | } 95 | 96 | message FillDVCGapMessage { 97 | required uint64 view = 1; 98 | required uint64 lastCommitted = 2; 99 | } 100 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /spec/tests/merge-test-case.proto: -------------------------------------------------------------------------------- 1 | package specpaxos.spec.test; 2 | 3 | message TestLogEntry 4 | { 5 | required uint64 view = 1; 6 | required uint64 opnum = 2; 7 | required string id = 3; 8 | required bool spec = 4; 9 | } 10 | 11 | message TestLog 12 | { 13 | required uint32 replicaidx = 1; 14 | required uint64 view = 2; 15 | required uint64 lastNormalView = 3; 16 | repeated TestLogEntry entries = 4; 17 | } 18 | 19 | message MergeTestCase 20 | { 21 | required uint64 newview = 1; 22 | repeated TestLog log = 2; 23 | repeated TestLogEntry expected = 3; 24 | } 25 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /timeserver/.gitignore: -------------------------------------------------------------------------------- 1 | replica 2 | -------------------------------------------------------------------------------- /timeserver/Rules.mk: -------------------------------------------------------------------------------- 1 | d := $(dir $(lastword $(MAKEFILE_LIST))) 2 | 3 | SRCS += $(addprefix $(d), timeserver.cc) 4 | 5 | $(d)replica: $(o)timeserver.o $(OBJS-fastpaxos-replica) \ 6 | $(OBJS-spec-replica) $(OBJS-vr-replica) $(LIB-udptransport) 7 | 8 | BINS += $(d)replica 9 | -------------------------------------------------------------------------------- /timeserver/timeserver.cc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * timeserver/timeserver.cc: 5 | * Single TimeStamp Server. 6 | * 7 | **********************************************************************/ 8 | 9 | #include "timeserver/timeserver.h" 10 | 11 | TimeStampServer::TimeStampServer() 12 | { 13 | ts = 0; 14 | } 15 | 16 | TimeStampServer::~TimeStampServer() { } 17 | 18 | string 19 | TimeStampServer::newTimeStamp() 20 | { 21 | ts++; 22 | return to_string(ts); 23 | } 24 | 25 | void 26 | TimeStampServer::ReplicaUpcall(opnum_t opnum, 27 | const string &str1, 28 | string &str2) 29 | { 30 | Debug("Received Upcall: " FMT_OPNUM ", %s", opnum, str1.c_str()); 31 | // Get a new timestamp from the TimeStampServer 32 | str2 = newTimeStamp(); 33 | } 34 | 35 | /* Ignore for now, will be used when running specpaxos. */ 36 | void 37 | TimeStampServer::RollbackUpcall(opnum_t current, 38 | opnum_t to, 39 | const std::map &opMap) 40 | { 41 | Debug("Received Rollback Upcall: " FMT_OPNUM ", " FMT_OPNUM, current, to); 42 | for (auto op : opMap) { 43 | ts--; 44 | } 45 | } 46 | 47 | 48 | /* Ignore for now, will be used when running specpaxos. */ 49 | void 50 | TimeStampServer::CommitUpcall(opnum_t commitOpnum) 51 | { 52 | Debug("Received Commit Upcall: " FMT_OPNUM, commitOpnum); 53 | } 54 | 55 | static void Usage(const char *progName) 56 | { 57 | fprintf(stderr, "usage: %s -c conf-file -i replica-index\n", 58 | progName); 59 | exit(1); 60 | } 61 | 62 | int 63 | main(int argc, char **argv) 64 | { 65 | int index = -1; 66 | const char *configPath = NULL; 67 | enum { 68 | PROTO_UNKNOWN, 69 | PROTO_VR, 70 | PROTO_SPEC, 71 | PROTO_FAST 72 | } proto = PROTO_UNKNOWN; 73 | 74 | // Parse arguments 75 | int opt; 76 | while ((opt = getopt(argc, argv, "c:i:m:")) != -1) { 77 | switch (opt) { 78 | case 'c': 79 | configPath = optarg; 80 | break; 81 | 82 | case 'i': 83 | { 84 | char *strtolPtr; 85 | index = strtoul(optarg, &strtolPtr, 10); 86 | if ((*optarg == '\0') || (*strtolPtr != '\0') || (index < 0)) 87 | { 88 | fprintf(stderr, 89 | "option -i requires a numeric arg\n"); 90 | Usage(argv[0]); 91 | } 92 | break; 93 | } 94 | 95 | case 'm': 96 | { 97 | if (strcasecmp(optarg, "vr") == 0) { 98 | proto = PROTO_VR; 99 | } else if (strcasecmp(optarg, "spec") == 0) { 100 | proto = PROTO_SPEC; 101 | } else if (strcasecmp(optarg, "fast") == 0) { 102 | proto = PROTO_FAST; 103 | } else { 104 | proto = PROTO_VR; 105 | } 106 | break; 107 | } 108 | 109 | default: 110 | fprintf(stderr, "Unknown argument %s\n", argv[optind]); 111 | break; 112 | } 113 | } 114 | 115 | if (!configPath) { 116 | fprintf(stderr, "option -c is required\n"); 117 | Usage(argv[0]); 118 | } 119 | 120 | if (index == -1) { 121 | fprintf(stderr, "option -i is required\n"); 122 | Usage(argv[0]); 123 | } 124 | 125 | if (proto == PROTO_UNKNOWN) { 126 | fprintf(stderr, "option -i is required\n"); 127 | Usage(argv[0]); 128 | } 129 | 130 | // Load configuration 131 | std::ifstream configStream(configPath); 132 | if (configStream.fail()) { 133 | fprintf(stderr, "unable to read configuration file: %s\n", 134 | configPath); 135 | Usage(argv[0]); 136 | } 137 | specpaxos::Configuration config(configStream); 138 | 139 | if (index >= config.n) { 140 | fprintf(stderr, "replica index %d is out of bounds; " 141 | "only %d replicas defined\n", index, config.n); 142 | Usage(argv[0]); 143 | } 144 | 145 | UDPTransport transport(0.0, 0.0, 0); 146 | 147 | specpaxos::Replica *replica; 148 | TimeStampServer server; 149 | 150 | switch (proto) { 151 | case PROTO_VR: 152 | replica = new specpaxos::vr::VRReplica(config, index, true, &transport, 1, &server); 153 | break; 154 | 155 | case PROTO_SPEC: 156 | replica = new specpaxos::spec::SpecReplica( 157 | config, index, true, &transport, &server); 158 | break; 159 | 160 | case PROTO_FAST: 161 | replica = new specpaxos::fastpaxos::FastPaxosReplica(config, index, true, &transport, &server); 162 | break; 163 | 164 | default: 165 | NOT_REACHABLE(); 166 | } 167 | 168 | (void)replica; // silence warning 169 | transport.Run(); 170 | 171 | return 0; 172 | } 173 | -------------------------------------------------------------------------------- /timeserver/timeserver.h: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; c-file-style: "k&r"; c-basic-offset: 4 -*- 2 | /*********************************************************************** 3 | * 4 | * timeserver/timeserver.h: 5 | * Timeserver API 6 | * 7 | **********************************************************************/ 8 | 9 | #ifndef _TIME_SERVER_H_ 10 | #define _TIME_SERVER_H_ 11 | 12 | #include "lib/configuration.h" 13 | #include "common/replica.h" 14 | #include "lib/udptransport.h" 15 | #include "spec/replica.h" 16 | #include "vr/replica.h" 17 | #include "fastpaxos/replica.h" 18 | 19 | #include 20 | 21 | using namespace std; 22 | 23 | class TimeStampServer : public specpaxos::AppReplica 24 | { 25 | public: 26 | TimeStampServer(); 27 | ~TimeStampServer(); 28 | 29 | void ReplicaUpcall(opnum_t opnum, const string &str1, string &str2); 30 | void RollbackUpcall(opnum_t current, opnum_t to, const std::map &opMap); 31 | void CommitUpcall(opnum_t op); 32 | private: 33 | long ts; 34 | string newTimeStamp(); 35 | 36 | }; 37 | #endif /* _TIME_SERVER_H_ */ 38 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-2016 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 | } 49 | 50 | UnreplicatedClient::~UnreplicatedClient() 51 | { 52 | if (pendingRequest) { 53 | delete pendingRequest; 54 | } 55 | if (pendingUnloggedRequest) { 56 | delete pendingUnloggedRequest; 57 | } 58 | } 59 | 60 | void 61 | UnreplicatedClient::Invoke(const string &request, 62 | continuation_t continuation) 63 | { 64 | // XXX Can only handle one pending request for now 65 | if (pendingRequest != NULL) { 66 | Panic("Client only supports one pending request"); 67 | } 68 | 69 | pendingRequest = new PendingRequest(request, continuation); 70 | 71 | proto::RequestMessage reqMsg; 72 | reqMsg.mutable_req()->set_op(pendingRequest->request); 73 | reqMsg.mutable_req()->set_clientid(clientid); 74 | reqMsg.mutable_req()->set_clientreqid(0); 75 | 76 | // Unreplicated: just send to replica 0 77 | transport->SendMessageToReplica(this, 0, reqMsg); 78 | 79 | } 80 | 81 | void 82 | UnreplicatedClient::InvokeUnlogged(int replicaIdx, 83 | const string &request, 84 | continuation_t continuation, 85 | timeout_continuation_t timeoutContinuation, 86 | uint32_t timeout) 87 | { 88 | // XXX Can only handle one pending request for now 89 | if (pendingUnloggedRequest != NULL) { 90 | Panic("Client only supports one pending request"); 91 | } 92 | 93 | pendingUnloggedRequest = new PendingRequest(request, continuation); 94 | 95 | proto::UnloggedRequestMessage reqMsg; 96 | reqMsg.mutable_req()->set_op(pendingUnloggedRequest->request); 97 | reqMsg.mutable_req()->set_clientid(clientid); 98 | reqMsg.mutable_req()->set_clientreqid(0); 99 | 100 | // Unreplicated: just send to replica 0 101 | if (replicaIdx != 0) { 102 | Panic("Attempt to invoke unlogged operation on replica that doesn't exist"); 103 | } 104 | transport->SendMessageToReplica(this, 0, reqMsg); 105 | 106 | } 107 | 108 | void 109 | UnreplicatedClient::ReceiveMessage(const TransportAddress &remote, 110 | const string &type, 111 | const string &data) 112 | { 113 | static proto::ReplyMessage reply; 114 | static proto::UnloggedReplyMessage unloggedReply; 115 | 116 | if (type == reply.GetTypeName()) { 117 | reply.ParseFromString(data); 118 | HandleReply(remote, reply); 119 | } else if (type == unloggedReply.GetTypeName()) { 120 | unloggedReply.ParseFromString(data); 121 | HandleUnloggedReply(remote, unloggedReply); 122 | } else { 123 | Client::ReceiveMessage(remote, type, data); 124 | } 125 | } 126 | 127 | void 128 | UnreplicatedClient::HandleReply(const TransportAddress &remote, 129 | const proto::ReplyMessage &msg) 130 | { 131 | if (pendingRequest == NULL) { 132 | Warning("Received reply when no request was pending"); 133 | } 134 | 135 | Debug("Client received reply"); 136 | 137 | PendingRequest *req = pendingRequest; 138 | pendingRequest = NULL; 139 | 140 | req->continuation(req->request, msg.reply()); 141 | delete req; 142 | } 143 | 144 | void 145 | UnreplicatedClient::HandleUnloggedReply(const TransportAddress &remote, 146 | const proto::UnloggedReplyMessage &msg) 147 | { 148 | if (pendingUnloggedRequest == NULL) { 149 | Warning("Received unloggedReply when no request was pending"); 150 | } 151 | 152 | Debug("Client received unloggedReply"); 153 | 154 | PendingRequest *req = pendingUnloggedRequest; 155 | pendingUnloggedRequest = NULL; 156 | 157 | req->continuation(req->request, msg.reply()); 158 | delete req; 159 | } 160 | 161 | } // namespace specpaxos::unreplicated 162 | } // namespace specpaxos 163 | -------------------------------------------------------------------------------- /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-2016 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); 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 | 58 | protected: 59 | struct PendingRequest 60 | { 61 | string request; 62 | continuation_t continuation; 63 | inline PendingRequest(string request, continuation_t continuation) 64 | : request(request), continuation(continuation) { } 65 | }; 66 | PendingRequest *pendingRequest; 67 | PendingRequest *pendingUnloggedRequest; 68 | 69 | void HandleReply(const TransportAddress &remote, 70 | const proto::ReplyMessage &msg); 71 | void HandleUnloggedReply(const TransportAddress &remote, 72 | const proto::UnloggedReplyMessage &msg); 73 | }; 74 | 75 | } // namespace specpaxos::unreplicated 76 | } // namespace specpaxos 77 | 78 | #endif /* _UNREPLICATED_CLIENT_H_ */ 79 | -------------------------------------------------------------------------------- /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-2016 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 | Debug("Received request %s", (char *)msg.req().op().c_str()); 51 | 52 | Execute(0, msg.req(), reply); 53 | 54 | // The protocol defines these as required, even if they're not 55 | // meaningful. 56 | reply.set_view(0); 57 | reply.set_opnum(0); 58 | 59 | if (!(transport->SendMessage(this, remote, reply))) 60 | Warning("Failed to send reply message"); 61 | } 62 | 63 | void 64 | UnreplicatedReplica::HandleUnloggedRequest(const TransportAddress &remote, 65 | const proto::UnloggedRequestMessage &msg) 66 | { 67 | proto::UnloggedReplyMessage reply; 68 | 69 | Debug("Received unlogged request %s", (char *)msg.req().op().c_str()); 70 | 71 | ExecuteUnlogged(msg.req(), reply); 72 | 73 | if (!(transport->SendMessage(this, remote, reply))) 74 | Warning("Failed to send reply message"); 75 | } 76 | 77 | UnreplicatedReplica::UnreplicatedReplica(Configuration config, 78 | int myIdx, 79 | bool initialize, 80 | Transport *transport, 81 | AppReplica *app) 82 | : Replica(config, myIdx, initialize, transport, app) 83 | { 84 | if (!initialize) { 85 | Panic("Recovery does not make sense for unreplicated mode"); 86 | } 87 | 88 | this->status = STATUS_NORMAL; 89 | } 90 | 91 | void 92 | UnreplicatedReplica::ReceiveMessage(const TransportAddress &remote, 93 | const string &type, const string &data) 94 | { 95 | static proto::RequestMessage request; 96 | static proto::UnloggedRequestMessage unloggedRequest; 97 | 98 | if (type == request.GetTypeName()) { 99 | request.ParseFromString(data); 100 | HandleRequest(remote, request); 101 | } else if (type == unloggedRequest.GetTypeName()) { 102 | unloggedRequest.ParseFromString(data); 103 | HandleUnloggedRequest(remote, unloggedRequest); 104 | } else { 105 | Panic("Received unexpected message type in unreplicated proto: %s", 106 | type.c_str()); 107 | } 108 | } 109 | 110 | } // namespace specpaxos::unreplicated 111 | } // namespace specpaxos 112 | -------------------------------------------------------------------------------- /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-2016 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 | namespace specpaxos { 39 | namespace unreplicated { 40 | 41 | class UnreplicatedReplica : public Replica 42 | { 43 | public: 44 | UnreplicatedReplica(Configuration config, int myIdx, 45 | bool initialize, 46 | Transport *transport, AppReplica *app); 47 | void ReceiveMessage(const TransportAddress &remote, 48 | const string &type, const string &data); 49 | 50 | private: 51 | void HandleRequest(const TransportAddress &remote, 52 | const proto::RequestMessage &msg); 53 | void HandleUnloggedRequest(const TransportAddress &remote, 54 | const proto::UnloggedRequestMessage &msg); 55 | }; 56 | 57 | } // namespace specpaxos::unreplicated 58 | } // namespace specpaxos 59 | 60 | #endif /* _UNREPLICATED_REPLICA_H_ */ 61 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-2016 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 | 47 | static string replicaLastOp; 48 | static string clientLastOp; 49 | static string clientLastReply; 50 | static string replicaLastUnloggedOp; 51 | 52 | class UnrepTestApp : public AppReplica { 53 | public: 54 | UnrepTestApp() { }; 55 | ~UnrepTestApp() { }; 56 | 57 | void ReplicaUpcall(opnum_t opnum, const string &req, string &reply) { 58 | replicaLastOp = req; 59 | reply = "reply: " + req; 60 | } 61 | 62 | void UnloggedUpcall(const string &req, string &reply) { 63 | replicaLastUnloggedOp = req; 64 | reply = "unlreply: " + req; 65 | } 66 | }; 67 | 68 | static void ClientUpcallHandler(const string &req, const string &reply) 69 | { 70 | clientLastOp = req; 71 | clientLastReply = reply; 72 | } 73 | 74 | 75 | TEST(Unreplicated, OneOp) 76 | { 77 | std::vector replicaAddrs = 78 | { { "localhost", "12345" } }; 79 | Configuration c(1, 0, replicaAddrs); 80 | 81 | SimulatedTransport transport; 82 | 83 | UnrepTestApp app; 84 | 85 | UnreplicatedReplica replica(c, 0, true, &transport, &app); 86 | UnreplicatedClient client(c, &transport); 87 | 88 | client.Invoke(string("test"), ClientUpcallHandler); 89 | 90 | transport.Run(); 91 | 92 | EXPECT_EQ(replicaLastOp, "test"); 93 | EXPECT_EQ(clientLastOp, "test"); 94 | EXPECT_EQ(clientLastReply, "reply: test"); 95 | EXPECT_EQ(replicaLastUnloggedOp, ""); 96 | } 97 | 98 | TEST(Unreplicated, Unlogged) 99 | { 100 | std::vector replicaAddrs = 101 | { { "localhost", "12345" } }; 102 | Configuration c(1, 0, replicaAddrs); 103 | 104 | SimulatedTransport transport; 105 | UnrepTestApp app; 106 | 107 | UnreplicatedReplica replica(c, 0, true, &transport, &app); 108 | UnreplicatedClient client(c, &transport); 109 | 110 | client.InvokeUnlogged(0, string("test2"), ClientUpcallHandler); 111 | 112 | transport.Run(); 113 | 114 | EXPECT_EQ(replicaLastOp, "test"); 115 | EXPECT_EQ(replicaLastUnloggedOp, "test2"); 116 | EXPECT_EQ(clientLastOp, "test2"); 117 | EXPECT_EQ(clientLastReply, "unlreply: test2"); 118 | } 119 | -------------------------------------------------------------------------------- /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 bytes reply = 3; 13 | } 14 | 15 | message UnloggedRequestMessage { 16 | required specpaxos.UnloggedRequest req = 1; 17 | } 18 | 19 | message UnloggedReplyMessage { 20 | required bytes reply = 1; 21 | } 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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-2016 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 | { 144 | static proto::ReplyMessage reply; 145 | static proto::UnloggedReplyMessage unloggedReply; 146 | 147 | if (type == reply.GetTypeName()) { 148 | reply.ParseFromString(data); 149 | HandleReply(remote, reply); 150 | } else if (type == unloggedReply.GetTypeName()) { 151 | unloggedReply.ParseFromString(data); 152 | HandleUnloggedReply(remote, unloggedReply); 153 | } else { 154 | Client::ReceiveMessage(remote, type, data); 155 | } 156 | } 157 | 158 | void 159 | VRClient::HandleReply(const TransportAddress &remote, 160 | const proto::ReplyMessage &msg) 161 | { 162 | if (pendingRequest == NULL) { 163 | Warning("Received reply when no request was pending"); 164 | return; 165 | } 166 | if (msg.clientreqid() != pendingRequest->clientReqId) { 167 | Warning("Received reply for a different request"); 168 | return; 169 | } 170 | 171 | Debug("Client received reply"); 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 | VRClient::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 | VRClient::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 | -------------------------------------------------------------------------------- /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-2016 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); 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 | 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::vr 90 | } // namespace specpaxos 91 | 92 | #endif /* _VR_CLIENT_H_ */ 93 | -------------------------------------------------------------------------------- /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-2016 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 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | namespace specpaxos { 51 | namespace vr { 52 | 53 | class VRReplica : public Replica 54 | { 55 | public: 56 | VRReplica(Configuration config, int myIdx, bool initialize, 57 | Transport *transport, int batchSize, 58 | AppReplica *app); 59 | ~VRReplica(); 60 | 61 | void ReceiveMessage(const TransportAddress &remote, 62 | const string &type, const string &data); 63 | 64 | // asd123www: Kernel_Prepare func. 65 | void HandlePrepare_Kernel(const proto::PrepareMessage &msg); 66 | void HandleRequest(const TransportAddress &remote, 67 | const proto::RequestMessage &msg); 68 | 69 | private: 70 | view_t view; 71 | opnum_t lastCommitted; 72 | opnum_t lastOp; 73 | view_t lastRequestStateTransferView; 74 | opnum_t lastRequestStateTransferOpnum; 75 | uint64_t recoveryNonce; 76 | std::list > pendingPrepares; 78 | proto::PrepareMessage lastPrepare; 79 | int batchSize; 80 | opnum_t lastBatchEnd; 81 | bool batchComplete; 82 | 83 | // asd123www: about the eBPF. 84 | int prepare_buffer_fd, request_buffer_fd, paxos_ctr_state_fd; 85 | struct ring_buffer *rb_prepare; // struct ring_buffer * 86 | struct ring_buffer *rb_request; // struct ring_buffer * 87 | uint32_t sgn_bits[3]; 88 | 89 | Log log; 90 | std::map > clientAddresses; 91 | struct ClientTableEntry 92 | { 93 | uint64_t lastReqId; 94 | bool replied; 95 | proto::ReplyMessage reply; 96 | }; 97 | std::map clientTable; 98 | 99 | QuorumSet prepareOKQuorum; 100 | QuorumSet startViewChangeQuorum; 101 | QuorumSet doViewChangeQuorum; 102 | QuorumSet recoveryResponseQuorum; 103 | 104 | Timeout *viewChangeTimeout; 105 | Timeout *nullCommitTimeout; 106 | Timeout *stateTransferTimeout; 107 | Timeout *resendPrepareTimeout; 108 | Timeout *closeBatchTimeout; 109 | Timeout *recoveryTimeout; 110 | 111 | Latency_t requestLatency; 112 | Latency_t executeAndReplyLatency; 113 | 114 | uint64_t GenerateNonce() const; 115 | bool AmLeader() const; 116 | void CommitUpTo(opnum_t upto); 117 | void SendPrepareOKs(opnum_t oldLastOp); 118 | void SendRecoveryMessages(); 119 | void RequestStateTransfer(); 120 | void EnterView(view_t newview); 121 | void StartViewChange(view_t newview); 122 | void SendNullCommit(); 123 | void UpdateClientTable(const Request &req); 124 | void ResendPrepare(); 125 | void CloseBatch(); 126 | void ModifyKernelState(); 127 | 128 | void HandleUnloggedRequest(const TransportAddress &remote, 129 | const proto::UnloggedRequestMessage &msg); 130 | 131 | void HandlePrepare(const TransportAddress &remote, 132 | const proto::PrepareMessage &msg); 133 | void HandlePrepareOK(const TransportAddress &remote, 134 | const proto::PrepareOKMessage &msg); 135 | void HandleCommit(const TransportAddress &remote, 136 | const proto::CommitMessage &msg); 137 | void HandleRequestStateTransfer(const TransportAddress &remote, 138 | const proto::RequestStateTransferMessage &msg); 139 | void HandleStateTransfer(const TransportAddress &remote, 140 | const proto::StateTransferMessage &msg); 141 | void HandleStartViewChange(const TransportAddress &remote, 142 | const proto::StartViewChangeMessage &msg); 143 | void HandleDoViewChange(const TransportAddress &remote, 144 | const proto::DoViewChangeMessage &msg); 145 | void HandleStartView(const TransportAddress &remote, 146 | const proto::StartViewMessage &msg); 147 | void HandleRecovery(const TransportAddress &remote, 148 | const proto::RecoveryMessage &msg); 149 | void HandleRecoveryResponse(const TransportAddress &remote, 150 | const proto::RecoveryResponseMessage &msg); 151 | }; 152 | 153 | } // namespace specpaxos::vr 154 | } // namespace specpaxos 155 | 156 | #endif /* _VR_REPLICA_H_ */ 157 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | message LogEntry { 49 | required uint64 view = 1; 50 | required uint64 opnum = 2; 51 | required specpaxos.Request request = 3; 52 | optional uint32 state = 4; 53 | optional bytes hash = 5; 54 | } 55 | required uint64 view = 1; 56 | required uint64 opnum = 2; 57 | repeated LogEntry entries = 3; 58 | } 59 | 60 | message StartViewChangeMessage { 61 | required uint64 view = 1; 62 | required uint32 replicaIdx = 2; 63 | required uint64 lastCommitted = 3; 64 | } 65 | 66 | message DoViewChangeMessage { 67 | message LogEntry { 68 | required uint64 view = 1; 69 | required uint64 opnum = 2; 70 | required specpaxos.Request request = 3; 71 | optional uint32 state = 4; 72 | optional bytes hash = 5; 73 | } 74 | required uint64 view = 1; 75 | required uint64 lastNormalView = 2; 76 | required uint64 lastOp = 3; 77 | required uint64 lastCommitted = 4; 78 | repeated LogEntry entries = 5; 79 | required uint32 replicaIdx = 6; 80 | } 81 | 82 | message StartViewMessage { 83 | message LogEntry { 84 | required uint64 view = 1; 85 | required uint64 opnum = 2; 86 | required specpaxos.Request request = 3; 87 | optional uint32 state = 4; 88 | optional bytes hash = 5; 89 | } 90 | required uint64 view = 1; 91 | required uint64 lastOp = 2; 92 | required uint64 lastCommitted = 3; 93 | repeated LogEntry entries = 4; 94 | } 95 | 96 | message RecoveryMessage { 97 | required uint32 replicaIdx = 1; 98 | required uint64 nonce = 2; 99 | } 100 | 101 | message RecoveryResponseMessage { 102 | message LogEntry { 103 | required uint64 view = 1; 104 | required uint64 opnum = 2; 105 | required specpaxos.Request request = 3; 106 | optional uint32 state = 4; 107 | optional bytes hash = 5; 108 | } 109 | required uint64 view = 1; 110 | required uint64 nonce = 2; 111 | repeated LogEntry entries = 3; 112 | optional uint64 lastOp = 4; 113 | optional uint64 lastCommitted = 5; 114 | required uint32 replicaIdx = 6; 115 | } 116 | -------------------------------------------------------------------------------- /xdp-handler/Makefile: -------------------------------------------------------------------------------- 1 | # Software Name : bmc-cache 2 | # SPDX-FileCopyrightText: Copyright (c) 2021 Orange 3 | # SPDX-License-Identifier: LGPL-2.1-only 4 | # 5 | # This software is distributed under the 6 | # GNU Lesser General Public License v2.1 only. 7 | # 8 | # Author: Yoann GHIGOFF et al. 9 | # 10 | # To use this Makefile: clang and llvm must be installed, 11 | # kernel sources available under ./linux and libbpf statically 12 | # compiled in Linux source tree. 13 | # 14 | # bmc_kern.c depends on kernel headers and bpf_helpers.h 15 | # bmc_user.c depends on libbpf 16 | 17 | LINUX_PATH ?= ./linux 18 | LINUX_TOOLS_PATH = $(LINUX_PATH)/tools 19 | LINUX_LIB_PATH = $(LINUX_TOOLS_PATH)/lib 20 | LIBBPF_PATH = $(LINUX_LIB_PATH)/bpf 21 | 22 | TARGETS += fast 23 | 24 | CLANG ?= clang 25 | LLC ?= llc 26 | CC := gcc 27 | 28 | KERN_SOURCES = ${TARGETS:=_kern.c} 29 | USER_SOURCES = ${TARGETS:=_user.c} 30 | KERN_OBJECTS = ${KERN_SOURCES:.c=.o} 31 | USER_OBJECTS = ${USER_SOURCES:.c=.o} 32 | 33 | LIBBPF = $(LIBBPF_PATH)/libbpf.a 34 | 35 | # CFLAGS := -g -O3 -Wall -DKBUILD_MODNAME="\"wzz\"" 36 | override CFLAGS += -g -O3 -Wall -DKBUILD_MODNAME="\"wzz\"" 37 | override CFLAGS += -I. 38 | override CFLAGS += -I$(LINUX_LIB_PATH) 39 | override CFLAGS += -I$(LINUX_TOOLS_PATH)/include/uapi 40 | # CFLAGS += -I$(LINUX_TOOLS_PATH)/include 41 | # CFLAGS += -I$(LINUX_PATH)/include 42 | # CFLAGS += -fno-pie 43 | LDFLAGS ?= -L$(LIBBPF_PATH) -l:libbpf.a -lelf $(USER_LIBS) -lz 44 | 45 | NOSTDINC_FLAGS := -nostdinc -isystem $(shell $(CC) -print-file-name=include) 46 | ARCH=$(shell uname -m | sed 's/x86_64/x86/' | sed 's/i386/x86/') 47 | 48 | LINUXINCLUDE := -I$(LINUX_PATH)/arch/$(ARCH)/include 49 | LINUXINCLUDE += -I$(LINUX_PATH)/arch/$(ARCH)/include/uapi 50 | LINUXINCLUDE += -I$(LINUX_PATH)/arch/$(ARCH)/include/generated 51 | LINUXINCLUDE += -I$(LINUX_PATH)/arch/$(ARCH)/include/generated/uapi 52 | LINUXINCLUDE += -I$(LINUX_PATH)/include 53 | LINUXINCLUDE += -I$(LINUX_PATH)/include/uapi 54 | LINUXINCLUDE += -I$(LINUX_PATH)/include/generated/uapi 55 | LINUXINCLUDE += -I$(LINUX_PATH)/tools/testing/selftests/bpf 56 | LINUXINCLUDE += -include $(LINUX_PATH)/include/linux/kconfig.h 57 | LINUXINCLUDE += -include $(LINUX_PATH)/samples/bpf/asm_goto_workaround.h 58 | 59 | # EXTRA_CFLAGS=-Werror 60 | override EXTRA_CFLAGS += -Werror 61 | 62 | ### 63 | 64 | all: dependencies $(TARGETS) $(KERN_OBJECTS) 65 | 66 | .PHONY: clean dependencies verify_cmds verify_target_bpf $(CLANG) $(LLC) 67 | 68 | clean: 69 | @find . -type f \ 70 | \( -name '*~' \ 71 | -o -name '*.ll' \ 72 | -o -name '*.bc' \ 73 | -o -name 'core' \) \ 74 | -exec rm -vf '{}' \; 75 | rm -f $(TARGETS) 76 | rm -f $(KERN_OBJECTS) 77 | rm -f $(USER_OBJECTS) 78 | rm -f $(OBJECT_LOADBPF) 79 | sudo rm -f /sys/fs/bpf/paxos_prepare_buffer 80 | sudo rm -f /sys/fs/bpf/paxos_request_buffer 81 | sudo rm -f /sys/fs/bpf/paxos_ctr_state 82 | sudo rm -f /sys/fs/bpf/FastBroadCast 83 | 84 | dependencies: verify_target_bpf 85 | 86 | linux-src: 87 | @if ! test -d $(LINUX_PATH)/; then \ 88 | echo "ERROR: Need kernel source code to compile against" ;\ 89 | echo "(Cannot open directory: $(LINUX_PATH))" ;\ 90 | exit 1; \ 91 | else true; fi 92 | 93 | linux-src-libbpf: linux-src 94 | @if ! test -d $(LIBBPF_PATH); then \ 95 | echo "WARNING: Compile against local kernel source code copy" ;\ 96 | echo " and specifically tools/lib/bpf/ "; \ 97 | else true; fi 98 | 99 | verify_cmds: $(CLANG) $(LLC) 100 | @for TOOL in $^ ; do \ 101 | if ! (which -- "$${TOOL}" > /dev/null 2>&1); then \ 102 | echo "*** ERROR: Cannot find LLVM tool $${TOOL}" ;\ 103 | exit 1; \ 104 | else true; fi; \ 105 | done 106 | 107 | verify_target_bpf: verify_cmds 108 | @if ! (${LLC} -march=bpf -mattr=help > /dev/null 2>&1); then \ 109 | echo "*** ERROR: LLVM (${LLC}) does not support 'bpf' target" ;\ 110 | echo " NOTICE: LLVM version >= 3.7.1 required" ;\ 111 | exit 2; \ 112 | else true; fi 113 | 114 | $(LIBBPF): $(wildcard $(LIBBPF_PATH)/*.[ch] $(LIBBPF_PATH)/Makefile) 115 | make -C $(LIBBPF_PATH) 116 | 117 | # Compiling of eBPF restricted-C code with LLVM 118 | # clang option -S generated output file with suffix .ll 119 | # which is the non-binary LLVM assembly language format 120 | # (normally LLVM bitcode format .bc is generated) 121 | # 122 | # Use -Wno-address-of-packed-member as eBPF verifier enforces 123 | # unaligned access checks where necessary 124 | # 125 | $(KERN_OBJECTS): %.o: %.c 126 | $(CLANG) -S $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \ 127 | -D__KERNEL__ -D__ASM_SYSREG_H -D__BPF_TRACING__ -DKBUILD_MODNAME="\"wzz\"" \ 128 | -D__TARGET_ARCH_$(ARCH) \ 129 | -Wno-unused-value -Wno-pointer-sign \ 130 | -Wno-compare-distinct-pointer-types \ 131 | -Wno-gnu-variable-sized-type-not-at-end \ 132 | -Wno-tautological-compare \ 133 | -Wno-unknown-warning-option \ 134 | -Wno-address-of-packed-member \ 135 | -O3 -g -emit-llvm -c $< -o ${@:.o=.ll} 136 | $(LLC) -march=bpf -filetype=obj -o $@ ${@:.o=.ll} 137 | 138 | $(TARGETS): %: %_user.c $(OBJECTS) $(LIBBPF) 139 | $(CC) $(CFLAGS) $(OBJECTS) -o $@ $< $(LIBBPF) $(LDFLAGS) -------------------------------------------------------------------------------- /xdp-handler/fast_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Software Name : fast-paxos 3 | * SPDX-FileCopyrightText: Copyright (c) 2022 Orange 4 | * SPDX-License-Identifier: LGPL-2.1-only 5 | * 6 | * This software is distributed under the 7 | * GNU Lesser General Public License v2.1 only. 8 | * 9 | * Author: asd123www et al. 10 | */ 11 | 12 | #ifndef _FAST_COMMON_H 13 | #define _FAST_COMMON_H 14 | 15 | #define ETH_ALEN 6 /* Octets in one ethernet addr */ 16 | 17 | #define CLUSTER_SIZE 3 // need 18 | #define FAST_REPLICA_MAX 100 // max # of replicas. 19 | #define NONFRAG_MAGIC 0x20050318 20 | #define FRAG_MAGIC 0x20101010 21 | 22 | 23 | #define MAGIC_LEN 4 24 | #define REQUEST_TYPE_LEN 33 25 | #define PREPARE_TYPE_LEN 33 26 | #define PREPAREOK_TYPE_LEN 35 27 | #define MYPREPAREOK_TYPE_LEN 24 28 | 29 | #define FAST_PAXOS_DATA_LEN 12 30 | #define BROADCAST_SIGN_BIT (1<<31) 31 | #define QUORUM_SIZE ((CLUSTER_SIZE + 1) >> 1) 32 | #define QUORUM_BITSET_ENTRY 1024 // must be 2^t 33 | 34 | 35 | enum ReplicaStatus { 36 | STATUS_NORMAL, 37 | STATUS_VIEW_CHANGE, 38 | STATUS_RECOVERING 39 | }; 40 | 41 | 42 | 43 | enum { 44 | FAST_PROG_XDP_HANDLE_PREPARE = 0, 45 | FAST_PROG_XDP_HANDLE_REQUEST, 46 | FAST_PROG_XDP_HANDLE_PREPAREOK, 47 | FAST_PROG_XDP_WRITE_BUFFER, 48 | FAST_PROG_XDP_PREPARE_REPLY, 49 | 50 | FAST_PROG_XDP_MAX 51 | }; 52 | 53 | enum { 54 | FAST_PROG_TC_BROADCAST = 0, 55 | 56 | FAST_PROG_TC_MAX 57 | }; 58 | 59 | struct paxos_configure { 60 | __u32 addr; // ipv4. 61 | __u16 port; 62 | char eth[ETH_ALEN]; 63 | }; 64 | 65 | #endif 66 | --------------------------------------------------------------------------------