├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── README.md ├── README_CN.md ├── _config.yml └── floyd ├── Makefile ├── example ├── kv │ ├── Makefile │ ├── README │ ├── cli.cc │ ├── kv_cli.cc │ ├── kv_cli.h │ ├── kv_server.cc │ ├── kv_server.h │ ├── logger.h │ ├── manager.sh │ ├── pr.sh │ ├── sdk.proto │ └── srv.cc ├── redis │ ├── Makefile │ ├── README.md │ ├── raftis.cc │ └── run.sh └── simple │ ├── Makefile │ ├── README.md │ ├── add_server.cc │ ├── add_server1.cc │ ├── read_bench.cc │ ├── remove_server.cc │ ├── t.cc │ ├── t1.cc │ ├── t2.cc │ ├── t3.cc │ ├── t4.cc │ ├── t5.cc │ ├── t6.cc │ ├── t7.cc │ ├── t8.cc │ ├── test_lock.cc │ ├── test_lock1.cc │ └── test_lock2.cc ├── include ├── floyd.h ├── floyd_options.h └── version.h ├── proto ├── floyd.proto └── pr.sh ├── src ├── build_version.cc.in ├── build_version.h ├── floyd.pb.cc ├── floyd.pb.h ├── floyd_apply.cc ├── floyd_apply.h ├── floyd_client_pool.cc ├── floyd_client_pool.h ├── floyd_context.cc ├── floyd_context.h ├── floyd_impl.cc ├── floyd_impl.h ├── floyd_options.cc ├── floyd_peer_thread.cc ├── floyd_peer_thread.h ├── floyd_primary_thread.cc ├── floyd_primary_thread.h ├── floyd_worker.cc ├── floyd_worker.h ├── logger.cc ├── logger.h ├── raft_log.cc ├── raft_log.h ├── raft_meta.cc └── raft_meta.h └── tools ├── Makefile ├── README ├── cl.cc ├── cl1.cc ├── cpt.cc ├── read_floyd.cc └── read_rock.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | gmon.out 30 | 31 | # Examples 32 | floyd/example/kv/sdk.pb.cc 33 | floyd/example/kv/sdk.pb.h 34 | *cpt 35 | *read_floyd 36 | *read_rock 37 | *t 38 | *t1 39 | *t2 40 | 41 | floyd/src/build_version.cc 42 | floyd/example/redis/deploy.sh 43 | 44 | tags 45 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "floyd/third/slash"] 2 | path = floyd/third/slash 3 | url = https://github.com/baotiao/slash.git 4 | branch = v1.0-rc2 5 | [submodule "floyd/third/pink"] 6 | path = floyd/third/pink 7 | url = https://github.com/Qihoo360/pink.git 8 | [submodule "floyd/third/rocksdb"] 9 | path = floyd/third/rocksdb 10 | url = https://github.com/facebook/rocksdb.git 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: cpp 4 | 5 | os: 6 | - linux 7 | 8 | addons: 9 | apt: 10 | packages: ['zlib1g-dev', 'libbz2-dev', 'libsnappy-dev', 'curl', 'libprotobuf-dev', 'protobuf-compiler'] 11 | 12 | compiler: 13 | - gcc 14 | 15 | language: cpp 16 | 17 | script: 18 | cd floyd && make 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Floyd [中文](https://github.com/Qihoo360/floyd/blob/master/README_CN.md) 2 | 3 | [![Build Status](https://travis-ci.org/Qihoo360/floyd.svg?branch=master)](https://travis-ci.org/Qihoo360/floyd) 4 | 5 | Floyd is an C++ library based on Raft consensus protocol. 6 | 7 | * [Raft](https://raft.github.io/) is a consensus algorithm which is easy to understand; 8 | * Floyd is a **library** that could be easily embeded into users' application; 9 | * Floyd support consistency between cluster nodes by APIs like Read/Write/Delete; 10 | * Also some query and debug managment APIs: GetLeader/GetServerStatus/set_log_level 11 | * Floyd support lock operation upon raft consensus protocol 12 | 13 | ## Users 14 | 15 | * Floyd has provided high available store for Meta cluster of [Zeppelin](https://github.com/Qihoo360/zeppelin) , which is a huge distributed key-value storage. 16 | * Floyd lock interface has used in our production pika_hub 17 | * The list will goes on. 18 | 19 | ## Why do we prefer a library to a service? 20 | 21 | When we want to coordinate services, ZooKeeper is always a good choice. 22 | * But we have to maintain another service. 23 | * We must use its' SDK at the same time. 24 | 25 | In our opion, a single service is much more simple than two services. As a result, an embeded library could be a better choice. 26 | 27 | 28 | ## Floyd's Features and APIs 29 | 30 | * APIs and [usage](https://github.com/PikaLabs/floyd/wiki/API%E4%BB%8B%E7%BB%8D%E4%B8%8E%E4%BD%BF%E7%94%A8) 31 | 32 | | type | API | Status | 33 | | --------- | --------------- | ------- | 34 | | Consensus | Read | support | 35 | | Consensus | Write | support | 36 | | Consensus | Delete | support | 37 | | Local | DirtyRead | support | 38 | | Local | DirtyWrite | support | 39 | | Query | GetLeader | support | 40 | | Query | GetServerStatus | support | 41 | | Debug | set_log_level | support | 42 | 43 | * Raft fetaures 44 | 45 | | Language | Leader election + Log Replication | Membership Changes | Log Compaction | 46 | | -------- | --------------------------------- | ------------------ | -------------- | 47 | | C++ | Yes | No | No | 48 | 49 | 50 | ## Compile and Have a Try 51 | 52 | * Dependencies 53 | - gcc version 4.8+ to support C++11. 54 | - protobuf-devel 55 | - snappy-devel 56 | - bzip2-devel 57 | - zlib-devel 58 | - bzip2 59 | - submodules: 60 |        - [Pink](https://github.com/PikaLabs/pink) 61 |        - [Slash](https://github.com/PikaLabs/slash) 62 | 63 | 64 | * Get source code and submodules recursively. 65 | ```powershell 66 | git clone --recursive https://github.com/Qihoo360/floyd.git 67 | ``` 68 | * Compile and get the libfloyd.a library 69 | ``` 70 | make 71 | ``` 72 | 73 | ### Example 74 | 75 | Then right now there is three examples in the example directory, go and compile in the corresponding directory 76 | 77 | #### example/simple/ 78 | 79 | contains many cases wrapped floyd into small example 80 | 81 | Get all simple example will make command, then every example will start floyd with five node 82 | 83 | ``` 84 | make 85 | ``` 86 | 87 | 1. t is a single thread wirte tool to get performance 88 | 2. t1 is multi thread program to get performance, in this case, all the writes is from the leader node 89 | 3. t2 is an example test node join and leave 90 | 4. t4 is an example used to see the message passing by each node in a stable situation 91 | 5. t5 used to test single mode floyd, including starting a node and writing data 92 | 6. t6 is the same as t1 except that all the writes is from the follower node 93 | 7. t7 test write 3 node and then join the other 2 node case 94 | 95 | #### example/redis/ 96 | 97 | raftis is a consensus server with 5 nodes and supporting redis protocol(get/set command). raftis is an example of building a consensus cluster with floyd(floyd is a simple implementation of raft protocol). It's very simple and intuitive. we can test raftis with redis-cli, benchmark with redis redis-benchmark tools. 98 | 99 | compile raftis with command make and then start with run.sh 100 | 101 | ``` 102 | make && sh run.sh 103 | ``` 104 | 105 | ``` 106 | #!/bin/sh 107 | # start with five node 108 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8901 "./data1/" 6379 & 109 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8902 "./data2/" 6479 & 110 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8903 "./data3/" 6579 & 111 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8904 "./data4/" 6679 & 112 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8905 "./data5/" 6779 & 113 | ``` 114 | 115 | 116 | ``` 117 | └─[$] ./src/redis-benchmark -t set -n 1000000 -r 100000000 -c 20 118 | ====== SET ====== 119 | 1000000 requests completed in 219.76 seconds 120 | 20 parallel clients 121 | 3 bytes payload 122 | keep alive: 1 123 | 124 | 0.00% <= 2 milliseconds 125 | 0.00% <= 3 milliseconds 126 | 8.72% <= 4 milliseconds 127 | 95.39% <= 5 milliseconds 128 | 95.96% <= 6 milliseconds 129 | 99.21% <= 7 milliseconds 130 | 99.66% <= 8 milliseconds 131 | 99.97% <= 9 milliseconds 132 | 99.97% <= 11 milliseconds 133 | 99.97% <= 12 milliseconds 134 | 99.97% <= 14 milliseconds 135 | 99.97% <= 15 milliseconds 136 | 99.99% <= 16 milliseconds 137 | 99.99% <= 17 milliseconds 138 | 99.99% <= 18 milliseconds 139 | 99.99% <= 19 milliseconds 140 | 99.99% <= 26 milliseconds 141 | 99.99% <= 27 milliseconds 142 | 100.00% <= 28 milliseconds 143 | 100.00% <= 29 milliseconds 144 | 100.00% <= 30 milliseconds 145 | 100.00% <= 61 milliseconds 146 | 100.00% <= 62 milliseconds 147 | 100.00% <= 63 milliseconds 148 | 100.00% <= 63 milliseconds 149 | 4550.31 requests per second 150 | ``` 151 | #### example/kv/ 152 | 153 | A simple consensus kv example contain server and client builded with floyd 154 | 155 | ## Test 156 | floyd has pass the jepsen test, you can get the test case here 157 | [jepsen](https://github.com/gaodq/jepsen) 158 | 159 | ## Documents 160 | * [Wikis](https://github.com/PikaLabs/floyd/wiki) 161 | 162 | ## Contant us 163 | 164 | Anyone who is interested in raft protocol, used floyd in your production or has wrote some article about souce code of floyd please contact me, we have a article list. 165 | 166 | * email: g-infra-bada@360.cn 167 | * QQ Group: 294254078 168 | * WeChat public: 360基础架构组 169 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # Floyd 中文 2 | 3 | Floyd是一个C++实现的Raft一致性协议库。 4 | 5 | * [Raft](https://raft.github.io/)是一个相对于Paxos更容易理解和工程实现的一致性算法; 6 | * Floyd是一个一致性**库**,可以很容易引入到各种项目; 7 | * Floyd支持集群节点之间的一致性操作,例如:Read/Write/Delete; 8 | * 同时也支持非一致性的本地数据访问接口: DirtyRead/DirtyWrite; 9 | * 以及查询、管理接口:GetLeader/GetServerStatus/set_log_level 10 | 11 | ## 用户 12 | 13 | * Floyd 目前应用在[Zeppelin](https://github.com/Qihoo360/zeppelin)中,为其Meta集群提供一致性的存储;Zeppeli是一个大容量的分布式key-value存储; 14 | * 陆续会有新的项目在使用; 15 | 16 | ## 我们为什么倾向于库,而不是一个服务? 17 | 18 | 当我们在有服务发现、协调和管理的需求时,ZooKeeper是一个很好的选择,但是有一定成本. 19 | * 我们必须维护一套新的ZooKeeper的服务; 20 | * 我们也必须使用其SDK,去和ZooKeeper服务交互; 21 | 22 | 我们认为,一个集成、单一的服务通常会比多个服务更加可控、简单. 所以,作为一个库来使用,能够简化整体的架构. 23 | 24 | 25 | ## Floyd功能和API 26 | 27 | * API和[具体使用](https://github.com/Qihoo360/floyd/wiki/API%E4%BB%8B%E7%BB%8D%E4%B8%8E%E4%BD%BF%E7%94%A8) 28 | 29 | | type | API | Status | 30 | | ----- | --------------- | ------ | 31 | | 一致性接口 | Read | 支持 | 32 | | 一致性接口 | Write | 支持 | 33 | | 一致性接口 | Delete | 支持 | 34 | | 本地接口 | DirtyRead | 支持 | 35 | | 本地接口 | DirtyWrite | 支持 | 36 | | 查询 | GetLeader | 支持 | 37 | | 查询 | GetServerStatus | 支持 | 38 | | 调试 | set_log_level | 支持 | 39 | 40 | * Raft的功能特性 41 | 42 | | Language | Leader election + Log Replication | Membership Changes | Log Compaction | 43 | | -------- | --------------------------------- | ------------------ | -------------- | 44 | | C++ | Yes | No | No | 45 | 46 | 47 | ## 编译运行 48 | 49 | * 依赖 50 | - gcc 版本4.8+,以支持C++11. 51 | - protobuf-devel 52 | - snappy-devel 53 | - bzip2-devel 54 | - zlib-devel 55 | - bzip2 56 | - submodules: 57 | - [Pink](https://github.com/Qihoo360/pink) 58 | - [Slash](https://github.com/Qihoo360/slash) 59 | 60 | 61 | * 1) 拉取代码及子模块依赖. 62 | ```powershell 63 | git clone --recursive https://github.com/Qihoo360/floyd.git 64 | ``` 65 | * 2) 编译Floyd库, 并且获得静态库libfloyd.a 66 | ```powershell 67 | make 68 | ``` 69 | 70 | ### 示例 71 | 72 | 目前我们实现了3个使用floyd 的例子, 在example/ 目录下面, 可以直接去对应的目录进行编译使用 73 | 74 | #### example/simple/ 75 | 76 | 这个simple 示例主要包含好几个本机就能够运行的使用floyd 的例子. 77 | 在这些例子里面, 都会在一个进程启动5个 floyd 对象, 然后会有对象的停止, 重新启动等等操作来观察floyd 的一致性 78 | 79 | 执行 make 就可以编译所以的示例.在 output/bin/ 目录下面 80 | ``` 81 | make 82 | ``` 83 | 84 | 1. t 是标准的示例, 运行起来以后会启动5个节点, 然后会不断的写入数据, 并统计QPS 以及展示集群目前的状态信息 85 | 2. t1 是一个多线程压测的示例, 在这例子里面, write 是直接写入到Leader node的, 在我们的机器上, 可以获得差不多2w 的性能 86 | 3. t2 这个例子主要用来示范节点的加入和删除操作是否正常, 可以通过观看每一个节点的LOG 信息来看raft 协议的过程 87 | 4. t4 是节点起来以后就不做任何操作的稳定的raft 集群, 通常用来查看raft 协议中传输的消息, 可以通过看每一个节点的LOG 信息来看一个稳定运行的raft 集群的日志信息. t4 也经常用来配合tools 下面的cl 来生成不同的raft log 来验证raft 的log 不一致的情况下, 如何进行log replication 88 | 5. t5 是用来示例单节点的floyd 运行以及写入数据 89 | 6. t6 是和t1 一样是一个多线程压测的示例, 但是写入是从客户端写入, 因此性能会比t1 要来的差, 在我们的机器上, 差不多可以是5500 的性能 90 | 7. t7 同样用来测试节点的加入和退出, 但是会在节点退出以后继续写入数据, 验证3个节点存活, 然后又有2个节点加入的过程 91 | 92 | #### example/redis/ 93 | 94 | raftis 是一个5个节点的floyd server. raftis 支持redis 协议里面的get, set 命令. 95 | raftis 是一个使用floyd 构建一致性集群的示例, 一般使用floyd 我们都推荐这么用, 非常的简单. raftis 可以直接使用 reids-cli, redis-benchmark 进行压测 96 | 97 | 98 | 使用make 编译 raftis, 然后运行run.sh 可以启动5个节点. 当然这里运行的5个节点都在本地, 你完全可以在5个不同的机器运行这5个节点 99 | 100 | ``` 101 | make 102 | sh run.sh 103 | ``` 104 | 105 | ``` 106 | #!/bin/sh 107 | # start with five node 108 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8901 "./data1/" 6379 & 109 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8902 "./data2/" 6479 & 110 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8903 "./data3/" 6579 & 111 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8904 "./data4/" 6679 & 112 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8905 "./data5/" 6779 & 113 | ``` 114 | 115 | 116 | ``` 117 | └─[$] ./src/redis-benchmark -t set -n 1000000 -r 100000000 -c 20 118 | ====== SET ====== 119 | 1000000 requests completed in 219.76 seconds 120 | 20 parallel clients 121 | 3 bytes payload 122 | keep alive: 1 123 | 124 | 0.00% <= 2 milliseconds 125 | 0.00% <= 3 milliseconds 126 | 8.72% <= 4 milliseconds 127 | 95.39% <= 5 milliseconds 128 | 95.96% <= 6 milliseconds 129 | 99.21% <= 7 milliseconds 130 | 99.66% <= 8 milliseconds 131 | 99.97% <= 9 milliseconds 132 | 99.97% <= 11 milliseconds 133 | 99.97% <= 12 milliseconds 134 | 99.97% <= 14 milliseconds 135 | 99.97% <= 15 milliseconds 136 | 99.99% <= 16 milliseconds 137 | 99.99% <= 17 milliseconds 138 | 99.99% <= 18 milliseconds 139 | 99.99% <= 19 milliseconds 140 | 99.99% <= 26 milliseconds 141 | 99.99% <= 27 milliseconds 142 | 100.00% <= 28 milliseconds 143 | 100.00% <= 29 milliseconds 144 | 100.00% <= 30 milliseconds 145 | 100.00% <= 61 milliseconds 146 | 100.00% <= 62 milliseconds 147 | 100.00% <= 63 milliseconds 148 | 100.00% <= 63 milliseconds 149 | 4550.31 requests per second 150 | ``` 151 | #### example/kv/ 152 | 153 | 一个使用floyd 实现强一致协议的server, 包含server, client 154 | 155 | 156 | 157 | ## 文档 158 | * [Wikis](https://github.com/Qihoo360/floyd/wiki) 159 | 160 | ## 联系我们 161 | 162 | * email: g-infra-bada@360.cn 163 | * QQ Group: 294254078 164 | * WeChat public: 360基础架构组 165 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-tactile -------------------------------------------------------------------------------- /floyd/Makefile: -------------------------------------------------------------------------------- 1 | CLEAN_FILES = # deliberately empty, so we can append below. 2 | CC=cc 3 | CXX=g++ 4 | LDFLAGS= -lpthread -lrt -lprotobuf 5 | CFLAGS= -fno-builtin-memcmp -msse -msse4.2 6 | CXXFLAGS= -std=c++11 -fno-builtin-memcmp -msse -msse4.2 7 | PROFILING_FLAGS=-pg 8 | ARFLAGS = rs 9 | OPT= 10 | 11 | # Set the default DEBUG_LEVEL to 0 12 | DEBUG_LEVEL?=0 13 | 14 | ifeq ($(MAKECMDGOALS),dbg) 15 | DEBUG_LEVEL=2 # compatible with rocksdb 16 | endif 17 | 18 | # compile with -O2 if for release 19 | # if we're compiling for release, compile without debug code (-DNDEBUG) and 20 | # don't treat warnings as errors 21 | ifeq ($(DEBUG_LEVEL),0) 22 | DISABLE_WARNING_AS_ERROR=1 23 | OPT += -O2 -fno-omit-frame-pointer -DNDEBUG 24 | OPT += -DLOG_LEVEL=LEVEL_INFO 25 | else 26 | $(warning Warning: Compiling in debug mode. Don't use the resulting binary in production) 27 | OPT += -O0 -D__XDEBUG__ -DLOG_LEVEL=LEVEL_DEBUG $(PROFILING_FLAGS) 28 | endif 29 | 30 | # for rocksdb 31 | OPT += -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX 32 | 33 | #----------------------------------------------- 34 | 35 | SRC_DIR=./src 36 | LIB_SOURCES := $(SRC_DIR)/build_version.cc \ 37 | $(wildcard $(SRC_DIR)/*.cc) \ 38 | $(wildcard $(SRC_DIR)/*.c) \ 39 | 40 | ifndef SLASH_PATH 41 | $(warning Warning: slash path missing, using default) 42 | SLASH_PATH=$(CURDIR)/third/slash 43 | endif 44 | SLASH_INCLUDE_DIR=$(SLASH_PATH) 45 | SLASH_LIBRARY=$(SLASH_PATH)/slash/lib/libslash.a 46 | 47 | ifndef PINK_PATH 48 | $(warning Warning: slash path missing, using default) 49 | PINK_PATH=$(CURDIR)/third/pink 50 | endif 51 | PINK_INCLUDE_DIR=$(PINK_PATH) 52 | PINK_LIBRARY=$(PINK_PATH)/pink/lib/libpink.a 53 | 54 | ifndef ROCKSDB_PATH 55 | $(warning Warning: rocksdb path missing, using default) 56 | ROCKSDB_PATH=$(CURDIR)/third/rocksdb 57 | endif 58 | ROCKSDB_INCLUDE_DIR=$(ROCKSDB_PATH)/include 59 | ROCKSDB_LIBRARY=$(ROCKSDB_PATH)/librocksdb.a 60 | 61 | AM_DEFAULT_VERBOSITY = 0 62 | 63 | AM_V_GEN = $(am__v_GEN_$(V)) 64 | am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) 65 | am__v_GEN_0 = @echo " GEN " $@; 66 | am__v_GEN_1 = 67 | AM_V_at = $(am__v_at_$(V)) 68 | am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) 69 | am__v_at_0 = @ 70 | am__v_at_1 = 71 | 72 | AM_V_CC = $(am__v_CC_$(V)) 73 | am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) 74 | am__v_CC_0 = @echo " CC " $@; 75 | am__v_CC_1 = 76 | CCLD = $(CC) 77 | LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ 78 | AM_V_CCLD = $(am__v_CCLD_$(V)) 79 | am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) 80 | am__v_CCLD_0 = @echo " CCLD " $@; 81 | am__v_CCLD_1 = 82 | AM_V_AR = $(am__v_AR_$(V)) 83 | am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY)) 84 | am__v_AR_0 = @echo " AR " $@; 85 | am__v_AR_1 = 86 | 87 | AM_LINK = $(AM_V_CCLD)$(CXX) $^ $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) 88 | 89 | CFLAGS += -g 90 | CXXFLAGS += -g 91 | 92 | # This (the first rule) must depend on "all". 93 | default: all 94 | 95 | WARNING_FLAGS = -W -Wextra -Wall -Wsign-compare \ 96 | -Wno-unused-parameter -Wno-redundant-decls -Wwrite-strings \ 97 | -Wpointer-arith -Wreorder -Wswitch -Wsign-promo 98 | 99 | ifndef DISABLE_WARNING_AS_ERROR 100 | WARNING_FLAGS += -Werror 101 | endif 102 | 103 | CFLAGS += $(WARNING_FLAGS) -I.. -I$(SLASH_INCLUDE_DIR) -I$(PINK_INCLUDE_DIR) -I$(ROCKSDB_INCLUDE_DIR) $(OPT) 104 | CXXFLAGS += $(WARNING_FLAGS) -I.. -I$(SLASH_INCLUDE_DIR) -I$(PINK_INCLUDE_DIR) -I$(ROCKSDB_INCLUDE_DIR) $(OPT) \ 105 | -Woverloaded-virtual -Wnon-virtual-dtor -Wno-missing-field-initializers 106 | 107 | date := $(shell date +%F) 108 | git_sha := $(shell git rev-parse HEAD 2>/dev/null) 109 | gen_build_version = sed -e s/@@GIT_SHA@@/$(git_sha)/ -e s/@@GIT_DATE_TIME@@/$(date)/ $(SRC_DIR)/build_version.cc.in 110 | # Record the version of the source that we are compiling. 111 | # We keep a record of the git revision in this file. It is then built 112 | # as a regular source file as part of the compilation process. 113 | # One can run "strings executable_filename | grep _build_" to find 114 | # the version of the source that we used to build the executable file. 115 | CLEAN_FILES += $(SRC_DIR)/build_version.cc 116 | 117 | $(SRC_DIR)/build_version.cc: FORCE 118 | $(AM_V_GEN)rm -f $@-t 119 | $(AM_V_at)$(gen_build_version) > $@-t 120 | $(AM_V_at)if test -f $@; then \ 121 | cmp -s $@-t $@ && rm -f $@-t || mv -f $@-t $@; \ 122 | else mv -f $@-t $@; fi 123 | FORCE: 124 | 125 | LIBOBJECTS = $(LIB_SOURCES:.cc=.o) 126 | 127 | # if user didn't config LIBNAME, set the default 128 | ifeq ($(LIBNAME),) 129 | # we should only run floyd in production with DEBUG_LEVEL 0 130 | ifeq ($(DEBUG_LEVEL),0) 131 | LIBNAME=libfloyd 132 | else 133 | LIBNAME=libfloyd_debug 134 | endif 135 | endif 136 | LIBOUTPUT = ./lib 137 | dummy := $(shell mkdir -p $(LIBOUTPUT)) 138 | LIBRARY = $(LIBOUTPUT)/${LIBNAME}.a 139 | 140 | .PHONY: clean dbg static_lib all 141 | 142 | all: $(LIBRARY) 143 | 144 | static_lib: $(LIBRARY) 145 | 146 | dbg: $(LIBRARY) 147 | 148 | $(LIBRARY): $(LIBOBJECTS) 149 | $(AM_V_AR)rm -f $@ 150 | $(AM_V_at)$(AR) $(ARFLAGS) $@ $(LIBOBJECTS) 151 | 152 | clean: 153 | rm -f $(TESTS) 154 | rm -f $(LIBRARY) 155 | rm -rf $(CLEAN_FILES) 156 | rm -rf $(LIBOUTPUT) 157 | find . -name "*.[oda]*" ! -path "./third/*" -exec rm -f {} \; 158 | 159 | .cc.o: 160 | $(AM_V_CC)$(CXX) $(CXXFLAGS) -c $< -o $@ 161 | 162 | .c.o: 163 | $(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@ 164 | -------------------------------------------------------------------------------- /floyd/example/kv/Makefile: -------------------------------------------------------------------------------- 1 | CC=cc 2 | CXX=g++ 3 | LDFLAGS= -lsnappy -lz -lbz2 -lprotobuf -lpthread -lrt $(EXTRA_LDFLAGS) 4 | CFLAGS= -DOS_LINUX -fno-builtin-memcmp -msse -msse4.2 ${EXTRA_CFLAGS} 5 | CXXFLAGS=-std=c++11 -DOS_LINUX -fno-builtin-memcmp -msse -msse4.2 ${EXTRA_CXXFLAGS} 6 | # OPT = -O0 -g 7 | OPT = -O2 -DNDEBUG 8 | 9 | # for rocksdb 10 | CXXFLAGS+= -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DOS_LINUX 11 | 12 | .PHONY: clean all 13 | 14 | all: srv cli 15 | 16 | ifndef SLASH_PATH 17 | $(warning Warning: missing slash path, using default) 18 | SLASH_PATH=$(CURDIR)/../third/slash 19 | endif 20 | SLASH_INCLUDE_DIR=$(SLASH_PATH) 21 | SLASH_LIBRARY=$(SLASH_PATH)/slash/lib/libslash.a 22 | 23 | ifndef PINK_PATH 24 | $(warning Warning: slash path missing, using default) 25 | PINK_PATH=$(CURDIR)/third/pink 26 | endif 27 | PINK_INCLUDE_DIR=$(PINK_PATH) 28 | PINK_LIBRARY=$(PINK_PATH)/pink/lib/libpink.a 29 | 30 | ifndef ROCKSDB_PATH 31 | $(warning Warning: rocksdb path missing, using default) 32 | ROCKSDB_PATH=$(CURDIR)/third/rocksdb 33 | endif 34 | ROCKSDB_INCLUDE_DIR=$(ROCKSDB_PATH)/include 35 | ROCKSDB_LIBRARY=$(ROCKSDB_PATH)/librocksdb.a 36 | 37 | FLOYD_LIBRARY=../../lib/libfloyd.a 38 | 39 | CXXFLAGS+=-I../../.. \ 40 | -I$(SLASH_INCLUDE_DIR) \ 41 | -I$(PINK_INCLUDE_DIR) \ 42 | -I$(ROCKSDB_INCLUDE_DIR) 43 | 44 | srv: kv_server.cc srv.cc $(FLOYD_LIBRARY) $(ROCKSDB_LIBRARY) $(PINK_LIBRARY) $(SLASH_LIBRARY) 45 | $(CXX) $(CXXFLAGS) $^ -o$@ $(LDFLAGS) 46 | 47 | cli: kv_cli.cc cli.cc $(FLOYD_LIBRARY) $(ROCKSDB_LIBRARY) $(PINK_LIBRARY) $(SLASH_LIBRARY) 48 | $(CXX) $(CXXFLAGS) $^ -o$@ $(LDFLAGS) 49 | 50 | clean: 51 | find . -name "*.[oda]" -exec rm -f {} \; 52 | rm -rf ./srv ./cli 53 | 54 | $(FLOYD_LIBRARY): 55 | cd ../.. && $(MAKE) static_lib 56 | -------------------------------------------------------------------------------- /floyd/example/kv/README: -------------------------------------------------------------------------------- 1 | this is a simple consensus store used floyd 2 | 3 | it includes two part: 4 | 1. server 5 | 2. client 6 | 7 | you can use it to test the performance of floyd 8 | -------------------------------------------------------------------------------- /floyd/example/kv/cli.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include "logger.h" 8 | 9 | #include "slash/include/slash_status.h" 10 | 11 | #include "kv_cli.h" 12 | 13 | using namespace std; 14 | 15 | 16 | static struct option const long_options[] = { 17 | {"server", required_argument, NULL, 's'}, 18 | {"cmd", required_argument, NULL, 't'}, 19 | {"begin", required_argument, NULL, 'b'}, 20 | {"end", required_argument, NULL, 'e'}, 21 | {NULL, 0, NULL, 0} }; 22 | 23 | int main(int argc, char* argv[]) { 24 | if (argc < 2) { 25 | fprintf (stderr, "Usage:\n" 26 | " ./client --server ip:port\n" 27 | " --cmd [read | write | delete | status | debug_on | debug_off]\n" 28 | " --begin id0 --end id1\n"); 29 | exit(-1); 30 | } 31 | 32 | int cnt = 1000; 33 | int begin = 0; 34 | std::string server_str, cmd; 35 | int opt, optindex; 36 | while ((opt = getopt_long(argc, argv, "s:", long_options, &optindex)) != -1) { 37 | switch (opt) { 38 | case 's': 39 | server_str = optarg; 40 | break; 41 | case 't': 42 | cmd = optarg; 43 | break; 44 | case 'b': { 45 | char *end; 46 | begin = strtol(optarg, &end, 10); 47 | break; 48 | } 49 | case 'e': { 50 | char *end; 51 | cnt = strtol(optarg, &end, 10); 52 | break; 53 | } 54 | default: 55 | break; 56 | } 57 | } 58 | floyd::client::Option option(server_str); 59 | floyd::client::Cluster cluster(option); 60 | 61 | printf ("Will connect(%s) with cmd(%s), begin=%d cnt=%d\n", server_str.c_str(), cmd.c_str(), begin, cnt); 62 | sleep(1); 63 | 64 | for (int i = begin; i < cnt; i++) { 65 | std::string key = "test_key" + std::to_string(i); 66 | std::string value = "test_value" + std::to_string(i); 67 | 68 | slash::Status result; 69 | 70 | if (cmd.empty() || cmd == "write") { 71 | //fprintf (stderr, "\n=====Test Write==========\n"); 72 | result = cluster.Write(key, value); 73 | if (result.ok()) { 74 | fprintf (stderr, "Write key(%s) ok\n", key.c_str()); 75 | } else { 76 | fprintf (stderr, "Write key(%s) failed, %s\n", key.c_str(), result.ToString().c_str()); 77 | } 78 | } 79 | 80 | if (cmd.empty() || cmd == "dirtywrite") { 81 | //fprintf (stderr, "\n=====Test DirtyWrite==========\n"); 82 | result = cluster.DirtyWrite(key, value); 83 | if (result.ok()) { 84 | fprintf (stderr, "DirtyWrite key(%s) ok\n", key.c_str()); 85 | } else { 86 | fprintf (stderr, "DirtyWrite key(%s) failed, %s\n", key.c_str(), result.ToString().c_str()); 87 | } 88 | } 89 | 90 | if (cmd.empty() || cmd == "read") { 91 | value = ""; 92 | //fprintf (stderr, "\n=====Test Read==========\n"); 93 | result = cluster.Read(key, &value); 94 | if (result.ok()) { 95 | fprintf (stderr, "Read key(%s) ok, value is %s\n", key.c_str(), value.c_str()); 96 | } else { 97 | fprintf (stderr, "Read key(%s) failed, %s\n", key.c_str(), result.ToString().c_str()); 98 | } 99 | } 100 | 101 | if (cmd.empty() || cmd == "dirtyread") { 102 | value = ""; 103 | //fprintf (stderr, "\n=====Test DirtyRead==========\n"); 104 | result = cluster.DirtyRead(key, &value); 105 | if (result.ok()) { 106 | fprintf (stderr, "DirtyRead key(%s) ok, value is %s\n", key.c_str(), value.c_str()); 107 | } else { 108 | fprintf (stderr, "DirtyRead key(%s) failed, %s\n", key.c_str(), result.ToString().c_str()); 109 | } 110 | } 111 | 112 | if (cmd.empty() || cmd == "status") { 113 | value = ""; 114 | //fprintf (stderr, "\n=====Test ServerStatus==========\n"); 115 | result = cluster.GetStatus(&value); 116 | if (result.ok()) { 117 | fprintf (stderr, "GetStatus ok, msg is\n%s\n", value.c_str()); 118 | } else { 119 | fprintf (stderr, "GetStatus failed, %s\n", result.ToString().c_str()); 120 | } 121 | } 122 | 123 | if (cmd.empty() || cmd == "delete") { 124 | //fprintf (stderr, "\n=====Test Delete==========\n"); 125 | result = cluster.Delete(key); 126 | if (result.ok()) { 127 | fprintf (stderr, "Delete key(%s) ok\n", key.c_str()); 128 | } else { 129 | fprintf (stderr, "Delete key(%s) failed, %s\n", key.c_str(), result.ToString().c_str()); 130 | } 131 | } 132 | 133 | if (cmd == "debug_on") { 134 | result = cluster.set_log_level(floyd::client::DEBUG_LEVEL); 135 | if (result.ok()) { 136 | fprintf (stderr, "set log_level to debug ok\n"); 137 | } else { 138 | fprintf (stderr, "set log_level to debug failed, %s\n", result.ToString().c_str()); 139 | } 140 | } 141 | if (cmd == "debug_off") { 142 | result = cluster.set_log_level(floyd::client::INFO_LEVEL); 143 | if (result.ok()) { 144 | fprintf (stderr, "set log_level to info ok\n"); 145 | } else { 146 | fprintf (stderr, "set log_level to info failed, %s\n", result.ToString().c_str()); 147 | } 148 | } 149 | } 150 | 151 | return 0; 152 | } 153 | -------------------------------------------------------------------------------- /floyd/example/kv/kv_cli.h: -------------------------------------------------------------------------------- 1 | #ifndef FLOYD_CLIENT_H 2 | #define FLOYD_CLIENT_H 3 | 4 | #include 5 | #include 6 | 7 | #include "pink/include/pink_cli.h" 8 | #include "slash/include/slash_status.h" 9 | 10 | 11 | namespace floyd { 12 | 13 | struct Option; 14 | class Server; 15 | class Cluster; 16 | 17 | using slash::Status; 18 | 19 | class Server { 20 | public: 21 | std::string ip; 22 | int port; 23 | 24 | // colon separated ip:port 25 | Server(const std::string& str); 26 | Server(const std::string& _ip, const int& _port) : ip(_ip), port(_port) {} 27 | 28 | Server(const Server& server) 29 | : ip(server.ip), 30 | port(server.port) {} 31 | 32 | Server& operator=(const Server& server) { 33 | ip = server.ip; 34 | port = server.port; 35 | return *this; 36 | } 37 | 38 | private: 39 | }; 40 | 41 | struct Option { 42 | // TODO session timeout 43 | int64_t timeout; 44 | Server server; 45 | 46 | Option(const std::string& _server); 47 | Option(const Option& option); 48 | }; 49 | 50 | // Logger Level 51 | enum LogLevel { 52 | DEBUG_LEVEL = 0x01, 53 | INFO_LEVEL = 0x02, 54 | WARN_LEVEL = 0x03, 55 | ERROR_LEVEL = 0x04, 56 | FATAL_LEVEL = 0x05, 57 | NONE_LEVEL = 0x06 58 | }; 59 | 60 | class Cluster { 61 | public: 62 | Cluster(const Option& option); 63 | 64 | Status Write(const std::string& key, const std::string& value); 65 | Status DirtyWrite(const std::string& key, const std::string& value); 66 | Status Read(const std::string& key, std::string* value); 67 | Status DirtyRead(const std::string& key, std::string* value); 68 | Status GetStatus(std::string *msg); 69 | Status Delete(const std::string& key); 70 | Status set_log_level(const int log_level); 71 | 72 | private: 73 | bool Init(); 74 | 75 | Option option_; 76 | 77 | pink::PinkCli *pb_cli_; 78 | }; 79 | 80 | } // namespace floyd 81 | #endif 82 | -------------------------------------------------------------------------------- /floyd/example/kv/kv_server.cc: -------------------------------------------------------------------------------- 1 | #include "./kv_server.h" 2 | 3 | #include 4 | 5 | #include "pink/include/server_thread.h" 6 | 7 | #include "./sdk.pb.h" 8 | #include "./logger.h" 9 | 10 | 11 | namespace floyd { 12 | 13 | 14 | // FloydServerHandler 15 | void KvServerHandler::CronHandle() const { 16 | server_->ResetLastSecQueryNum(); 17 | LOG_INFO ("FloydServer QPS:%llu", server_->last_qps()); 18 | } 19 | 20 | KvServer::KvServer(int sdk_port, const Options& options) 21 | : options_(options), 22 | last_query_num_(0), 23 | query_num_(0), 24 | last_time_us_(slash::NowMicros()) { 25 | Floyd::Open(options_, &floyd_); 26 | conn_factory_ = new KvServerConnFactory(floyd_, this); 27 | server_handler_ = new KvServerHandler(this); 28 | server_thread_ = pink::NewHolyThread(sdk_port, conn_factory_, 3000, server_handler_); 29 | LOG_DEBUG ("KvServer will started on port:%d", sdk_port); 30 | //pthread_rwlock_init(&state_protector_, NULL); 31 | } 32 | 33 | KvServer::~KvServer() { 34 | server_thread_->StopThread(); 35 | delete server_thread_; 36 | delete conn_factory_; 37 | delete server_handler_; 38 | delete floyd_; 39 | } 40 | 41 | slash::Status KvServer::Start() { 42 | // TEST 43 | std::set nodes; 44 | floyd_->GetAllNodes(nodes); 45 | for (auto& it : nodes) { 46 | LOG_DEBUG ("nodes: %s", it.c_str()); 47 | } 48 | 49 | std::string ip; 50 | int port; 51 | floyd_->GetLeader(&ip, &port); 52 | LOG_DEBUG ("Leader: %s %d", ip.c_str(), port); 53 | 54 | int ret = server_thread_->StartThread(); 55 | if (ret != 0) { 56 | return Status::Corruption("Start server server error"); 57 | } 58 | LOG_DEBUG ("Kv started on port:%d", options_.local_port); 59 | server_mutex.Lock(); 60 | server_mutex.Lock(); 61 | server_mutex.Unlock(); 62 | return Status::OK(); 63 | } 64 | 65 | ////// ServerConn ////// 66 | KvServerConn::KvServerConn(int fd, const std::string &ip_port, 67 | pink::ServerThread *thread, 68 | Floyd *floyd, KvServer* server) 69 | : PbConn(fd, ip_port, thread), 70 | floyd_(floyd), 71 | server_(server) { 72 | } 73 | 74 | int KvServerConn::DealMessage() { 75 | if (!command_.ParseFromArray(rbuf_ + 4, header_len_)) { 76 | LOG_DEBUG("WorkerConn::DealMessage ParseFromArray failed"); 77 | return -1; 78 | } 79 | command_res_.Clear(); 80 | 81 | LOG_DEBUG ("deal message msg_code:%d\n", command_.type()); 82 | server_->PlusQueryNum(); 83 | 84 | set_is_reply(true); 85 | 86 | switch (command_.type()) { 87 | case client::Type::WRITE: { 88 | LOG_DEBUG("ServerConn::DealMessage Write"); 89 | client::Request_Write request = command_.write(); 90 | 91 | command_res_.set_type(client::Type::WRITE); 92 | 93 | Status result = floyd_->Write(request.key(), request.value()); 94 | if (!result.ok()) { 95 | command_res_.set_code(client::StatusCode::kError); 96 | command_res_.set_msg(result.ToString()); 97 | LOG_ERROR("write failed %s", result.ToString().c_str()); 98 | } else { 99 | command_res_.set_code(client::StatusCode::kOk); 100 | LOG_DEBUG ("write key(%s) ok!", request.key().c_str()); 101 | } 102 | break; 103 | } 104 | 105 | case client::Type::READ: { 106 | LOG_DEBUG("ServerConn::DealMessage READ"); 107 | client::Request_Read request = command_.read(); 108 | 109 | command_res_.set_type(client::Type::READ); 110 | client::Response_Read* response = command_res_.mutable_read(); 111 | 112 | std::string value; 113 | Status result = floyd_->Read(request.key(), value); 114 | if (result.ok()) { 115 | command_res_.set_code(client::StatusCode::kOk); 116 | response->set_value(value); 117 | LOG_DEBUG ("read key(%s) ok!", request.key().c_str()); 118 | } else if (result.IsNotFound()) { 119 | command_res_.set_code(client::StatusCode::kNotFound); 120 | LOG_ERROR("read key(%s) not found %s", request.key().c_str(), result.ToString().c_str()); 121 | } else { 122 | command_res_.set_code(client::StatusCode::kError); 123 | LOG_ERROR("read key(%s) failed %s", request.key().c_str(), result.ToString().c_str()); 124 | } 125 | #ifndef NDEBUG 126 | std::string text_format; 127 | google::protobuf::TextFormat::PrintToString(command_res_, &text_format); 128 | LOG_DEBUG("Read res message :\n%s", text_format.c_str()); 129 | #endif 130 | break; 131 | } 132 | 133 | case client::Type::STATUS: { 134 | LOG_DEBUG("ServerConn::DealMessage ServerStaus"); 135 | command_res_.set_type(client::Type::STATUS); 136 | client::Response_ServerStatus* response = command_res_.mutable_server_status(); 137 | 138 | std::string value; 139 | bool ret = floyd_->GetServerStatus(value); 140 | if (!ret) { 141 | command_res_.set_code(client::StatusCode::kError); 142 | response->set_msg("failed to dump status"); 143 | LOG_ERROR("Status failed"); 144 | } else { 145 | command_res_.set_code(client::StatusCode::kOk); 146 | response->set_msg(value); 147 | LOG_DEBUG ("Status ok!\n%s", value.c_str()); 148 | } 149 | break; 150 | } 151 | case client::Type::DIRTYWRITE: { 152 | LOG_DEBUG("ServerConn::DealMessage DirtyWrite"); 153 | client::Request_Write request = command_.write(); 154 | 155 | command_res_.set_type(client::Type::DIRTYWRITE); 156 | Status result = floyd_->DirtyWrite(request.key(), request.value()); 157 | if (!result.ok()) { 158 | command_res_.set_code(client::StatusCode::kError); 159 | command_res_.set_msg(result.ToString()); 160 | LOG_ERROR("DirtyWrite failed %s", result.ToString().c_str()); 161 | } else { 162 | command_res_.set_code(client::StatusCode::kOk); 163 | LOG_DEBUG ("DirtyWrite key(%s) ok!", request.key().c_str()); 164 | } 165 | 166 | std::string text_format; 167 | google::protobuf::TextFormat::PrintToString(command_res_, &text_format); 168 | LOG_DEBUG("DirtyWrite res message :\n%s", text_format.c_str()); 169 | break; 170 | } 171 | case client::Type::DIRTYREAD: { 172 | LOG_DEBUG("ServerConn::DealMessage DIRTYREAD"); 173 | client::Request_Read request = command_.read(); 174 | 175 | command_res_.set_type(client::Type::DIRTYREAD); 176 | client::Response_Read* response = command_res_.mutable_read(); 177 | 178 | std::string value; 179 | Status result = floyd_->DirtyRead(request.key(), value); 180 | if (result.ok()) { 181 | command_res_.set_code(client::StatusCode::kOk); 182 | response->set_value(value); 183 | LOG_DEBUG ("DirtyRead key(%s) ok!", request.key().c_str()); 184 | } else if (result.IsNotFound()) { 185 | command_res_.set_code(client::StatusCode::kNotFound); 186 | LOG_ERROR("DirtyRead key(%s) not found %s", request.key().c_str(), result.ToString().c_str()); 187 | } else { 188 | command_res_.set_code(client::StatusCode::kError); 189 | LOG_ERROR("DirtyRead key(%s) failed %s", request.key().c_str(), result.ToString().c_str()); 190 | } 191 | 192 | std::string text_format; 193 | google::protobuf::TextFormat::PrintToString(command_res_, &text_format); 194 | LOG_DEBUG("DirtyRead res message :\n%s", text_format.c_str()); 195 | break; 196 | } 197 | case client::Type::DELETE: { 198 | LOG_DEBUG("ServerConn::DealMessage Delete"); 199 | client::Request_Delete request = command_.del(); 200 | 201 | command_res_.set_type(client::Type::DELETE); 202 | Status result = floyd_->Delete(request.key()); 203 | if (!result.ok()) { 204 | command_res_.set_code(client::StatusCode::kError); 205 | command_res_.set_msg(result.ToString()); 206 | LOG_ERROR("Delete failed %s", result.ToString().c_str()); 207 | } else { 208 | command_res_.set_code(client::StatusCode::kOk); 209 | LOG_DEBUG ("Delete key(%s) ok!", request.key().c_str()); 210 | } 211 | 212 | std::string text_format; 213 | google::protobuf::TextFormat::PrintToString(command_res_, &text_format); 214 | LOG_DEBUG("Delete res message :\n%s", text_format.c_str()); 215 | break; 216 | } 217 | case client::Type::LOGLEVEL: { 218 | int log_level = command_.log_level(); 219 | LOG_DEBUG("ServerConn::DealMessage LogLevel %d", log_level); 220 | command_res_.set_type(client::Type::LOGLEVEL); 221 | floyd_->set_log_level(log_level); 222 | command_res_.set_code(client::StatusCode::kOk); 223 | break; 224 | } 225 | default: 226 | LOG_DEBUG ("invalid msg_code %d\n", command_.type()); 227 | break; 228 | } 229 | 230 | res_ = &command_res_; 231 | return 0; 232 | } 233 | 234 | } // namespace floyd 235 | -------------------------------------------------------------------------------- /floyd/example/kv/kv_server.h: -------------------------------------------------------------------------------- 1 | #ifndef KV_KV_SERVER_H_ 2 | #define KV_KV_SERVER_H_ 3 | 4 | #include 5 | #include "sdk.pb.h" 6 | 7 | #include "pink/include/pb_conn.h" 8 | #include "pink/include/server_thread.h" 9 | 10 | #include "slash/include/env.h" 11 | #include "slash/include/slash_mutex.h" 12 | #include "slash/include/slash_status.h" 13 | #include "floyd/include/floyd.h" 14 | 15 | namespace floyd { 16 | 17 | class KvServer; 18 | class KvServerConn; 19 | class KvServerConnFactory; 20 | 21 | class KvServerHandler : public pink::ServerHandle { 22 | public: 23 | explicit KvServerHandler(KvServer* server) 24 | : server_(server) { } 25 | virtual ~KvServerHandler() {} 26 | 27 | virtual void CronHandle() const; 28 | virtual bool AccessHandle(std::string& ip) const { 29 | return true; 30 | } 31 | 32 | private: 33 | KvServer* server_; 34 | }; 35 | 36 | class KvServerConn : public pink::PbConn { 37 | public: 38 | KvServerConn(int fd, const std::string& ip_port, pink::ServerThread* thread, 39 | Floyd* floyd, KvServer* server); 40 | virtual ~KvServerConn() {} 41 | 42 | //virtual pink::Status BuildObuf(); 43 | virtual int DealMessage(); 44 | 45 | private: 46 | Floyd* floyd_; 47 | KvServer* server_; 48 | client::Request command_; 49 | client::Response command_res_; 50 | }; 51 | 52 | class KvServerConnFactory : public pink::ConnFactory { 53 | public: 54 | explicit KvServerConnFactory(Floyd* floyd, KvServer* server) 55 | : floyd_(floyd), 56 | server_(server) { } 57 | 58 | virtual pink::PinkConn *NewPinkConn(int connfd, 59 | const std::string &ip_port, 60 | pink::ServerThread *server_thread, 61 | void* worker_private_data) const override { 62 | return new KvServerConn(connfd, ip_port, server_thread, floyd_, server_); 63 | } 64 | 65 | private: 66 | Floyd* floyd_; 67 | KvServer* server_; 68 | }; 69 | 70 | class KvServer { 71 | public: 72 | explicit KvServer(int sdk_port, const Options& option); 73 | virtual ~KvServer(); 74 | slash::Status Start(); 75 | 76 | uint64_t last_qps() { 77 | return last_qps_.load(); 78 | } 79 | 80 | void PlusQueryNum() { 81 | query_num_++; 82 | } 83 | 84 | void ResetLastSecQueryNum() { 85 | uint64_t cur_time_us = slash::NowMicros(); 86 | last_qps_ = (query_num_ - last_query_num_) * 1000000 / (cur_time_us - last_time_us_ + 1); 87 | last_query_num_ = query_num_.load(); 88 | last_time_us_ = cur_time_us; 89 | } 90 | 91 | slash::Mutex server_mutex; 92 | 93 | private: 94 | Options options_; 95 | 96 | Floyd* floyd_; 97 | 98 | KvServerHandler* server_handler_; 99 | KvServerConnFactory* conn_factory_; 100 | pink::ServerThread* server_thread_; 101 | 102 | std::atomic last_query_num_; 103 | std::atomic query_num_; 104 | std::atomic last_qps_; 105 | std::atomic last_time_us_; 106 | }; 107 | 108 | } // namespace floyd 109 | #endif 110 | -------------------------------------------------------------------------------- /floyd/example/kv/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOGGER_H__ 2 | #define __LOGGER_H__ 3 | 4 | #include 5 | #include 6 | 7 | static inline char *timenow(); 8 | 9 | #define _FILE strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__ 10 | 11 | #define LEVEL_DEBUG 0x04 12 | #define LEVEL_INFO 0x03 13 | #define LEVEL_WARNING 0x02 14 | #define LEVEL_ERROR 0x01 15 | #define LEVEL_NONE 0x00 16 | 17 | #ifndef LOG_LEVEL 18 | #define LOG_LEVEL NONE 19 | #endif 20 | 21 | #define PRINTFUNCTION(format, ...) fprintf(stderr, format, __VA_ARGS__) 22 | 23 | #define LOG_FMT "%-7s %s %s:%d] " 24 | #define LOG_ARGS(LOG_TAG) LOG_TAG, timenow(), _FILE, __LINE__ 25 | 26 | #define NEWLINE "\n" 27 | 28 | #define DEBUG_TAG "[DEBUG]" 29 | #define INFO_TAG "[INFO]" 30 | #define WARN_TAG "[WARN]" 31 | #define ERROR_TAG "[ERROR]" 32 | 33 | #if LOG_LEVEL >= LEVEL_DEBUG 34 | #define LOG_DEBUG(message, args...) \ 35 | PRINTFUNCTION(LOG_FMT message NEWLINE, LOG_ARGS(DEBUG_TAG), ##args) 36 | #else 37 | #define LOG_DEBUG(message, args...) 38 | #endif 39 | 40 | #if LOG_LEVEL >= LEVEL_INFO 41 | #define LOG_INFO(message, args...) \ 42 | PRINTFUNCTION(LOG_FMT message NEWLINE, LOG_ARGS(INFO_TAG), ##args) 43 | #else 44 | #define LOG_INFO(message, args...) 45 | #endif 46 | 47 | #if LOG_LEVEL >= LEVEL_WARNING 48 | #define LOG_WARN(message, args...) \ 49 | PRINTFUNCTION(LOG_FMT message NEWLINE, LOG_ARGS(WARN_TAG), ##args) 50 | #else 51 | #define LOG_WARN(message, args...) 52 | #endif 53 | 54 | #if LOG_LEVEL >= LEVEL_ERROR 55 | #define LOG_ERROR(message, args...) \ 56 | PRINTFUNCTION(LOG_FMT message NEWLINE, LOG_ARGS(ERROR_TAG), ##args) 57 | #else 58 | #define LOG_ERROR(message, args...) 59 | #endif 60 | 61 | #if LOG_LEVEL >= LEVEL_NONE 62 | #define LOG_IF_ERROR(condition, message, args...) \ 63 | if (condition) \ 64 | PRINTFUNCTION(LOG_FMT message NEWLINE, LOG_ARGS(ERROR_TAG), ##args) 65 | #else 66 | #define LOG_IF_ERROR(condition, message, args...) 67 | #endif 68 | 69 | static inline char *timenow() { 70 | static char buffer[64]; 71 | struct timeval tv; 72 | gettimeofday(&tv, NULL); 73 | 74 | snprintf(buffer, 64, "%ld.%06ld", tv.tv_sec, tv.tv_usec); 75 | 76 | return buffer; 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /floyd/example/kv/manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $1 = "1" ] ; then 4 | ./output/bin/floyd_node --servers 127.0.0.1:9100,127.0.0.1:9101,127.0.0.1:9102 --local_ip 127.0.0.1 --local_port 9100 --sdk_port 8900 --data_path ./node1/data --log_path ./node1/log > 1.out 2>&1 5 | elif [ $1 = "2" ] ; then 6 | ./output/bin/floyd_node --servers 127.0.0.1:9100,127.0.0.1:9101,127.0.0.1:9102 --local_ip 127.0.0.1 --local_port 9101 --sdk_port 8901 --data_path ./node2/data --log_path ./node2/log > 2.out 2>&1 7 | elif [ $1 = "3" ] ; then 8 | ./output/bin/floyd_node --servers 127.0.0.1:9100,127.0.0.1:9101,127.0.0.1:9102 --local_ip 127.0.0.1 --local_port 9102 --sdk_port 8902 --data_path ./node3/data --log_path ./node3/log > 3.out 2>&1 9 | elif [ $1 = "clean" ] ; then 10 | rm -rf node* *out 11 | fi 12 | -------------------------------------------------------------------------------- /floyd/example/kv/pr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ##################### 4 | # sdk.proto 5 | ################### 6 | FILE3="sdk" 7 | protoc -I=./ --cpp_out=./ ./$FILE3.proto 8 | -------------------------------------------------------------------------------- /floyd/example/kv/sdk.proto: -------------------------------------------------------------------------------- 1 | enum Type { 2 | WRITE = 1; 3 | READ = 2; 4 | DELETE = 3; 5 | STATUS = 4; 6 | DIRTYWRITE = 5; 7 | DIRTYREAD = 6; 8 | LOGLEVEL = 7; 9 | } 10 | 11 | // Write 12 | message Request { 13 | required Type type = 1; 14 | 15 | message Write { 16 | required bytes key = 1; 17 | required bytes value = 2; 18 | optional bytes uuid = 3; 19 | } 20 | optional Write write = 2; 21 | 22 | message Read { 23 | required bytes key = 1; 24 | } 25 | optional Read read = 3; 26 | 27 | message Delete { 28 | required bytes key = 1; 29 | } 30 | optional Delete del = 4; 31 | 32 | optional int32 log_level = 5; 33 | } 34 | 35 | enum StatusCode { 36 | kOk = 0; 37 | kNotFound = 1; 38 | kError = 2; 39 | } 40 | 41 | message Response { 42 | required Type type = 1; 43 | optional StatusCode code = 2; 44 | optional bytes msg = 3; 45 | 46 | message Read { 47 | optional bytes value = 1; 48 | } 49 | optional Read read = 4; 50 | 51 | message ServerStatus { 52 | required bytes msg = 1; 53 | } 54 | optional ServerStatus server_status = 5; 55 | } 56 | -------------------------------------------------------------------------------- /floyd/example/kv/srv.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd_server.h" 9 | 10 | #include "slash/include/slash_status.h" 11 | 12 | void Usage(); 13 | const struct option long_options[] = { 14 | {"servers", required_argument, NULL, 's'}, 15 | {"local_ip", required_argument, NULL, 'i'}, 16 | {"local_port", required_argument, NULL, 'p'}, 17 | {"sdk_port", required_argument, NULL, 'P'}, 18 | {"data_path", required_argument, NULL, 'd'}, 19 | {"log_path", required_argument, NULL, 'l'}, 20 | {NULL, 0, NULL, 0}, }; 21 | 22 | const char* short_options = "s:i:p:d:l:"; 23 | 24 | floyd::FloydServer *fs; 25 | 26 | void IntSigHandle(int sig) { 27 | printf ("Catch Signal %d, cleanup...\n", sig); 28 | fs->server_mutex.Unlock(); 29 | } 30 | 31 | void SignalSetup() { 32 | signal(SIGPIPE, SIG_IGN); 33 | if (signal(SIGINT, &IntSigHandle) == SIG_ERR) { 34 | printf ("Catch SignalInt error\n"); 35 | } 36 | signal(SIGQUIT, &IntSigHandle); 37 | signal(SIGTERM, &IntSigHandle); 38 | } 39 | 40 | int main(int argc, char** argv) { 41 | if (argc < 12) { 42 | printf ("Usage:\n" 43 | " ./main --servers ip1:port1,ip2:port2 --local_ip ip --local_port port\n" 44 | " --sdk_port portx --data_path data_path --log_path log_path\n"); 45 | exit(0); 46 | } 47 | 48 | floyd::Options options; 49 | 50 | int ch, longindex; 51 | int server_port; 52 | 53 | while ((ch = getopt_long(argc, argv, short_options, long_options, 54 | &longindex)) >= 0) { 55 | switch (ch) { 56 | case 's': 57 | options.SetMembers(std::string(optarg)); 58 | break; 59 | case 'i': 60 | options.local_ip = optarg; 61 | break; 62 | case 'p': 63 | options.local_port = atoi(optarg); 64 | break; 65 | case 'P': 66 | server_port = atoi(optarg); 67 | break; 68 | case 'd': 69 | options.path = optarg; 70 | break; 71 | default: 72 | break; 73 | } 74 | } 75 | 76 | options.Dump(); 77 | 78 | SignalSetup(); 79 | 80 | fs = new floyd::FloydServer(server_port, options); 81 | slash::Status s = fs->Start(); 82 | if (!s.ok()) { 83 | printf("Start Floyd Server error\n"); 84 | return -1; 85 | } 86 | 87 | printf ("Will Stop FloydServer...\n"); 88 | delete fs; 89 | 90 | sleep(1); 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /floyd/example/redis/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | ifeq ($(__PERF), 1) 3 | CXXFLAGS = -O0 -g -pg -pipe -fPIC -DNDEBUG -DLOG_LEVEL=LEVEL_INFO -W -Wwrite-strings -Wpointer-arith -Wreorder -Wswitch -Wsign-promo -Wredundant-decls -Wformat -Wall -D_GNU_SOURCE -std=c++11 -D__STDC_FORMAT_MACROS -std=c++11 -gdwarf-2 -Wno-redundant-decls -Wno-unused-variable -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DOS_LINUX 4 | else 5 | CXXFLAGS = -g -O2 -ggdb3 -pipe -fPIC -W -Wwrite-strings -Wpointer-arith -Wreorder -Wswitch -Wsign-promo -Wredundant-decls -Wformat -D_GNU_SOURCE -D__STDC_FORMAT_MACROS -std=c++11 -gdwarf-2 -Wno-redundant-decls -Wno-unused-variable -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DOS_LINUX 6 | endif 7 | 8 | ifndef SLASH_PATH 9 | $(warning Warning: slash path missing, using default) 10 | SLASH_PATH=$(CURDIR)/../../third/slash 11 | endif 12 | SLASH_INCLUDE_DIR=$(SLASH_PATH) 13 | SLASH_LIBRARY=$(SLASH_PATH)/slash/lib/libslash.a 14 | 15 | ifndef PINK_PATH 16 | $(warning Warning: slash path missing, using default) 17 | PINK_PATH=$(CURDIR)/../../third/pink 18 | endif 19 | PINK_INCLUDE_DIR=$(PINK_PATH) 20 | PINK_LIBRARY=$(PINK_PATH)/pink/lib/libpink.a 21 | 22 | ifndef ROCKSDB_PATH 23 | $(warning Warning: rocksdb path missing, using default) 24 | ROCKSDB_PATH=$(CURDIR)/../../third/rocksdb 25 | endif 26 | ROCKSDB_INCLUDE_DIR=$(ROCKSDB_PATH)/include 27 | ROCKSDB_LIBRARY=$(ROCKSDB_PATH)/librocksdb.a 28 | 29 | FLOYD_LIBRARY=../../lib/libfloyd.a 30 | 31 | CXXFLAGS+=-I../../.. \ 32 | -I$(SLASH_INCLUDE_DIR) \ 33 | -I$(PINK_INCLUDE_DIR) \ 34 | -I$(ROCKSDB_INCLUDE_DIR) 35 | 36 | OBJECT = raftis 37 | SRC_DIR = ./ 38 | THIRD_PATH = ../../third 39 | OUTPUT = ./output 40 | 41 | LIB_PATH = -L../../lib/ \ 42 | -L$(SLASH_PATH)/slash/lib/ \ 43 | -L$(ROCKSDB_PATH)/ \ 44 | -L$(PINK_PATH)/pink/lib/ 45 | 46 | 47 | LIBS = -lfloyd \ 48 | -lpink \ 49 | -lslash \ 50 | -lrocksdb \ 51 | -lsnappy \ 52 | -lprotobuf \ 53 | -lz \ 54 | -lbz2 \ 55 | -lrt \ 56 | -lpthread 57 | 58 | INCLUDE_PATH = -I../../../ \ 59 | -I$(THIRD_PATH)/rocksdb/include \ 60 | -I$(THIRD_PATH)/slash/ \ 61 | -I$(THIRD_PATH)/pink/ 62 | 63 | AM_DEFAULT_VERBOSITY = 0 64 | 65 | AM_V_GEN = $(am__v_GEN_$(V)) 66 | am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) 67 | am__v_GEN_0 = @echo " GEN " $@; 68 | am__v_GEN_1 = 69 | AM_V_at = $(am__v_at_$(V)) 70 | am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) 71 | am__v_at_0 = @ 72 | am__v_at_1 = 73 | 74 | AM_V_CC = $(am__v_CC_$(V)) 75 | am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) 76 | am__v_CC_0 = @echo " CC " $@; 77 | am__v_CC_1 = 78 | CCLD = $(CC) 79 | LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ 80 | AM_V_CCLD = $(am__v_CCLD_$(V)) 81 | am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) 82 | am__v_CCLD_0 = @echo " CCLD " $@; 83 | am__v_CCLD_1 = 84 | AM_V_AR = $(am__v_AR_$(V)) 85 | am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY)) 86 | am__v_AR_0 = @echo " AR " $@; 87 | am__v_AR_1 = 88 | 89 | AM_LINK = $(AM_V_CCLD)$(CXX) $^ $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) 90 | 91 | 92 | .PHONY: all clean version 93 | 94 | 95 | BASE_BOJS := $(wildcard $(SRC_DIR)/*.cc) 96 | BASE_BOJS += $(wildcard $(SRC_DIR)/*.c) 97 | BASE_BOJS += $(wildcard $(SRC_DIR)/*.cpp) 98 | OBJS = $(patsubst %.cc,%.o,$(BASE_BOJS)) 99 | 100 | all: $(OBJECT) 101 | rm -rf $(OUTPUT) 102 | mkdir -p $(OUTPUT) 103 | mkdir -p $(OUTPUT)/bin 104 | cp $(OBJECT) $(OUTPUT)/bin/ 105 | rm -rf $(OBJECT) 106 | @echo "Success, go, go, go..." 107 | 108 | raftis: raftis.o 109 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 110 | 111 | .cc.o: 112 | $(AM_V_CC)$(CXX) $(CXXFLAGS) -c $< -o $@ 113 | 114 | .c.o: 115 | $(AM_V_CC)$(CC) $(CFLAGS) -c $< -o $@ 116 | 117 | clean: 118 | rm -rf $(OUTPUT) 119 | rm -rf $(SRC_DIR)/log 120 | rm -rf ./data* 121 | rm -f $(SRC_DIR)/*.o 122 | rm -rf $(OBJECT) 123 | -------------------------------------------------------------------------------- /floyd/example/redis/README.md: -------------------------------------------------------------------------------- 1 | ### Raftis 2 | 3 | raftis is a consensus server with 5 nodes and supporting redis protocol(get/set command). raftis is an example of building a consensus cluster with floyd(floyd is a simple implementation of raft protocol). It's very simple and intuitive. we can test raftis with redis-cli, benchmark with redis redis-benchmark tools. 4 | here is a 5 local nodes benchmark with redis-benchmark 5 | 6 | compile raftis with command make and then start with run.sh 7 | 8 | ``` 9 | make 10 | sh run.sh 11 | ``` 12 | 13 | 14 | ``` 15 | #!/bin/sh 16 | # start with five nodes 17 | 18 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8901 "./data1/" 6379 & 19 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8902 "./data2/" 6479 & 20 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8903 "./data3/" 6579 & 21 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8904 "./data4/" 6679 & 22 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8905 "./data5/" 6779 & 23 | ``` 24 | 25 | 26 | ``` 27 | └─[$] ./src/redis-benchmark -t set -n 1000000 -r 100000000 -c 20 28 | ====== SET ====== 29 | 1000000 requests completed in 219.76 seconds 30 | 20 parallel clients 31 | 3 bytes payload 32 | keep alive: 1 33 | 34 | 0.00% <= 2 milliseconds 35 | 0.00% <= 3 milliseconds 36 | 8.72% <= 4 milliseconds 37 | 95.39% <= 5 milliseconds 38 | 95.96% <= 6 milliseconds 39 | 99.21% <= 7 milliseconds 40 | 99.66% <= 8 milliseconds 41 | 99.97% <= 9 milliseconds 42 | 99.97% <= 11 milliseconds 43 | 99.97% <= 12 milliseconds 44 | 99.97% <= 14 milliseconds 45 | 99.97% <= 15 milliseconds 46 | 99.99% <= 16 milliseconds 47 | 99.99% <= 17 milliseconds 48 | 99.99% <= 18 milliseconds 49 | 99.99% <= 19 milliseconds 50 | 99.99% <= 26 milliseconds 51 | 99.99% <= 27 milliseconds 52 | 100.00% <= 28 milliseconds 53 | 100.00% <= 29 milliseconds 54 | 100.00% <= 30 milliseconds 55 | 100.00% <= 61 milliseconds 56 | 100.00% <= 62 milliseconds 57 | 100.00% <= 63 milliseconds 58 | 100.00% <= 63 milliseconds 59 | 4550.31 requests per second 60 | ``` 61 | -------------------------------------------------------------------------------- /floyd/example/redis/raftis.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "floyd/include/floyd.h" 7 | 8 | #include "pink/include/server_thread.h" 9 | #include "pink/include/pink_conn.h" 10 | #include "pink/include/redis_conn.h" 11 | #include "pink/include/pink_thread.h" 12 | 13 | using namespace pink; 14 | using namespace floyd; 15 | 16 | Floyd *f; 17 | 18 | class MyConn: public RedisConn { 19 | public: 20 | MyConn(int fd, const std::string& ip_port, ServerThread *thread, 21 | void* worker_specific_data); 22 | virtual ~MyConn(); 23 | 24 | protected: 25 | virtual int DealMessage(); 26 | 27 | private: 28 | }; 29 | 30 | MyConn::MyConn(int fd, const std::string& ip_port, 31 | ServerThread *thread, void* worker_specific_data) 32 | : RedisConn(fd, ip_port, thread) { 33 | // Handle worker_specific_data ... 34 | } 35 | 36 | MyConn::~MyConn() { 37 | } 38 | 39 | int MyConn::DealMessage() { 40 | slash::Status s; 41 | std::string val; 42 | // set command 43 | std::string res; 44 | 45 | if (argv_.size() == 3 && (argv_[0] == "set" || argv_[0] == "SET")) { 46 | int retries = 5; 47 | while (true) { 48 | retries--; 49 | s = f->Write(argv_[1], argv_[2]); 50 | if (s.ok()) { 51 | res = "+OK\r\n"; 52 | break; 53 | } else if (retries > 0 && 54 | (s.ToString().find("no leader") != std::string::npos || 55 | s.ToString().find("Client sent error") != std::string::npos)) { 56 | sleep(1); 57 | } else { 58 | res = "-ERR write " + s.ToString() + " \r\n"; 59 | break; 60 | } 61 | } 62 | memcpy(wbuf_ + wbuf_len_, res.data(), res.size()); 63 | wbuf_len_ += res.size(); 64 | } else if (argv_.size() == 2 && (argv_[0] == "get" || argv_[0] == "GET")) { 65 | int retries = 5; 66 | while (true) { 67 | retries--; 68 | s = f->Read(argv_[1], &val); 69 | if (s.ok() || s.IsNotFound()) { 70 | if (s.IsNotFound()) { 71 | val = "0"; // default value for jepsen 72 | } 73 | memcpy(wbuf_ + wbuf_len_, "$", 1); 74 | wbuf_len_ += 1; 75 | std::string len = std::to_string(val.length()); 76 | memcpy(wbuf_ + wbuf_len_, len.data(), len.size()); 77 | wbuf_len_ += len.size(); 78 | memcpy(wbuf_ + wbuf_len_, "\r\n", 2); 79 | wbuf_len_ += 2; 80 | memcpy(wbuf_ + wbuf_len_, val.data(), val.size()); 81 | wbuf_len_ += val.size(); 82 | memcpy(wbuf_ + wbuf_len_, "\r\n", 2); 83 | wbuf_len_ += 2; 84 | break; 85 | } else if (retries > 0 && 86 | (s.ToString().find("Client sent error") != std::string::npos || 87 | s.ToString().find("no leader") != std::string::npos)) { 88 | sleep(1); 89 | } else { 90 | res = "-ERR read " + s.ToString() + " \r\n"; 91 | memcpy(wbuf_ + wbuf_len_, res.data(), res.size()); 92 | wbuf_len_ += res.size(); 93 | break; 94 | } 95 | } 96 | } else if (argv_.size() == 1 && argv_[0] == "status") { 97 | std::string server_msg; 98 | if (f->GetServerStatus(&server_msg)) { 99 | wbuf_len_ += snprintf(wbuf_, 1024, "$%lu\r\n%s\r\n", 100 | server_msg.size(), server_msg.c_str()); 101 | 102 | } else { 103 | wbuf_len_ += snprintf(wbuf_, 1024, "-ERR GetServerStatus\r\n"); 104 | } 105 | } else { 106 | res = "+OK\r\n"; 107 | memcpy(wbuf_ + wbuf_len_, res.data(), res.size()); 108 | wbuf_len_ += res.size(); 109 | } 110 | set_is_reply(true); 111 | return 0; 112 | } 113 | 114 | class MyConnFactory : public ConnFactory { 115 | public: 116 | virtual PinkConn *NewPinkConn(int connfd, const std::string &ip_port, 117 | ServerThread *thread, 118 | void* worker_specific_data) const { 119 | return new MyConn(connfd, ip_port, thread, worker_specific_data); 120 | } 121 | }; 122 | 123 | static std::atomic running(false); 124 | 125 | static void IntSigHandle(const int sig) { 126 | running.store(false); 127 | } 128 | 129 | static void SignalSetup() { 130 | signal(SIGHUP, SIG_IGN); 131 | signal(SIGPIPE, SIG_IGN); 132 | signal(SIGINT, &IntSigHandle); 133 | signal(SIGQUIT, &IntSigHandle); 134 | signal(SIGTERM, &IntSigHandle); 135 | } 136 | 137 | int main(int argc, char* argv[]) { 138 | Options op(argv[1], argv[2], atoi(argv[3]), argv[4]); 139 | op.Dump(); 140 | 141 | slash::Status s; 142 | s = Floyd::Open(op, &f); 143 | printf("%s\n", s.ToString().c_str()); 144 | 145 | SignalSetup(); 146 | 147 | ConnFactory *conn_factory = new MyConnFactory(); 148 | 149 | ServerThread* my_thread = NewHolyThread(atoi(argv[5]), conn_factory); 150 | if (my_thread->StartThread() != 0) { 151 | printf("StartThread error happened!\n"); 152 | exit(-1); 153 | } 154 | running.store(true); 155 | while (running.load()) { 156 | sleep(1); 157 | } 158 | my_thread->StopThread(); 159 | delete my_thread; 160 | delete conn_factory; 161 | 162 | return 0; 163 | } 164 | -------------------------------------------------------------------------------- /floyd/example/redis/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8901 "./data1/" 6379 & 4 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8902 "./data2/" 6479 & 5 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8903 "./data3/" 6579 & 6 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8904 "./data4/" 6679 & 7 | ./output/bin/raftis "127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905" "127.0.0.1" 8905 "./data5/" 6779 & 8 | 9 | -------------------------------------------------------------------------------- /floyd/example/simple/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | ifeq ($(__PERF), 1) 3 | CXXFLAGS = -O0 -g -pipe -fPIC -DNDEBUG -DLOG_LEVEL=LEVEL_INFO -W -Wwrite-strings -Wpointer-arith -Wreorder -Wswitch -Wsign-promo -Wredundant-decls -Wformat -Wall -D_GNU_SOURCE -std=c++11 -D__STDC_FORMAT_MACROS -std=c++11 -gdwarf-2 -Wno-redundant-decls -Wno-unused-variable -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DOS_LINUX 4 | else 5 | CXXFLAGS = -pg -g -O2 -ggdb3 -pipe -fPIC -W -Wwrite-strings -Wpointer-arith -Wreorder -Wswitch -Wsign-promo -Wredundant-decls -Wformat -D_GNU_SOURCE -D__STDC_FORMAT_MACROS -std=c++11 -gdwarf-2 -Wno-redundant-decls -Wno-unused-variable -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DOS_LINUX 6 | endif 7 | 8 | ifndef SLASH_PATH 9 | $(warning Warning: slash path missing, using default) 10 | SLASH_PATH=$(CURDIR)/third/slash 11 | endif 12 | SLASH_INCLUDE_DIR=$(SLASH_PATH) 13 | SLASH_LIBRARY=$(SLASH_PATH)/slash/lib/libslash.a 14 | 15 | ifndef PINK_PATH 16 | $(warning Warning: slash path missing, using default) 17 | PINK_PATH=$(CURDIR)/third/pink 18 | endif 19 | PINK_INCLUDE_DIR=$(PINK_PATH) 20 | PINK_LIBRARY=$(PINK_PATH)/pink/lib/libpink.a 21 | 22 | ifndef ROCKSDB_PATH 23 | $(warning Warning: rocksdb path missing, using default) 24 | ROCKSDB_PATH=$(CURDIR)/third/rocksdb 25 | endif 26 | ROCKSDB_INCLUDE_DIR=$(ROCKSDB_PATH)/include 27 | ROCKSDB_LIBRARY=$(ROCKSDB_PATH)/librocksdb.a 28 | 29 | FLOYD_LIBRARY=../../lib/libfloyd.a 30 | 31 | CXXFLAGS+=-I../../.. \ 32 | -I$(SLASH_INCLUDE_DIR) \ 33 | -I$(PINK_INCLUDE_DIR) \ 34 | -I$(ROCKSDB_INCLUDE_DIR) 35 | 36 | OBJECT = t t1 t2 t3 t4 t5 t6 t7 t8 test_lock test_lock1 test_lock2 add_server add_server1 remove_server read_bench 37 | SRC_DIR = ./ 38 | THIRD_PATH = ../../third 39 | OUTPUT = ./output 40 | 41 | LIB_PATH = -L../../lib/ \ 42 | -L$(THIRD_PATH)/slash/slash/lib/ \ 43 | -L$(THIRD_PATH)/rocksdb/ \ 44 | -L$(THIRD_PATH)/pink/pink/lib/ 45 | 46 | 47 | LIBS = -lfloyd \ 48 | -lpink \ 49 | -lslash \ 50 | -lrocksdb \ 51 | -lsnappy \ 52 | -lprotobuf \ 53 | -lz \ 54 | -lbz2 \ 55 | -lrt \ 56 | -lssl \ 57 | -lcrypto \ 58 | -lpthread 59 | 60 | INCLUDE_PATH = -I../../../ \ 61 | -I$(THIRD_PATH)/rocksdb/include \ 62 | -I$(THIRD_PATH)/slash/ \ 63 | -I$(THIRD_PATH)/pink/ 64 | 65 | .PHONY: all clean version 66 | 67 | 68 | BASE_BOJS := $(wildcard $(SRC_DIR)/*.cc) 69 | BASE_BOJS += $(wildcard $(SRC_DIR)/*.c) 70 | BASE_BOJS += $(wildcard $(SRC_DIR)/*.cpp) 71 | OBJS = $(patsubst %.cc,%.o,$(BASE_BOJS)) 72 | 73 | all: $(OBJECT) 74 | rm -rf $(OUTPUT) 75 | mkdir -p $(OUTPUT) 76 | mkdir -p $(OUTPUT)/bin 77 | cp $(OBJECT) $(OUTPUT)/bin/ 78 | rm -rf $(OBJECT) 79 | @echo "Success, go, go, go..." 80 | 81 | t: t.o 82 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 83 | 84 | t1: t1.cc 85 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 86 | 87 | t2: t2.cc 88 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 89 | t3: t3.cc 90 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 91 | t4: t4.cc 92 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 93 | t5: t5.cc 94 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 95 | t6: t6.cc 96 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 97 | t7: t7.cc 98 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 99 | t8: t8.cc 100 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 101 | test_lock: test_lock.cc 102 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 103 | test_lock1: test_lock1.cc 104 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 105 | test_lock2: test_lock2.cc 106 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 107 | add_server: add_server.cc 108 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 109 | add_server1: add_server1.cc 110 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 111 | remove_server: remove_server.cc 112 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 113 | read_bench: read_bench.cc 114 | $(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 115 | $(OBJS): %.o : %.cc 116 | $(CXX) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_PATH) 117 | 118 | clean: 119 | rm -rf $(OUTPUT) 120 | rm -rf $(SRC_DIR)/log 121 | rm -rf ./data* 122 | rm -f $(SRC_DIR)/*.o 123 | rm -rf $(OBJECT) 124 | -------------------------------------------------------------------------------- /floyd/example/simple/README.md: -------------------------------------------------------------------------------- 1 | ### simple test cases 2 | 3 | the simple example will run the Floyd:write the get performance of floyd in a simple machine 4 | 5 | t is a single thread wirte tool to get performance 6 | 7 | t1 is multi thread program to get performance, in this case, all the writes is from the leader node 8 | 9 | t2 is an example test node join and leave 10 | 11 | t4 is an example used to see the message passing by each node in a stable situation 12 | 13 | t5 used to test single mode floyd, including starting a node and writing data 14 | 15 | t6 is the same as t1 except that all the writes is from the follower node 16 | 17 | t7 test write 3 node and then join the other 2 node case 18 | 19 | t8 start three nodes, node1 has the shortest log, and it will start first. node1 20 | will not be choosen as leader, node2/node3 will be choosen as leader, and the 21 | leader's log will cover node1's log 22 | 23 | test_lock test the base lock operation in floyd, the case is use lock and unlock in a simple thread 24 | 25 | test_lock1 is the case that two thread preempt to a same lock 26 | 27 | add_server test the base membership change proto, start 3 nodes and writing some data, then start the 4th node and join the group, at last start another node and join the group. 28 | 29 | add_server1 is the case that join the group parallel with writing data 30 | 31 | read_bench is an benchmark tool to get multi thread reading performance 32 | -------------------------------------------------------------------------------- /floyd/example/simple/add_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | int main() 19 | { 20 | Options op("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313", "127.0.0.1", 4311, "./data1/"); 21 | op.Dump(); 22 | 23 | Floyd *f1, *f2, *f3, *f4, *f5; 24 | 25 | slash::Status s; 26 | s = Floyd::Open(op, &f1); 27 | printf("start floyd f1 status %s\n", s.ToString().c_str()); 28 | 29 | Options op2("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313", "127.0.0.1", 4312, "./data2/"); 30 | s = Floyd::Open(op2, &f2); 31 | printf("start floyd f2 status %s\n", s.ToString().c_str()); 32 | 33 | Options op3("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313", "127.0.0.1", 4313, "./data3/"); 34 | s = Floyd::Open(op3, &f3); 35 | printf("start floyd f3 status %s\n", s.ToString().c_str()); 36 | 37 | std::string msg; 38 | 39 | while (1) { 40 | if (f1->HasLeader()) { 41 | f1->GetServerStatus(&msg); 42 | printf("%s\n", msg.c_str()); 43 | break; 44 | } 45 | printf("electing leader... sleep 2s\n"); 46 | sleep(2); 47 | } 48 | 49 | // write some data in the origin cluster 50 | 51 | std::string mystr[100100]; 52 | std::string val; 53 | for (int i = 0; i < 100; i++) { 54 | mystr[i] = slash::RandomString(10); 55 | } 56 | for (int i = 0; i < 10; i++) { 57 | f1->Write(mystr[i], mystr[i]); 58 | s = f1->Read(mystr[i], &val); 59 | printf("status %s val %s\n", s.ToString().c_str(), val.c_str()); 60 | } 61 | 62 | // then start another new server 63 | 64 | Options op4("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314", "127.0.0.1", 4314, "./data4/"); 65 | s = Floyd::Open(op4, &f4); 66 | printf("%s\n", s.ToString().c_str()); 67 | 68 | printf("Add new server4 to cluster\n"); 69 | s = f1->AddServer("127.0.0.1:4314"); 70 | printf("add new server4 status %s\n", s.ToString().c_str()); 71 | 72 | while (1) { 73 | if (f1->HasLeader()) { 74 | f1->GetServerStatus(&msg); 75 | printf("%s\n", msg.c_str()); 76 | break; 77 | } 78 | printf("electing leader after server 4 join the cluster... sleep 2s\n"); 79 | sleep(2); 80 | } 81 | printf("Write 100 pairs key-value after f4 node join in cluster\n"); 82 | for (int i = 0; i < 100; i++) { 83 | f1->Write(mystr[i], mystr[i]); 84 | s = f1->Read(mystr[i], &val); 85 | printf("status %s val %s\n", s.ToString().c_str(), val.c_str()); 86 | } 87 | 88 | Options op5("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4315, "./data5/"); 89 | s = Floyd::Open(op5, &f5); 90 | printf("start f5 node %s\n", s.ToString().c_str()); 91 | 92 | printf("Add new server5 to cluster\n"); 93 | s = f1->AddServer("127.0.0.1:4315"); 94 | printf("add new server5 status %s\n", s.ToString().c_str()); 95 | while (1) { 96 | if (f1->HasLeader()) { 97 | f1->GetServerStatus(&msg); 98 | printf("%s\n", msg.c_str()); 99 | } 100 | printf("electing leader after server 5 join the cluster... sleep 2s\n"); 101 | sleep(2); 102 | } 103 | 104 | 105 | getchar(); 106 | delete f2; 107 | delete f3; 108 | delete f4; 109 | delete f5; 110 | delete f1; 111 | return 0; 112 | } 113 | -------------------------------------------------------------------------------- /floyd/example/simple/add_server1.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | Floyd *f1, *f2, *f3, *f4, *f5; 19 | 20 | void *thread_fun(void *arg) { 21 | printf("Add new server4 to cluster and in the same time the cluster is writing data\n"); 22 | slash::Status s = f1->AddServer("127.0.0.1:4314"); 23 | printf("add new server4 status %s\n", s.ToString().c_str()); 24 | } 25 | 26 | int main() 27 | { 28 | Options op("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313", "127.0.0.1", 4311, "./data1/"); 29 | op.Dump(); 30 | 31 | 32 | slash::Status s; 33 | s = Floyd::Open(op, &f1); 34 | printf("start floyd f1 status %s\n", s.ToString().c_str()); 35 | 36 | Options op2("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313", "127.0.0.1", 4312, "./data2/"); 37 | s = Floyd::Open(op2, &f2); 38 | printf("start floyd f2 status %s\n", s.ToString().c_str()); 39 | 40 | Options op3("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313", "127.0.0.1", 4313, "./data3/"); 41 | s = Floyd::Open(op3, &f3); 42 | printf("start floyd f3 status %s\n", s.ToString().c_str()); 43 | 44 | std::string msg; 45 | 46 | while (1) { 47 | if (f1->HasLeader()) { 48 | f1->GetServerStatus(&msg); 49 | printf("%s\n", msg.c_str()); 50 | break; 51 | } 52 | printf("electing leader... sleep 2s\n"); 53 | sleep(2); 54 | } 55 | 56 | // write some data in the origin cluster 57 | 58 | std::string mystr[200100]; 59 | std::string val; 60 | for (int i = 0; i < 200000; i++) { 61 | mystr[i] = slash::RandomString(10); 62 | } 63 | for (int i = 0; i < 10000; i++) { 64 | f1->Write(mystr[i], mystr[i]); 65 | } 66 | 67 | // then start another new server 68 | 69 | Options op4("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314", "127.0.0.1", 4314, "./data4/"); 70 | s = Floyd::Open(op4, &f4); 71 | printf("%s\n", s.ToString().c_str()); 72 | 73 | pthread_t t1; 74 | pthread_create(&t1, NULL, thread_fun, NULL); 75 | 76 | for (int i = 10000; i < 20000; i++) { 77 | f1->Write(mystr[i], mystr[i]); 78 | } 79 | 80 | while (1) { 81 | if (f1->HasLeader()) { 82 | f1->GetServerStatus(&msg); 83 | printf("%s\n", msg.c_str()); 84 | break; 85 | } 86 | printf("electing leader... sleep 2s\n"); 87 | sleep(2); 88 | } 89 | printf("Write 100 pairs key-value after f4 node join in cluster\n"); 90 | for (int i = 0; i < 100; i++) { 91 | f1->Write(mystr[i], mystr[i]); 92 | s = f1->Read(mystr[i], &val); 93 | printf("status %s val %s\n", s.ToString().c_str(), val.c_str()); 94 | } 95 | 96 | Options op5("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4315, "./data5/"); 97 | s = Floyd::Open(op5, &f5); 98 | printf("start f5 node %s\n", s.ToString().c_str()); 99 | 100 | printf("Add new server5 to cluster\n"); 101 | s = f1->AddServer("127.0.0.1:4315"); 102 | printf("add new server5 status %s\n", s.ToString().c_str()); 103 | while (1) { 104 | if (f1->HasLeader()) { 105 | f1->GetServerStatus(&msg); 106 | printf("%s\n", msg.c_str()); 107 | } 108 | printf("electing leader after server 5 join in cluster... sleep 2s\n"); 109 | sleep(2); 110 | } 111 | 112 | 113 | getchar(); 114 | delete f2; 115 | delete f3; 116 | delete f4; 117 | delete f5; 118 | delete f1; 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /floyd/example/simple/read_bench.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "floyd/include/floyd.h" 16 | #include "slash/include/testutil.h" 17 | 18 | using namespace floyd; 19 | uint64_t NowMicros() { 20 | struct timeval tv; 21 | gettimeofday(&tv, NULL); 22 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 23 | } 24 | 25 | Floyd *f1, *f2, *f3, *f4, *f5; 26 | std::string keystr[1001000]; 27 | std::string valstr[1001000]; 28 | int val_size = 10; 29 | int thread_num = 32; 30 | int item_num = 100000; 31 | 32 | void *fun(void *arg) { 33 | int i = 1; 34 | Floyd *p; 35 | if (f1->IsLeader()) { 36 | p = f1; 37 | } else if (f2->IsLeader()) { 38 | p = f2; 39 | } else if (f3->IsLeader()) { 40 | p = f3; 41 | } else if (f4->IsLeader()) { 42 | p = f4; 43 | } else { 44 | p = f5; 45 | } 46 | std::string val; 47 | while (i--) { 48 | for (int j = 0; j < item_num; j++) { 49 | p->Read(keystr[j], &val); 50 | } 51 | } 52 | } 53 | 54 | int main(int argc, char * argv[]) 55 | { 56 | if (argc > 1) { 57 | thread_num = atoi(argv[1]); 58 | } 59 | if (argc > 2) { 60 | val_size = atoi(argv[2]); 61 | } 62 | if (argc > 3) { 63 | item_num = atoi(argv[3]); 64 | } 65 | 66 | printf("multi threads test to get performance thread num %d key size %d item number %d\n", thread_num, val_size, item_num); 67 | 68 | Options op1("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 69 | slash::Status s = Floyd::Open(op1, &f1); 70 | printf("%s\n", s.ToString().c_str()); 71 | 72 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 73 | s = Floyd::Open(op2, &f2); 74 | printf("%s\n", s.ToString().c_str()); 75 | 76 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 77 | s = Floyd::Open(op3, &f3); 78 | printf("%s\n", s.ToString().c_str()); 79 | 80 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 81 | s = Floyd::Open(op4, &f4); 82 | printf("%s\n", s.ToString().c_str()); 83 | 84 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 85 | s = Floyd::Open(op5, &f5); 86 | printf("%s\n", s.ToString().c_str()); 87 | 88 | std::string msg; 89 | int i = 10; 90 | uint64_t st = NowMicros(), ed; 91 | for (int i = 0; i < item_num; i++) { 92 | keystr[i] = slash::RandomString(32); 93 | } 94 | for (int i = 0; i < item_num; i++) { 95 | valstr[i] = slash::RandomString(val_size); 96 | } 97 | while (1) { 98 | if (f1->HasLeader()) { 99 | f1->GetServerStatus(&msg); 100 | printf("%s\n", msg.c_str()); 101 | break; 102 | } 103 | printf("electing leader... sleep 2s\n"); 104 | sleep(2); 105 | } 106 | for (int i = 0; i < item_num; i++) { 107 | f1->Write(keystr[i], valstr[i]); 108 | } 109 | 110 | pthread_t pid[24]; 111 | st = NowMicros(); 112 | for (int i = 0; i < thread_num; i++) { 113 | pthread_create(&pid[i], NULL, fun, NULL); 114 | } 115 | for (int i = 0; i < thread_num; i++) { 116 | pthread_join(pid[i], NULL); 117 | } 118 | ed = NowMicros(); 119 | printf("read_bench reading %d datas cost time microsecond(us) %ld, qps %llu\n", 120 | item_num * thread_num, ed - st, item_num * thread_num * 1000000LL / (ed - st)); 121 | 122 | getchar(); 123 | delete f2; 124 | delete f3; 125 | delete f4; 126 | delete f5; 127 | delete f1; 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /floyd/example/simple/remove_server.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | bool print_members(Floyd* f) { 19 | std::set nodes; 20 | Status s = f->GetAllServers(&nodes); 21 | if (!s.ok()) { 22 | return false; 23 | } 24 | printf("Membership: "); 25 | for (const std::string& n : nodes) { 26 | printf(" %s", n.c_str()); 27 | } 28 | printf("\n"); 29 | return true; 30 | } 31 | 32 | int main() 33 | { 34 | slash::Status s; 35 | Floyd *f1, *f2, *f3, *f4, *f5; 36 | 37 | Options op("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4311, "./data1/"); 38 | s = Floyd::Open(op, &f1); 39 | printf("start floyd f1 status %s\n", s.ToString().c_str()); 40 | 41 | Options op2("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4312, "./data2/"); 42 | s = Floyd::Open(op2, &f2); 43 | printf("start floyd f2 status %s\n", s.ToString().c_str()); 44 | 45 | Options op3("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4313, "./data3/"); 46 | s = Floyd::Open(op3, &f3); 47 | printf("start floyd f3 status %s\n", s.ToString().c_str()); 48 | 49 | Options op4("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4314, "./data4/"); 50 | s = Floyd::Open(op4, &f4); 51 | printf("start floyd f4 status %s\n", s.ToString().c_str()); 52 | 53 | Options op5("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4315, "./data5/"); 54 | s = Floyd::Open(op5, &f5); 55 | printf("start floyd f5 status %s\n", s.ToString().c_str()); 56 | 57 | 58 | std::string msg; 59 | 60 | while (1) { 61 | if (print_members(f1)) { 62 | break; 63 | } 64 | printf("electing leader... sleep 2s\n"); 65 | sleep(2); 66 | } 67 | 68 | // write some data in the origin cluster 69 | 70 | std::string mystr[100100]; 71 | std::string val; 72 | for (int i = 0; i < 100; i++) { 73 | mystr[i] = slash::RandomString(10); 74 | } 75 | for (int i = 0; i < 10; i++) { 76 | f1->Write(mystr[i], mystr[i]); 77 | s = f1->Read(mystr[i], &val); 78 | printf("status %s val %s\n", s.ToString().c_str(), val.c_str()); 79 | } 80 | 81 | getchar(); 82 | // then remove one server 83 | printf("Remove out server4 to cluster\n"); 84 | s = f1->RemoveServer("127.0.0.1:4314"); 85 | delete f4; 86 | printf("Remove out server4 status %s\n", s.ToString().c_str()); 87 | 88 | while (1) { 89 | if (print_members(f1)) { 90 | break; 91 | } 92 | printf("electing leader after server 4 leave the cluster... sleep 2s\n"); 93 | sleep(2); 94 | } 95 | printf("Write 100 pairs key-value after f4 node leave from cluster\n"); 96 | for (int i = 0; i < 10; i++) { 97 | f1->Write(mystr[i], mystr[i]); 98 | s = f1->Read(mystr[i], &val); 99 | printf("status %s val %s\n", s.ToString().c_str(), val.c_str()); 100 | } 101 | 102 | 103 | getchar(); 104 | // then remove one more server 105 | printf("Remove out server5 to cluster\n"); 106 | s = f1->RemoveServer("127.0.0.1:4315"); 107 | delete f5; 108 | printf("Remove out server5 status %s\n", s.ToString().c_str()); 109 | while (1) { 110 | if (print_members(f1)) { 111 | break; 112 | } 113 | printf("electing leader after server 5 leave the cluster... sleep 2s\n"); 114 | sleep(2); 115 | } 116 | printf("Write 100 pairs key-value after f5 node leave from cluster\n"); 117 | for (int i = 0; i < 10; i++) { 118 | f1->Write(mystr[i], mystr[i]); 119 | s = f1->Read(mystr[i], &val); 120 | printf("status %s val %s\n", s.ToString().c_str(), val.c_str()); 121 | } 122 | 123 | 124 | delete f2; 125 | delete f3; 126 | delete f1; 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /floyd/example/simple/t.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | int main() 19 | { 20 | Options op("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 21 | op.Dump(); 22 | 23 | Floyd *f1, *f2, *f3, *f4, *f5; 24 | 25 | slash::Status s; 26 | s = Floyd::Open(op, &f1); 27 | printf("%s\n", s.ToString().c_str()); 28 | 29 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 30 | s = Floyd::Open(op2, &f2); 31 | printf("%s\n", s.ToString().c_str()); 32 | 33 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 34 | s = Floyd::Open(op3, &f3); 35 | printf("%s\n", s.ToString().c_str()); 36 | 37 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 38 | s = Floyd::Open(op4, &f4); 39 | printf("%s\n", s.ToString().c_str()); 40 | 41 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 42 | s = Floyd::Open(op5, &f5); 43 | printf("%s\n", s.ToString().c_str()); 44 | 45 | std::string msg; 46 | int cnt = 100; 47 | uint64_t st = NowMicros(), ed; 48 | 49 | sleep(10); 50 | while (1) { 51 | if (f1->HasLeader()) { 52 | break; 53 | } 54 | printf("electing leader... sleep 2s\n"); 55 | sleep(2); 56 | } 57 | 58 | while (cnt--) { 59 | std::string mystr[100100]; 60 | for (int i = 0; i < 100000; i++) { 61 | mystr[i] = slash::RandomString(10); 62 | } 63 | f1->GetServerStatus(&msg); 64 | printf("%s\n", msg.c_str()); 65 | st = NowMicros(); 66 | for (int j = 0; j < 100000; j++) { 67 | f1->Write(mystr[j], mystr[j]); 68 | // f1->Write("zz", "zz"); 69 | } 70 | ed = NowMicros(); 71 | printf("write 100000 cost time microsecond(us) %ld, qps %llu\n", ed - st, 100000 * 1000000LL / (ed - st)); 72 | } 73 | 74 | delete f1; 75 | 76 | cnt = 5; 77 | while (cnt--) { 78 | f2->GetServerStatus(&msg); 79 | for (int j = 0; j < 100; j++) { 80 | f2->Write("zz2" + char(j), "value2" + char(j)); 81 | } 82 | printf("%s\n", msg.c_str()); 83 | } 84 | 85 | s = Floyd::Open(op, &f1); 86 | if (!s.ok()) { 87 | printf("floyd reoptn failed\n"); 88 | } 89 | cnt = 5; 90 | while (cnt--) { 91 | f2->GetServerStatus(&msg); 92 | for (int j = 0; j < 100; j++) { 93 | f1->Write("zz3" + char(j), "value3" + char(j)); 94 | } 95 | printf("%s\n", msg.c_str()); 96 | } 97 | 98 | getchar(); 99 | delete f2; 100 | delete f3; 101 | delete f4; 102 | delete f5; 103 | delete f1; 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /floyd/example/simple/t1.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "floyd/include/floyd.h" 16 | #include "slash/include/testutil.h" 17 | 18 | using namespace floyd; 19 | uint64_t NowMicros() { 20 | struct timeval tv; 21 | gettimeofday(&tv, NULL); 22 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 23 | } 24 | 25 | Floyd *f1, *f2, *f3, *f4, *f5; 26 | std::string keystr[1001000]; 27 | std::string valstr[1001000]; 28 | int val_size = 128; 29 | int thread_num = 4; 30 | int item_num = 10000; 31 | 32 | void *fun(void *arg) { 33 | int i = 1; 34 | Floyd *p; 35 | if (f1->IsLeader()) { 36 | p = f1; 37 | } else if (f2->IsLeader()) { 38 | p = f2; 39 | } else if (f3->IsLeader()) { 40 | p = f3; 41 | } else if (f4->IsLeader()) { 42 | p = f4; 43 | } else { 44 | p = f5; 45 | } 46 | while (i--) { 47 | for (int j = 0; j < item_num; j++) { 48 | p->Write(keystr[j], valstr[j]); 49 | } 50 | } 51 | } 52 | 53 | int main(int argc, char * argv[]) 54 | { 55 | if (argc > 1) { 56 | thread_num = atoi(argv[1]); 57 | } 58 | if (argc > 2) { 59 | val_size = atoi(argv[2]); 60 | } 61 | if (argc > 3) { 62 | item_num = atoi(argv[3]); 63 | } 64 | 65 | printf("multi threads test to get performance thread num %d key size %d item number %d\n", thread_num, val_size, item_num); 66 | 67 | Options op1("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 68 | slash::Status s = Floyd::Open(op1, &f1); 69 | printf("%s\n", s.ToString().c_str()); 70 | 71 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 72 | s = Floyd::Open(op2, &f2); 73 | printf("%s\n", s.ToString().c_str()); 74 | 75 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 76 | s = Floyd::Open(op3, &f3); 77 | printf("%s\n", s.ToString().c_str()); 78 | 79 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 80 | s = Floyd::Open(op4, &f4); 81 | printf("%s\n", s.ToString().c_str()); 82 | 83 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 84 | s = Floyd::Open(op5, &f5); 85 | printf("%s\n", s.ToString().c_str()); 86 | 87 | std::string msg; 88 | int i = 10; 89 | uint64_t st = NowMicros(), ed; 90 | for (int i = 0; i < item_num; i++) { 91 | keystr[i] = slash::RandomString(32); 92 | } 93 | for (int i = 0; i < item_num; i++) { 94 | valstr[i] = slash::RandomString(val_size); 95 | } 96 | while (1) { 97 | if (f1->HasLeader()) { 98 | f1->GetServerStatus(&msg); 99 | printf("%s\n", msg.c_str()); 100 | break; 101 | } 102 | printf("electing leader... sleep 2s\n"); 103 | sleep(2); 104 | } 105 | 106 | pthread_t pid[24]; 107 | st = NowMicros(); 108 | for (int i = 0; i < thread_num; i++) { 109 | pthread_create(&pid[i], NULL, fun, NULL); 110 | } 111 | for (int i = 0; i < thread_num; i++) { 112 | pthread_join(pid[i], NULL); 113 | } 114 | ed = NowMicros(); 115 | printf("write %d datas cost time microsecond(us) %ld, qps %llu\n", item_num * thread_num, ed - st, item_num * thread_num * 1000000LL / (ed - st)); 116 | 117 | getchar(); 118 | delete f2; 119 | delete f3; 120 | delete f4; 121 | delete f5; 122 | delete f1; 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /floyd/example/simple/t2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | int main() 19 | { 20 | Options op("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 21 | op.Dump(); 22 | 23 | Floyd *f1, *f2, *f3, *f4, *f5; 24 | 25 | slash::Status s; 26 | s = Floyd::Open(op, &f1); 27 | printf("%s\n", s.ToString().c_str()); 28 | 29 | usleep(100000); 30 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 31 | s = Floyd::Open(op2, &f2); 32 | printf("%s\n", s.ToString().c_str()); 33 | 34 | usleep(200000); 35 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 36 | s = Floyd::Open(op3, &f3); 37 | printf("%s\n", s.ToString().c_str()); 38 | 39 | usleep(300000); 40 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 41 | s = Floyd::Open(op4, &f4); 42 | printf("%s\n", s.ToString().c_str()); 43 | 44 | usleep(400000); 45 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 46 | s = Floyd::Open(op5, &f5); 47 | printf("%s\n", s.ToString().c_str()); 48 | 49 | std::string msg; 50 | int i = 8; 51 | while (i--) { 52 | f1->GetServerStatus(&msg); 53 | printf("%s\n", msg.c_str()); 54 | sleep(2); 55 | } 56 | 57 | printf("delete node2, node3 to show 3 nodes status\n"); 58 | delete f2; 59 | delete f3; 60 | i = 8; 61 | while (i--) { 62 | f1->GetServerStatus(&msg); 63 | printf("%s\n", msg.c_str()); 64 | sleep(2); 65 | } 66 | 67 | printf("restart node2, node3 and stop node4, show 4 nodes status\n"); 68 | s = Floyd::Open(op2, &f2); 69 | s = Floyd::Open(op3, &f3); 70 | delete f4; 71 | i = 8; 72 | while (i--) { 73 | f1->GetServerStatus(&msg); 74 | printf("%s\n", msg.c_str()); 75 | sleep(2); 76 | } 77 | 78 | printf("reopen node4, delete node1, node5 show 3 nodes status\n"); 79 | s = Floyd::Open(op4, &f4); 80 | delete f1; 81 | delete f5; 82 | i = 8; 83 | while (i--) { 84 | f3->GetServerStatus(&msg); 85 | printf("%s\n", msg.c_str()); 86 | sleep(2); 87 | } 88 | 89 | printf("delete node2, now only two nodes are alive\n"); 90 | delete f2; 91 | i = 8; 92 | while (i--) { 93 | f3->GetServerStatus(&msg); 94 | printf("%s\n", msg.c_str()); 95 | sleep(2); 96 | } 97 | 98 | printf("reopen node1, node2, node5, the cluster recover now\n"); 99 | s = Floyd::Open(op, &f1); 100 | s = Floyd::Open(op2, &f2); 101 | s = Floyd::Open(op5, &f5); 102 | i = 8; 103 | while (i--) { 104 | f1->GetServerStatus(&msg); 105 | printf("%s\n", msg.c_str()); 106 | sleep(2); 107 | } 108 | 109 | getchar(); 110 | delete f2; 111 | delete f3; 112 | delete f4; 113 | delete f5; 114 | delete f1; 115 | 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /floyd/example/simple/t3.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | std::string mystr[100100]; 18 | 19 | int main() 20 | { 21 | Options op("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 22 | op.Dump(); 23 | 24 | Floyd *f1, *f2, *f3, *f4, *f5; 25 | 26 | slash::Status s; 27 | s = Floyd::Open(op, &f1); 28 | printf("%s\n", s.ToString().c_str()); 29 | 30 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 31 | s = Floyd::Open(op2, &f2); 32 | printf("%s\n", s.ToString().c_str()); 33 | 34 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 35 | s = Floyd::Open(op3, &f3); 36 | printf("%s\n", s.ToString().c_str()); 37 | 38 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 39 | s = Floyd::Open(op4, &f4); 40 | printf("%s\n", s.ToString().c_str()); 41 | 42 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 43 | s = Floyd::Open(op5, &f5); 44 | printf("%s\n", s.ToString().c_str()); 45 | 46 | std::string msg; 47 | int i = 100; 48 | uint64_t st = NowMicros(), ed; 49 | for (int i = 0; i < 100000; i++) { 50 | mystr[i] = slash::RandomString(10); 51 | } 52 | 53 | while (1) { 54 | if (f1->HasLeader()) { 55 | break; 56 | } 57 | sleep(2); 58 | } 59 | 60 | // ran at the begining 61 | printf("run 5 times, every time write 100 item. at the beginning state\n"); 62 | i = 5; 63 | std::string val; 64 | while (i--) { 65 | f3->GetServerStatus(&msg); 66 | for (int j = 0; j < 100; j++) { 67 | f3->Write(mystr[j], mystr[j]); 68 | s = f3->Read(mystr[j], &val); 69 | printf("status %s val %s\n", s.ToString().c_str(), val.c_str()); 70 | } 71 | printf("%s\n", msg.c_str()); 72 | } 73 | 74 | // sleep(1); 75 | 76 | 77 | getchar(); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /floyd/example/simple/t4.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | int main() 19 | { 20 | Options op("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 21 | op.Dump(); 22 | 23 | Floyd *f1, *f2, *f3, *f4, *f5; 24 | 25 | slash::Status s; 26 | s = Floyd::Open(op, &f1); 27 | printf("%s\n", s.ToString().c_str()); 28 | 29 | usleep(100000); 30 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 31 | s = Floyd::Open(op2, &f2); 32 | printf("%s\n", s.ToString().c_str()); 33 | 34 | usleep(200000); 35 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 36 | s = Floyd::Open(op3, &f3); 37 | printf("%s\n", s.ToString().c_str()); 38 | 39 | usleep(300000); 40 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 41 | s = Floyd::Open(op4, &f4); 42 | printf("%s\n", s.ToString().c_str()); 43 | 44 | usleep(400000); 45 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 46 | s = Floyd::Open(op5, &f5); 47 | printf("%s\n", s.ToString().c_str()); 48 | 49 | bool is_writed = false; 50 | std::string msg; 51 | while (1) { 52 | f1->GetServerStatus(&msg); 53 | if (is_writed == false) { 54 | // writing one record to update the meta data 55 | slash::Status s = f1->Write("lastdata", "lastdata"); 56 | if (s.ok()) { 57 | is_writed = true; 58 | printf("write lastdata success\n"); 59 | } 60 | } 61 | printf("%s\n", msg.c_str()); 62 | sleep(2); 63 | } 64 | getchar(); 65 | delete f2; 66 | delete f3; 67 | delete f4; 68 | delete f5; 69 | delete f1; 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /floyd/example/simple/t5.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | int main() 19 | { 20 | printf("testing single mode floyd, including starting a node and writing data\n"); 21 | Options op("127.0.0.1:8901", "127.0.0.1", 8901, "./data1/"); 22 | op.Dump(); 23 | 24 | Floyd *f1; 25 | 26 | op.single_mode = true; 27 | slash::Status s; 28 | s = Floyd::Open(op, &f1); 29 | printf("%s\n", s.ToString().c_str()); 30 | 31 | std::string msg; 32 | int cnt = 10; 33 | while (cnt--) { 34 | f1->GetServerStatus(&msg); 35 | printf("%s\n", msg.c_str()); 36 | sleep(2); 37 | } 38 | uint64_t st, ed; 39 | std::string mystr[100100]; 40 | for (int i = 0; i < 100000; i++) { 41 | mystr[i] = slash::RandomString(10); 42 | } 43 | f1->GetServerStatus(&msg); 44 | printf("%s\n", msg.c_str()); 45 | st = NowMicros(); 46 | for (int j = 0; j < 100000; j++) { 47 | slash::Status ws = f1->Write(mystr[j], mystr[j]); 48 | if (!ws.ok()) { 49 | printf("floyd write error\n"); 50 | } 51 | // f1->Write("zz", "zz"); 52 | } 53 | ed = NowMicros(); 54 | printf("write 100000 cost time microsecond(us) %ld, qps %llu\n", ed - st, 100000 * 1000000LL / (ed - st)); 55 | getchar(); 56 | delete f1; 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /floyd/example/simple/t6.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include "floyd/include/floyd.h" 16 | #include "slash/include/testutil.h" 17 | 18 | using namespace floyd; 19 | uint64_t NowMicros() { 20 | struct timeval tv; 21 | gettimeofday(&tv, NULL); 22 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 23 | } 24 | 25 | Floyd *f1, *f2, *f3, *f4, *f5; 26 | std::string keystr[1001000]; 27 | std::string valstr[1001000]; 28 | int val_size = 128; 29 | int thread_num = 4; 30 | int item_num = 10000; 31 | 32 | void *fun(void *arg) { 33 | int i = 1; 34 | Floyd *p = f1; 35 | if (f1->IsLeader()) { 36 | p = f2; 37 | } 38 | while (i--) { 39 | for (int j = 0; j < item_num; j++) { 40 | p->Write(keystr[j], valstr[j]); 41 | } 42 | } 43 | } 44 | 45 | int main(int argc, char * argv[]) 46 | { 47 | if (argc > 1) { 48 | val_size = atoi(argv[1]); 49 | } 50 | if (argc > 2) { 51 | thread_num = atoi(argv[2]); 52 | } 53 | 54 | printf("multi threads test to get performance thread num %d key size %d\n", thread_num, val_size); 55 | 56 | Options op1("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 57 | slash::Status s = Floyd::Open(op1, &f1); 58 | printf("%s\n", s.ToString().c_str()); 59 | 60 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 61 | s = Floyd::Open(op2, &f2); 62 | printf("%s\n", s.ToString().c_str()); 63 | 64 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 65 | s = Floyd::Open(op3, &f3); 66 | printf("%s\n", s.ToString().c_str()); 67 | 68 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 69 | s = Floyd::Open(op4, &f4); 70 | printf("%s\n", s.ToString().c_str()); 71 | 72 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 73 | s = Floyd::Open(op5, &f5); 74 | printf("%s\n", s.ToString().c_str()); 75 | 76 | std::string msg; 77 | int i = 10; 78 | uint64_t st = NowMicros(), ed; 79 | for (int i = 0; i < item_num; i++) { 80 | keystr[i] = slash::RandomString(32); 81 | } 82 | for (int i = 0; i < item_num; i++) { 83 | valstr[i] = slash::RandomString(val_size); 84 | } 85 | while (1) { 86 | if (f1->HasLeader()) { 87 | f1->GetServerStatus(&msg); 88 | printf("%s\n", msg.c_str()); 89 | break; 90 | } 91 | printf("electing leader... sleep 2s\n"); 92 | sleep(2); 93 | } 94 | 95 | pthread_t pid[24]; 96 | st = NowMicros(); 97 | for (int i = 0; i < thread_num; i++) { 98 | pthread_create(&pid[i], NULL, fun, NULL); 99 | } 100 | for (int i = 0; i < thread_num; i++) { 101 | pthread_join(pid[i], NULL); 102 | } 103 | ed = NowMicros(); 104 | printf("write 100000 cost time microsecond(us) %ld, qps %llu\n", ed - st, item_num * thread_num * 1000000LL / (ed - st)); 105 | 106 | getchar(); 107 | delete f2; 108 | delete f3; 109 | delete f4; 110 | delete f5; 111 | delete f1; 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /floyd/example/simple/t7.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | std::string keystr[1001000]; 19 | std::string valstr[1001000]; 20 | int val_size = 128; 21 | int item_num = 1000; 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | if (argc > 1) { 26 | val_size = atoi(argv[1]); 27 | } 28 | 29 | printf("test write 3 node and then join the other 2 node case, key size %d\n", val_size); 30 | 31 | Options op("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8901, "./data1/"); 32 | op.Dump(); 33 | 34 | Floyd *f1, *f2, *f3, *f4, *f5; 35 | 36 | slash::Status s; 37 | s = Floyd::Open(op, &f1); 38 | printf("%s\n", s.ToString().c_str()); 39 | 40 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8902, "./data2/"); 41 | s = Floyd::Open(op2, &f2); 42 | printf("%s\n", s.ToString().c_str()); 43 | 44 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8903, "./data3/"); 45 | s = Floyd::Open(op3, &f3); 46 | printf("%s\n", s.ToString().c_str()); 47 | 48 | Options op4("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8904, "./data4/"); 49 | s = Floyd::Open(op4, &f4); 50 | printf("%s\n", s.ToString().c_str()); 51 | 52 | Options op5("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903,127.0.0.1:8904,127.0.0.1:8905", "127.0.0.1", 8905, "./data5/"); 53 | s = Floyd::Open(op5, &f5); 54 | printf("%s\n", s.ToString().c_str()); 55 | 56 | std::string msg; 57 | int cnt = 1; 58 | uint64_t st = NowMicros(), ed; 59 | for (int i = 0; i < item_num; i++) { 60 | keystr[i] = slash::RandomString(32); 61 | } 62 | 63 | while (1) { 64 | if (f1->HasLeader()) { 65 | break; 66 | } 67 | printf("electing leader... sleep 2s\n"); 68 | sleep(2); 69 | } 70 | 71 | while (cnt--) { 72 | for (int i = 0; i < item_num; i++) { 73 | valstr[i] = slash::RandomString(10); 74 | } 75 | f1->GetServerStatus(&msg); 76 | printf("%s\n", msg.c_str()); 77 | st = NowMicros(); 78 | for (int j = 0; j < item_num; j++) { 79 | slash::Status s1 = f1->Write(keystr[j], valstr[j]); 80 | if (!s1.ok()) { 81 | printf("write key error in 5 node, key is %s\n", keystr[j].c_str()); 82 | } 83 | } 84 | ed = NowMicros(); 85 | printf("write 100000 cost time microsecond(us) %ld, qps %llu\n", ed - st, item_num * 1000000LL / (ed - st)); 86 | } 87 | 88 | delete f1; 89 | delete f5; 90 | 91 | sleep(10); 92 | while (1) { 93 | if (f2->HasLeader()) { 94 | break; 95 | } 96 | printf("electing leader... sleep 2s\n"); 97 | sleep(2); 98 | } 99 | cnt = 1; 100 | while (cnt--) { 101 | for (int i = 0; i < item_num; i++) { 102 | keystr[i] = slash::RandomString(32); 103 | } 104 | for (int i = 0; i < item_num; i++) { 105 | valstr[i] = slash::RandomString(10); 106 | } 107 | f2->GetServerStatus(&msg); 108 | printf("%s\n", msg.c_str()); 109 | st = NowMicros(); 110 | for (int j = 0; j < item_num; j++) { 111 | slash::Status s1 = f2->Write(keystr[j], valstr[j]); 112 | if (s.ok()) { 113 | printf("write key success number %d %s %s\n", j, keystr[j].c_str(), valstr[j].c_str()); 114 | } else { 115 | printf("write error\n"); 116 | } 117 | } 118 | ed = NowMicros(); 119 | printf("write after delete two nodes cost time microsecond(us) %ld, qps %llu\n", ed - st, item_num * 1000000LL / (ed - st)); 120 | } 121 | 122 | s = Floyd::Open(op, &f1); 123 | s = Floyd::Open(op5, &f5); 124 | 125 | cnt = 10; 126 | while (cnt--) { 127 | f2->GetServerStatus(&msg); 128 | printf("%s\n", msg.c_str()); 129 | sleep(2); 130 | } 131 | 132 | getchar(); 133 | delete f2; 134 | delete f3; 135 | delete f4; 136 | delete f5; 137 | delete f1; 138 | return 0; 139 | } 140 | -------------------------------------------------------------------------------- /floyd/example/simple/t8.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file t8.cc 3 | * @brief start three nodes, node1 has the shortest log, and it will start first 4 | * log struct: (term, key, value) 5 | * node1 | (22, "22", "22"), (22, "23", "23"), (22, "24", "24"), (22, "25", "25"), (22, "26", 26") 6 | * node2 | (22, "22", "22"), (22, "23", "23"), (22, "24", "24"), (27, "27key", "27val"), (27, "28key", "28val"), (27, "29key", "29val"), (27, "30key", "30val"), (27, "30key", "30val") 7 | * node3 | (22, "22", "22"), (22, "23", "23"), (22, "24", "24"), (27, "27key", "27val"), (27, "28key", "28val"), (27, "29key", "29val"), (27, "30key", "30val"), (27, "30key", "30val") 8 | * 9 | * after start node2, node3. node2 or node3 will become leader, and node1 will 10 | * delete these two log (22, "25", "25"), (22, "26", 26") 11 | * 12 | * @author chenzongzhi 13 | * @version 1.0.0 14 | * @date 2017-08-06 15 | */ 16 | 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "rocksdb/db.h" 24 | #include "slash/include/env.h" 25 | 26 | #include "floyd/src/raft_log.h" 27 | #include "floyd/src/raft_meta.h" 28 | #include "floyd/src/floyd.pb.h" 29 | #include "floyd/src/logger.h" 30 | #include "floyd/include/floyd.h" 31 | 32 | using namespace floyd; 33 | 34 | void InitEntry(int term, const std::string &key, const std::string &val, Entry *entry) { 35 | entry->set_term(term); 36 | entry->set_key(key); 37 | entry->set_value(val); 38 | entry->set_optype(Entry_OpType_kWrite); 39 | } 40 | 41 | int cl1(const std::string path) { 42 | // construct data1 node 43 | Logger *logger; 44 | slash::CreatePath(path); 45 | if (NewLogger(path + "/LOG", &logger) != 0) { 46 | return -1; 47 | } 48 | rocksdb::DB* db; 49 | rocksdb::Options options; 50 | options.create_if_missing = true; 51 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 52 | RaftMeta *raft_meta = new RaftMeta(db, logger); 53 | raft_meta->Init(); 54 | RaftLog *raft_log = new RaftLog(db, logger); 55 | 56 | std::vector entries; 57 | Entry *entry = new Entry(); 58 | InitEntry(22, "22", "22", entry); 59 | entries.push_back(entry); 60 | 61 | entry = new Entry(); 62 | InitEntry(22, "23", "23", entry); 63 | entries.push_back(entry); 64 | 65 | entry = new Entry(); 66 | InitEntry(22, "24", "24", entry); 67 | entries.push_back(entry); 68 | 69 | entry = new Entry(); 70 | InitEntry(22, "25", "25", entry); 71 | entries.push_back(entry); 72 | 73 | entry = new Entry(); 74 | InitEntry(22, "26", "26", entry); 75 | entries.push_back(entry); 76 | 77 | raft_log->Append(entries); 78 | raft_meta->SetCurrentTerm(6); 79 | raft_meta->SetCommitIndex(9); 80 | raft_meta->SetLastApplied(0); 81 | 82 | delete raft_meta; 83 | delete raft_log; 84 | delete db; 85 | delete logger; 86 | } 87 | 88 | int cl2(const std::string path) { 89 | // construct data1 node 90 | Logger *logger; 91 | slash::CreatePath(path); 92 | if (NewLogger(path + "/LOG", &logger) != 0) { 93 | return -1; 94 | } 95 | rocksdb::DB* db; 96 | rocksdb::Options options; 97 | options.create_if_missing = true; 98 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 99 | RaftMeta *raft_meta = new RaftMeta(db, logger); 100 | raft_meta->Init(); 101 | RaftLog *raft_log = new RaftLog(db, logger); 102 | 103 | std::vector entries; 104 | 105 | Entry *entry = new Entry(); 106 | InitEntry(22, "22", "22", entry); 107 | entries.push_back(entry); 108 | 109 | entry = new Entry(); 110 | InitEntry(22, "23", "23", entry); 111 | entries.push_back(entry); 112 | 113 | entry = new Entry(); 114 | InitEntry(22, "24", "24", entry); 115 | entries.push_back(entry); 116 | 117 | entry = new Entry(); 118 | InitEntry(27, "27key", "27val", entry); 119 | entries.push_back(entry); 120 | 121 | entry = new Entry(); 122 | InitEntry(27, "28key", "28val", entry); 123 | entries.push_back(entry); 124 | 125 | entry = new Entry(); 126 | InitEntry(27, "29key", "29val", entry); 127 | entries.push_back(entry); 128 | 129 | entry = new Entry(); 130 | InitEntry(27, "30key", "30val", entry); 131 | entries.push_back(entry); 132 | 133 | entry = new Entry(); 134 | InitEntry(27, "31key", "31val", entry); 135 | entries.push_back(entry); 136 | 137 | raft_log->Append(entries); 138 | raft_meta->SetCurrentTerm(6); 139 | raft_meta->SetCommitIndex(9); 140 | raft_meta->SetLastApplied(0); 141 | 142 | delete raft_meta; 143 | delete raft_log; 144 | delete db; 145 | delete logger; 146 | } 147 | 148 | int cl3(const std::string path) { 149 | // construct data1 node 150 | Logger *logger; 151 | slash::CreatePath(path); 152 | if (NewLogger(path + "/LOG", &logger) != 0) { 153 | return -1; 154 | } 155 | rocksdb::DB* db; 156 | rocksdb::Options options; 157 | options.create_if_missing = true; 158 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 159 | RaftMeta *raft_meta = new RaftMeta(db, logger); 160 | raft_meta->Init(); 161 | RaftLog *raft_log = new RaftLog(db, logger); 162 | 163 | std::vector entries; 164 | Entry *entry = new Entry(); 165 | InitEntry(22, "22", "22", entry); 166 | entries.push_back(entry); 167 | 168 | entry = new Entry(); 169 | InitEntry(22, "23", "23", entry); 170 | entries.push_back(entry); 171 | 172 | entry = new Entry(); 173 | InitEntry(22, "24", "24", entry); 174 | entries.push_back(entry); 175 | 176 | entry = new Entry(); 177 | InitEntry(27, "27key", "27val", entry); 178 | entries.push_back(entry); 179 | 180 | entry = new Entry(); 181 | InitEntry(27, "28key", "28val", entry); 182 | entries.push_back(entry); 183 | 184 | entry = new Entry(); 185 | InitEntry(27, "29key", "29val", entry); 186 | entries.push_back(entry); 187 | 188 | entry = new Entry(); 189 | InitEntry(27, "30key", "30val", entry); 190 | entries.push_back(entry); 191 | 192 | entry = new Entry(); 193 | InitEntry(27, "31key", "31val", entry); 194 | entries.push_back(entry); 195 | 196 | raft_log->Append(entries); 197 | raft_meta->SetCurrentTerm(6); 198 | raft_meta->SetCommitIndex(9); 199 | raft_meta->SetLastApplied(0); 200 | 201 | delete raft_meta; 202 | delete raft_log; 203 | delete db; 204 | delete logger; 205 | } 206 | 207 | int main() 208 | { 209 | cl1("./data1/"); 210 | cl2("./data2/"); 211 | cl3("./data3/"); 212 | 213 | Floyd *f1, *f2, *f3; 214 | slash::Status s; 215 | 216 | Options op1("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903", "127.0.0.1", 8901, "./data1/"); 217 | s = Floyd::Open(op1, &f1); 218 | printf("%s\n", s.ToString().c_str()); 219 | 220 | sleep(2); 221 | 222 | Options op2("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903", "127.0.0.1", 8902, "./data2/"); 223 | s = Floyd::Open(op2, &f2); 224 | printf("%s\n", s.ToString().c_str()); 225 | 226 | Options op3("127.0.0.1:8901,127.0.0.1:8902,127.0.0.1:8903", "127.0.0.1", 8903, "./data3/"); 227 | s = Floyd::Open(op3, &f3); 228 | printf("%s\n", s.ToString().c_str()); 229 | 230 | getchar(); 231 | 232 | return 0; 233 | } 234 | -------------------------------------------------------------------------------- /floyd/example/simple/test_lock.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | int main() 19 | { 20 | Options op("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4311, "./data1/"); 21 | op.Dump(); 22 | 23 | Floyd *f1, *f2, *f3, *f4, *f5; 24 | 25 | slash::Status s; 26 | s = Floyd::Open(op, &f1); 27 | printf("%s\n", s.ToString().c_str()); 28 | 29 | Options op2("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4312, "./data2/"); 30 | s = Floyd::Open(op2, &f2); 31 | printf("%s\n", s.ToString().c_str()); 32 | 33 | Options op3("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4313, "./data3/"); 34 | s = Floyd::Open(op3, &f3); 35 | printf("%s\n", s.ToString().c_str()); 36 | 37 | Options op4("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4314, "./data4/"); 38 | s = Floyd::Open(op4, &f4); 39 | printf("%s\n", s.ToString().c_str()); 40 | 41 | Options op5("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4315, "./data5/"); 42 | s = Floyd::Open(op5, &f5); 43 | printf("%s\n", s.ToString().c_str()); 44 | 45 | std::string msg; 46 | uint64_t st = NowMicros(), ed; 47 | 48 | while (1) { 49 | if (f1->HasLeader()) { 50 | break; 51 | } 52 | printf("electing leader... sleep 2s\n"); 53 | sleep(2); 54 | } 55 | 56 | int cnt = 100; 57 | std::string holder = "baotiao-holder"; 58 | while (cnt--) { 59 | s = f1->TryLock("baotiao-key", holder, 1000); 60 | printf("TryLock status %s holder %s\n", s.ToString().c_str(), holder.c_str()); 61 | s = f1->UnLock("baotiao-key", holder); 62 | printf("TryUnLock status %s holder %s\n", s.ToString().c_str(), holder.c_str()); 63 | } 64 | 65 | getchar(); 66 | delete f2; 67 | delete f3; 68 | delete f4; 69 | delete f5; 70 | delete f1; 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /floyd/example/simple/test_lock1.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | Floyd *f1, *f2, *f3, *f4, *f5; 19 | slash::Status s; 20 | 21 | /* 22 | * in this case, thread1 get the lock first, and then sleep 6 second 23 | * during this time, thread2 try to get lock every second, it will failed every time. 24 | * at the 7 second, thread2 may get the lock 25 | */ 26 | 27 | void *thread1_fun(void *arg) { 28 | std::string holder = "thread1_fun"; 29 | while (1) { 30 | s = f1->TryLock("baotiao-key", holder, 10000); 31 | printf("thread1 TryLock status %s holder %s\n", s.ToString().c_str(), holder.c_str()); 32 | sleep(6); 33 | s = f1->UnLock("baotiao-key", holder); 34 | printf("thread2 TryUnLock status %s holder %s\n", s.ToString().c_str(), holder.c_str()); 35 | } 36 | } 37 | 38 | void *thread2_fun(void *arg) { 39 | std::string holder = "thread2_fun"; 40 | while (1) { 41 | s = f1->TryLock("baotiao-key", holder, 10000); 42 | printf("thread2 TryLock status %s holder %s\n", s.ToString().c_str(), holder.c_str()); 43 | s = f1->UnLock("baotiao-key", holder); 44 | printf("thread2 TryUnLock status %s holder %s\n", s.ToString().c_str(), holder.c_str()); 45 | sleep(1); 46 | } 47 | } 48 | 49 | int main() 50 | { 51 | Options op("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4311, "./data1/"); 52 | op.Dump(); 53 | 54 | 55 | s = Floyd::Open(op, &f1); 56 | printf("%s\n", s.ToString().c_str()); 57 | 58 | Options op2("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4312, "./data2/"); 59 | s = Floyd::Open(op2, &f2); 60 | printf("%s\n", s.ToString().c_str()); 61 | 62 | Options op3("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4313, "./data3/"); 63 | s = Floyd::Open(op3, &f3); 64 | printf("%s\n", s.ToString().c_str()); 65 | 66 | Options op4("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4314, "./data4/"); 67 | s = Floyd::Open(op4, &f4); 68 | printf("%s\n", s.ToString().c_str()); 69 | 70 | Options op5("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4315, "./data5/"); 71 | s = Floyd::Open(op5, &f5); 72 | printf("%s\n", s.ToString().c_str()); 73 | 74 | std::string msg; 75 | uint64_t st = NowMicros(), ed; 76 | 77 | while (1) { 78 | if (f1->HasLeader()) { 79 | break; 80 | } 81 | printf("electing leader... sleep 2s\n"); 82 | sleep(2); 83 | } 84 | 85 | pthread_t t1, t2; 86 | pthread_create(&t1, NULL, thread1_fun, NULL); 87 | sleep(1); 88 | pthread_create(&t2, NULL, thread2_fun, NULL); 89 | 90 | pthread_join(t1, NULL); 91 | pthread_join(t2, NULL); 92 | 93 | getchar(); 94 | delete f2; 95 | delete f3; 96 | delete f4; 97 | delete f5; 98 | delete f1; 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /floyd/example/simple/test_lock2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "floyd/include/floyd.h" 9 | #include "slash/include/testutil.h" 10 | 11 | using namespace floyd; 12 | uint64_t NowMicros() { 13 | struct timeval tv; 14 | gettimeofday(&tv, NULL); 15 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 16 | } 17 | 18 | int main() 19 | { 20 | Options op("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4311, "./data1/"); 21 | op.Dump(); 22 | 23 | Floyd *f1, *f2, *f3, *f4, *f5; 24 | 25 | slash::Status s; 26 | s = Floyd::Open(op, &f1); 27 | printf("%s\n", s.ToString().c_str()); 28 | 29 | Options op2("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4312, "./data2/"); 30 | s = Floyd::Open(op2, &f2); 31 | printf("%s\n", s.ToString().c_str()); 32 | 33 | Options op3("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4313, "./data3/"); 34 | s = Floyd::Open(op3, &f3); 35 | printf("%s\n", s.ToString().c_str()); 36 | 37 | Options op4("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4314, "./data4/"); 38 | s = Floyd::Open(op4, &f4); 39 | printf("%s\n", s.ToString().c_str()); 40 | 41 | Options op5("127.0.0.1:4311,127.0.0.1:4312,127.0.0.1:4313,127.0.0.1:4314,127.0.0.1:4315", "127.0.0.1", 4315, "./data5/"); 42 | s = Floyd::Open(op5, &f5); 43 | printf("%s\n", s.ToString().c_str()); 44 | 45 | std::string msg; 46 | uint64_t st = NowMicros(), ed; 47 | 48 | while (1) { 49 | if (f1->HasLeader()) { 50 | break; 51 | } 52 | printf("electing leader... sleep 2s\n"); 53 | sleep(2); 54 | } 55 | 56 | std::string key_name = "baotiao-key"; 57 | // 1. lock by f1 58 | std::string holder = "baotiao-holder"; 59 | s = f1->TryLock(key_name, holder, 1000); 60 | printf("1. TryLock status %s name %s holder %s\n", s.ToString().c_str(), key_name.c_str(), holder.c_str()); 61 | 62 | // 2. delete f1 node 63 | delete f1; 64 | 65 | // 3. TryLock by other node 66 | // here the TryLock should be failed 67 | while (1) { 68 | if (f2->HasLeader()) { 69 | break; 70 | } 71 | printf("electing leader... sleep 2s\n"); 72 | sleep(2); 73 | } 74 | std::string holder2 = "baotiao-holder2"; 75 | s = f2->TryLock(key_name, holder2, 1000); 76 | printf("3. TryLock should be failed, since the lock hasn't been unlock\n"); 77 | printf("3. TryLock status %s name %s holder %s\n", s.ToString().c_str(), key_name.c_str(), holder2.c_str()); 78 | 79 | // 4. Unlock by other node 80 | // here the Unlock should be success 81 | s = f2->UnLock(key_name, holder); 82 | printf("4. Unlock by other node, here the Unlock should be success\n"); 83 | printf("4. UnLock status %s name %s holder %s\n", s.ToString().c_str(), key_name.c_str(), holder.c_str()); 84 | 85 | // 5. TryLock by other node again 86 | // here the TryLock should be success 87 | s = f2->TryLock(key_name, holder2, 1000); 88 | printf("5. TryLock should be success\n"); 89 | printf("5. TryLock status %s name %s holder %s\n", s.ToString().c_str(), key_name.c_str(), holder2.c_str()); 90 | 91 | // 6. delete more node 92 | delete f2; 93 | delete f3; 94 | printf("6. Delete more nodes, test lock when the cluster is error\n"); 95 | s = f4->UnLock(key_name, holder2); 96 | printf("6. TryLock status %s name %s holder %s\n", s.ToString().c_str(), key_name.c_str(), holder2.c_str()); 97 | 98 | 99 | // 7. test node with cluster recover 100 | s = Floyd::Open(op, &f1); 101 | s = Floyd::Open(op2, &f2); 102 | s = Floyd::Open(op3, &f3); 103 | while (1) { 104 | if (f1->HasLeader()) { 105 | break; 106 | } 107 | printf("electing leader... sleep 2s\n"); 108 | sleep(2); 109 | } 110 | s = f2->TryLock(key_name, holder, 1000); 111 | printf("7. test node with cluster recover\n"); 112 | printf("7. UnLock status %s name %s holder %s\n", s.ToString().c_str(), key_name.c_str(), holder2.c_str()); 113 | 114 | // 8. test lock expired 115 | 116 | printf("8. the lock is holded by %s, when time expired the lock should be success\n", holder.c_str()); 117 | sleep(10); 118 | s = f2->TryLock(key_name, holder, 1000); 119 | printf("8. sleep 10s, the trylock should be success\n"); 120 | printf("8. TryLock status %s name %s holder %s\n", s.ToString().c_str(), key_name.c_str(), holder2.c_str()); 121 | 122 | 123 | getchar(); 124 | delete f2; 125 | delete f3; 126 | delete f4; 127 | delete f5; 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /floyd/include/floyd.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_INCLUDE_FLOYD_H_ 7 | #define FLOYD_INCLUDE_FLOYD_H_ 8 | 9 | #include 10 | #include 11 | 12 | #include "floyd/include/floyd_options.h" 13 | #include "slash/include/slash_status.h" 14 | 15 | namespace floyd { 16 | 17 | using slash::Status; 18 | 19 | class Floyd { 20 | public: 21 | static Status Open(const Options& options, Floyd** floyd); 22 | 23 | Floyd() { } 24 | virtual ~Floyd(); 25 | 26 | virtual Status Write(const std::string& key, const std::string& value) = 0; 27 | virtual Status Delete(const std::string& key) = 0; 28 | virtual Status Read(const std::string& key, std::string* value) = 0; 29 | virtual Status DirtyRead(const std::string& key, std::string* value) = 0; 30 | // ttl is millisecond 31 | virtual Status TryLock(const std::string& name, const std::string& holder, uint64_t ttl) = 0; 32 | virtual Status UnLock(const std::string& name, const std::string& holder) = 0; 33 | 34 | // membership change interface 35 | virtual Status AddServer(const std::string& new_server) = 0; 36 | virtual Status RemoveServer(const std::string& out_server) = 0; 37 | 38 | // return true if leader has been elected 39 | virtual bool GetLeader(std::string* ip_port) = 0; 40 | virtual bool GetLeader(std::string* ip, int* port) = 0; 41 | virtual bool HasLeader() = 0; 42 | virtual bool IsLeader() = 0; 43 | virtual Status GetAllServers(std::set* nodes) = 0; 44 | 45 | // used for debug 46 | virtual bool GetServerStatus(std::string* msg) = 0; 47 | 48 | // log level can be modified 49 | virtual void set_log_level(const int log_level) = 0; 50 | 51 | private: 52 | // No coping allowed 53 | Floyd(const Floyd&); 54 | void operator=(const Floyd&); 55 | }; 56 | 57 | } // namespace floyd 58 | #endif // FLOYD_INCLUDE_FLOYD_H_ 59 | -------------------------------------------------------------------------------- /floyd/include/floyd_options.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_INCLUDE_FLOYD_OPTIONS_H_ 7 | #define FLOYD_INCLUDE_FLOYD_OPTIONS_H_ 8 | 9 | #include 10 | #include 11 | 12 | namespace floyd { 13 | 14 | // Logger Level 15 | enum { 16 | DEBUG_LEVEL = 0x01, 17 | INFO_LEVEL = 0x02, 18 | WARN_LEVEL = 0x03, 19 | ERROR_LEVEL = 0x04, 20 | FATAL_LEVEL = 0x05, 21 | NONE_LEVEL = 0x06 22 | }; 23 | 24 | struct Options { 25 | // cluster members 26 | // parsed from comma separated ip1:port1,ip2:port2... 27 | std::vector members; 28 | std::string local_ip; 29 | int local_port; 30 | std::string path; 31 | uint64_t check_leader_us; 32 | uint64_t heartbeat_us; 33 | uint64_t append_entries_size_once; 34 | uint64_t append_entries_count_once; 35 | bool single_mode; 36 | 37 | void SetMembers(const std::string& cluster_string); 38 | 39 | void Dump(); 40 | std::string ToString(); 41 | 42 | Options(); 43 | Options(const std::string& cluster_string, 44 | const std::string& _local_ip, int _local_port, 45 | const std::string& _path); 46 | }; 47 | 48 | } // namespace floyd 49 | #endif // FLOYD_INCLUDE_FLOYD_OPTIONS_H_ 50 | -------------------------------------------------------------------------------- /floyd/include/version.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. 7 | // This source code is licensed under the BSD-style license found in the 8 | // LICENSE file in the root directory of this source tree. An additional grant 9 | // of patent rights can be found in the PATENTS file in the same directory. 10 | #pragma once 11 | 12 | #define FLOYD_MAJOR 1 13 | #define FLOYD_MINOR 3 14 | #define FLOYD_PATCH 1 15 | -------------------------------------------------------------------------------- /floyd/proto/floyd.proto: -------------------------------------------------------------------------------- 1 | package floyd; 2 | 3 | /* 4 | * Entry is used storing data in raft log 5 | */ 6 | message Entry { 7 | enum OpType { 8 | kRead = 0; 9 | kWrite = 1; 10 | kDelete = 2; 11 | kTryLock= 4; 12 | kUnLock = 5; 13 | kAddServer = 6; 14 | kRemoveServer = 7; 15 | kGetAllServers = 8; 16 | } 17 | // used in key value operator 18 | optional uint64 term = 1; 19 | optional string key = 2; 20 | optional bytes value = 3; 21 | required OpType optype = 4; 22 | // used in lock and unlock 23 | optional bytes holder = 5; 24 | optional uint64 lease_end = 6; 25 | optional bytes server = 7; 26 | } 27 | 28 | // Raft RPC is the RPC presented in raft paper 29 | // User cmd RPC the cmd build upon the raft protocol 30 | 31 | enum Type { 32 | // User cmd 33 | kRead = 0; 34 | kWrite = 1; 35 | kDelete = 3; 36 | kTryLock = 5; 37 | kUnLock = 6; 38 | kAddServer = 11; 39 | kRemoveServer = 12; 40 | kGetAllServers = 13; 41 | 42 | // Raft RPC 43 | kRequestVote = 8; 44 | kAppendEntries = 9; 45 | kServerStatus = 10; 46 | } 47 | 48 | message CmdRequest { 49 | required Type type = 1; 50 | 51 | message RequestVote { 52 | required uint64 term = 1; 53 | required bytes ip = 2; 54 | required int32 port = 3; 55 | required uint64 last_log_index = 4; 56 | required uint64 last_log_term = 5; 57 | } 58 | optional RequestVote request_vote = 2; 59 | 60 | message AppendEntries { 61 | required uint64 term = 1; 62 | required bytes ip = 2; 63 | required int32 port = 3; 64 | required uint64 prev_log_index = 4; 65 | required uint64 prev_log_term = 5; 66 | required uint64 leader_commit = 6; 67 | repeated Entry entries = 7; 68 | } 69 | optional AppendEntries append_entries = 3; 70 | 71 | message KvRequest { 72 | required bytes key = 1; 73 | optional bytes value = 2; 74 | } 75 | optional KvRequest kv_request = 4; 76 | 77 | message LockRequest { 78 | required bytes name = 1; 79 | required bytes holder = 2; 80 | optional uint64 lease_end = 3; 81 | } 82 | optional LockRequest lock_request = 5; 83 | 84 | message AddServerRequest { 85 | required bytes new_server = 1; 86 | } 87 | optional AddServerRequest add_server_request = 7; 88 | 89 | message RemoveServerRequest { 90 | required bytes old_server = 1; 91 | } 92 | optional RemoveServerRequest remove_server_request = 8; 93 | 94 | message ServerStatus { 95 | required int64 term = 1; 96 | required int64 commit_index = 2; 97 | optional bytes ip = 3; 98 | optional int32 port = 4; 99 | } 100 | optional ServerStatus server_status = 6; 101 | } 102 | 103 | enum StatusCode { 104 | kOk = 0; 105 | kNotFound = 1; 106 | kError = 2; 107 | kLocked = 3; 108 | } 109 | 110 | message CmdResponse { 111 | required Type type = 1; 112 | optional StatusCode code = 2; 113 | 114 | message RequestVoteResponse { 115 | required uint64 term = 1; 116 | required bool vote_granted = 2; 117 | } 118 | optional RequestVoteResponse request_vote_res = 3; 119 | 120 | message AppendEntriesResponse { 121 | required uint64 term = 1; 122 | required bool success = 2; 123 | optional uint64 last_log_index = 3; 124 | } 125 | optional AppendEntriesResponse append_entries_res = 4; 126 | 127 | optional bytes msg = 5; 128 | 129 | message KvResponse { 130 | optional bytes value = 1; 131 | } 132 | optional KvResponse kv_response = 6; 133 | 134 | message ServerStatus { 135 | required uint64 term = 1; 136 | required uint64 commit_index = 2; 137 | required bytes role = 3; 138 | optional bytes leader_ip = 4; 139 | optional int32 leader_port = 5; 140 | optional bytes voted_for_ip = 6; 141 | optional int32 voted_for_port = 7; 142 | optional uint64 last_log_term = 8; 143 | optional uint64 last_log_index = 9; 144 | optional uint64 last_applied = 10; 145 | } 146 | optional ServerStatus server_status = 7; 147 | 148 | optional Membership all_servers = 8; 149 | } 150 | 151 | /* 152 | * protos used in lock API 153 | * Lock is used storing data in database 154 | * since the Lock should contain more than one variable as the value 155 | * so we need a struct to serialize the value 156 | */ 157 | message Lock { 158 | required bytes holder = 1; 159 | required uint64 lease_end = 2; 160 | } 161 | 162 | /* 163 | * protos used for membership 164 | * Membership record current membership config of floyd 165 | */ 166 | message Membership { 167 | repeated bytes nodes = 1; 168 | } 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /floyd/proto/pr.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -x 3 | 4 | protoc -I=./ --cpp_out=../src/ ./floyd.proto 5 | 6 | echo "run protoc success, go, go, go..."; 7 | -------------------------------------------------------------------------------- /floyd/src/build_version.cc.in: -------------------------------------------------------------------------------- 1 | #include "floyd/src/build_version.h" 2 | const char* floyd_build_git_sha = "floyd_build_git_sha:@@GIT_SHA@@"; 3 | const char* floyd_build_git_date = "floyd_build_git_date:@@GIT_DATE_TIME@@"; 4 | const char* floyd_build_compile_date = __DATE__; 5 | -------------------------------------------------------------------------------- /floyd/src/build_version.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | // 6 | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. 7 | // This source code is licensed under the BSD-style license found in the 8 | // LICENSE file in the root directory of this source tree. An additional grant 9 | // of patent rights can be found in the PATENTS file in the same directory. 10 | // 11 | #pragma once 12 | 13 | // this variable tells us about the git revision 14 | extern const char* floyd_build_git_sha; 15 | 16 | // Date on which the code was compiled: 17 | extern const char* floyd_build_compile_date; 18 | -------------------------------------------------------------------------------- /floyd/src/floyd_apply.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/src/floyd_apply.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "slash/include/xdebug.h" 14 | #include "slash/include/env.h" 15 | 16 | #include "floyd/src/logger.h" 17 | #include "floyd/src/floyd.pb.h" 18 | #include "floyd/src/raft_meta.h" 19 | #include "floyd/src/raft_log.h" 20 | #include "floyd/src/floyd_impl.h" 21 | 22 | namespace floyd { 23 | 24 | FloydApply::FloydApply(FloydContext* context, rocksdb::DB* db, RaftMeta* raft_meta, 25 | RaftLog* raft_log, FloydImpl* impl, Logger* info_log) 26 | : bg_thread_(1024 * 1024 * 1024), 27 | context_(context), 28 | db_(db), 29 | raft_meta_(raft_meta), 30 | raft_log_(raft_log), 31 | impl_(impl), 32 | info_log_(info_log) { 33 | } 34 | 35 | FloydApply::~FloydApply() { 36 | } 37 | 38 | int FloydApply::Start() { 39 | bg_thread_.set_thread_name("A:" + std::to_string(impl_->GetLocalPort())); 40 | bg_thread_.Schedule(ApplyStateMachineWrapper, this); 41 | return bg_thread_.StartThread(); 42 | } 43 | 44 | int FloydApply::Stop() { 45 | return bg_thread_.StopThread(); 46 | } 47 | 48 | void FloydApply::ScheduleApply() { 49 | /* 50 | * int timer_queue_size, queue_size; 51 | * bg_thread_.QueueSize(&timer_queue_size, &queue_size); 52 | * LOGV(INFO_LEVEL, info_log_, "Peer::AddRequestVoteTask timer_queue size %d queue_size %d", 53 | * timer_queue_size, queue_size); 54 | */ 55 | bg_thread_.Schedule(&ApplyStateMachineWrapper, this); 56 | } 57 | 58 | void FloydApply::ApplyStateMachineWrapper(void* arg) { 59 | reinterpret_cast(arg)->ApplyStateMachine(); 60 | } 61 | 62 | void FloydApply::ApplyStateMachine() { 63 | uint64_t last_applied = context_->last_applied; 64 | // Apply as more entry as possible 65 | uint64_t commit_index; 66 | commit_index = context_->commit_index; 67 | 68 | LOGV(DEBUG_LEVEL, info_log_, "FloydApply::ApplyStateMachine: last_applied: %lu, commit_index: %lu", 69 | last_applied, commit_index); 70 | Entry log_entry; 71 | if (last_applied >= commit_index) { 72 | return; 73 | } 74 | // TODO: use batch commit to optimization 75 | while (last_applied < commit_index) { 76 | last_applied++; 77 | raft_log_->GetEntry(last_applied, &log_entry); 78 | // TODO: we need change the s type 79 | // since the Apply may not operate rocksdb 80 | rocksdb::Status s = Apply(log_entry); 81 | if (!s.ok()) { 82 | LOGV(WARN_LEVEL, info_log_, "FloydApply::ApplyStateMachine: Apply log entry failed, at: %d, error: %s", 83 | last_applied, s.ToString().c_str()); 84 | usleep(1000000); 85 | ScheduleApply(); // try once more 86 | return; 87 | } 88 | } 89 | context_->apply_mu.Lock(); 90 | context_->last_applied = last_applied; 91 | raft_meta_->SetLastApplied(last_applied); 92 | context_->apply_mu.Unlock(); 93 | context_->apply_cond.SignalAll(); 94 | } 95 | 96 | rocksdb::Status FloydApply::Apply(const Entry& entry) { 97 | rocksdb::Status ret; 98 | Lock lock; 99 | std::string val; 100 | // be careful: 101 | // we need to return the ret carefully 102 | // the FloydApply::ApplyStateMachine need use the ret to judge 103 | // whether consume this successfully 104 | switch (entry.optype()) { 105 | case Entry_OpType_kWrite: 106 | ret = db_->Put(rocksdb::WriteOptions(), entry.key(), entry.value()); 107 | LOGV(DEBUG_LEVEL, info_log_, "FloydApply::Apply %s, key(%s)", 108 | ret.ToString().c_str(), entry.key().c_str()); 109 | break; 110 | case Entry_OpType_kDelete: 111 | ret = db_->Delete(rocksdb::WriteOptions(), entry.key()); 112 | break; 113 | case Entry_OpType_kRead: 114 | ret = rocksdb::Status::OK(); 115 | break; 116 | case Entry_OpType_kTryLock: 117 | ret = db_->Get(rocksdb::ReadOptions(), entry.key(), &val); 118 | if (ret.ok()) { 119 | lock.ParseFromString(val); 120 | if (lock.lease_end() < slash::NowMicros()) { 121 | LOGV(INFO_LEVEL, info_log_, "FloydApply::Apply Trylock Success, name %s holder %s, " 122 | "but the lock has been locked by %s, and right now it is timeout", 123 | entry.key().c_str(), entry.holder().c_str(), lock.holder().c_str()); 124 | lock.set_holder(entry.holder()); 125 | lock.set_lease_end(entry.lease_end()); 126 | lock.SerializeToString(&val); 127 | ret = db_->Put(rocksdb::WriteOptions(), entry.key(), val); 128 | } else { 129 | ret = rocksdb::Status::OK(); 130 | } 131 | } else if (ret.IsNotFound()) { 132 | lock.set_holder(entry.holder()); 133 | lock.set_lease_end(entry.lease_end()); 134 | lock.SerializeToString(&val); 135 | ret = db_->Put(rocksdb::WriteOptions(), entry.key(), val); 136 | } else { 137 | LOGV(WARN_LEVEL, info_log_, "FloydImpl::Apply Trylock Error operate db error, name %s holder %s", 138 | entry.key().c_str(), entry.holder().c_str()); 139 | } 140 | break; 141 | case Entry_OpType_kUnLock: 142 | ret = db_->Get(rocksdb::ReadOptions(), entry.key(), &val); 143 | if (ret.ok()) { 144 | lock.ParseFromString(val); 145 | if (lock.holder() != entry.holder()) { 146 | LOGV(INFO_LEVEL, info_log_, "FloydApply::Apply Warning UnLock an lock holded by other, name %s holder %s, origin holder %s", 147 | entry.key().c_str(), entry.holder().c_str(), lock.holder().c_str()); 148 | } else if (lock.lease_end() < slash::NowMicros()) { 149 | LOGV(INFO_LEVEL, info_log_, "FloydImpl::Apply UnLock an lock which is expired, name %s holder %s", 150 | entry.key().c_str(), entry.holder().c_str(), lock.holder().c_str()); 151 | } else { 152 | ret = db_->Delete(rocksdb::WriteOptions(), entry.key()); 153 | } 154 | } else if (ret.IsNotFound()) { 155 | LOGV(INFO_LEVEL, info_log_, "FloydApply::Apply Warning UnLock an dosen't exist lock, name %s holder %s", 156 | entry.key().c_str(), entry.holder().c_str()); 157 | ret = rocksdb::Status::OK(); 158 | } else { 159 | LOGV(WARN_LEVEL, info_log_, "FloydApply::Apply UnLock Error, operate db error, name %s holder %s", 160 | entry.key().c_str(), entry.holder().c_str()); 161 | } 162 | break; 163 | case Entry_OpType_kAddServer: 164 | ret = MembershipChange(entry.server(), true); 165 | if (ret.ok()) { 166 | context_->members.insert(entry.server()); 167 | impl_->AddNewPeer(entry.server()); 168 | } 169 | LOGV(INFO_LEVEL, info_log_, "FloydApply::Apply Add server %s to cluster", 170 | entry.server().c_str()); 171 | break; 172 | case Entry_OpType_kRemoveServer: 173 | ret = MembershipChange(entry.server(), false); 174 | if (ret.ok()) { 175 | context_->members.erase(entry.server()); 176 | impl_->RemoveOutPeer(entry.server()); 177 | } 178 | LOGV(INFO_LEVEL, info_log_, "FloydApply::Apply Remove server %s to cluster", 179 | entry.server().c_str()); 180 | break; 181 | case Entry_OpType_kGetAllServers: 182 | ret = rocksdb::Status::OK(); 183 | break; 184 | default: 185 | ret = rocksdb::Status::Corruption("Unknown entry type"); 186 | } 187 | return ret; 188 | } 189 | 190 | rocksdb::Status FloydApply::MembershipChange(const std::string& ip_port, 191 | bool add) { 192 | std::string value; 193 | Membership members; 194 | rocksdb::Status ret = db_->Get(rocksdb::ReadOptions(), 195 | kMemberConfigKey, &value); 196 | if (!ret.ok()) { 197 | return ret; 198 | } 199 | 200 | if(!members.ParseFromString(value)) { 201 | return rocksdb::Status::Corruption("Parse failed"); 202 | } 203 | int count = members.nodes_size(); 204 | for (int i = 0; i < count; i++) { 205 | if (members.nodes(i) == ip_port) { 206 | if (add) { 207 | return rocksdb::Status::OK(); // Already in 208 | } 209 | // Remove Server 210 | if (i != count - 1) { 211 | std::string *nptr = members.mutable_nodes(i); 212 | *nptr = members.nodes(count - 1); 213 | } 214 | members.mutable_nodes()->RemoveLast(); 215 | } 216 | } 217 | 218 | if (add) { 219 | members.add_nodes(ip_port); 220 | } 221 | 222 | if (!members.SerializeToString(&value)) { 223 | return rocksdb::Status::Corruption("Serialize failed"); 224 | } 225 | return db_->Put(rocksdb::WriteOptions(), kMemberConfigKey, value); 226 | } 227 | 228 | } // namespace floyd 229 | -------------------------------------------------------------------------------- /floyd/src/floyd_apply.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_FLOYD_APPLY_H_ 7 | #define FLOYD_SRC_FLOYD_APPLY_H_ 8 | 9 | #include "floyd/src/floyd_context.h" 10 | 11 | #include "slash/include/slash_status.h" 12 | #include "pink/include/bg_thread.h" 13 | 14 | namespace floyd { 15 | 16 | using slash::Status; 17 | 18 | class RaftMeta; 19 | class RaftLog; 20 | class Logger; 21 | class FloydImpl; 22 | 23 | class FloydApply { 24 | public: 25 | FloydApply(FloydContext* context, rocksdb::DB* db, RaftMeta* raft_meta, 26 | RaftLog* raft_log, FloydImpl* impl_, Logger* info_log); 27 | virtual ~FloydApply(); 28 | int Start(); 29 | int Stop(); 30 | void ScheduleApply(); 31 | 32 | private: 33 | pink::BGThread bg_thread_; 34 | FloydContext* const context_; 35 | rocksdb::DB* const db_; 36 | /* 37 | * we will store the increasing id in raft_meta_ 38 | */ 39 | RaftMeta* const raft_meta_; 40 | RaftLog* const raft_log_; 41 | FloydImpl* const impl_; 42 | Logger* const info_log_; 43 | static void ApplyStateMachineWrapper(void* arg); 44 | void ApplyStateMachine(); 45 | rocksdb::Status Apply(const Entry& log_entry); 46 | rocksdb::Status MembershipChange(const std::string& ip_port, bool add); 47 | 48 | 49 | FloydApply(const FloydApply&); 50 | void operator=(const FloydApply&); 51 | }; 52 | 53 | } // namespace floyd 54 | 55 | #endif // FLOYD_SRC_FLOYD_APPLY_H_ 56 | -------------------------------------------------------------------------------- /floyd/src/floyd_client_pool.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/src/floyd_client_pool.h" 7 | 8 | #include 9 | #include "floyd/src/logger.h" 10 | #include "floyd/include/floyd_options.h" 11 | 12 | #include "slash/include/slash_string.h" 13 | 14 | namespace floyd { 15 | 16 | static std::string CmdType(const CmdRequest& cmd) { 17 | std::string ret; 18 | switch (cmd.type()) { 19 | case Type::kRead: 20 | ret = "Read"; 21 | break; 22 | case Type::kWrite: 23 | ret = "Write"; 24 | break; 25 | case Type::kDelete: 26 | ret = "Delete"; 27 | break; 28 | case Type::kTryLock: 29 | ret = "TryLock"; 30 | break; 31 | case Type::kUnLock: 32 | ret = "UnLock"; 33 | break; 34 | case Type::kRequestVote: 35 | ret = "RequestVote"; 36 | break; 37 | case Type::kAppendEntries: 38 | ret = "AppendEntries"; 39 | break; 40 | case Type::kServerStatus: 41 | ret = "ServerStatus"; 42 | break; 43 | default: 44 | ret = "UnknownCmd"; 45 | } 46 | return ret; 47 | } 48 | 49 | 50 | ClientPool::ClientPool(Logger* info_log, int timeout_ms, int retry) 51 | : info_log_(info_log), 52 | timeout_ms_(timeout_ms), 53 | retry_(retry) { 54 | } 55 | 56 | // sleep 1 second after each send message 57 | Status ClientPool::SendAndRecv(const std::string& server, const CmdRequest& req, CmdResponse* res) { 58 | /* 59 | * if (req.type() == kAppendEntries) { 60 | * LOGV(INFO_LEVEL, info_log_, "ClientPool::SendAndRecv to %s" 61 | * " Request type %s prev_log_index %lu prev_log_term %lu leader_commit %lu " 62 | * "append entries size %d at term %d", server.c_str(), 63 | * CmdType(req).c_str(), req.append_entries().prev_log_index(), req.append_entries().prev_log_term(), 64 | * req.append_entries().leader_commit(), req.append_entries().entries().size(), req.append_entries().term()); 65 | * } 66 | */ 67 | LOGV(DEBUG_LEVEL, info_log_, "ClientPool::SendAndRecv Send %s command to server %s", CmdType(req).c_str(), server.c_str()); 68 | Client *client = GetClient(server); 69 | pink::PinkCli* cli = client->cli; 70 | 71 | Status ret = Status::Incomplete("Not send"); 72 | slash::MutexLock l(&client->mu); 73 | ret = UpHoldCli(client); 74 | if (!ret.ok()) { 75 | if (req.type() == kAppendEntries) { 76 | LOGV(WARN_LEVEL, info_log_, "ClientPool::SendAndRecv Server Connect to %s failed, error reason: %s" 77 | " Request type %s prev_log_index %lu prev_log_term %lu leader_commit %lu " 78 | "append entries size %d at term %d", server.c_str(), ret.ToString().c_str(), 79 | CmdType(req).c_str(), req.append_entries().prev_log_index(), req.append_entries().prev_log_term(), 80 | req.append_entries().leader_commit(), req.append_entries().entries().size(), req.append_entries().term()); 81 | } else { 82 | LOGV(WARN_LEVEL, info_log_, "ClientPool::SendAndRecv Server Connect to %s failed, error reason: %s" 83 | " Request type %s", server.c_str(), ret.ToString().c_str(), CmdType(req).c_str()); 84 | sleep(1); 85 | } 86 | cli->Close(); 87 | return ret; 88 | } 89 | 90 | ret = cli->Send((void *)(&req)); 91 | if (!ret.ok()) { 92 | if (req.type() == kAppendEntries) { 93 | LOGV(WARN_LEVEL, info_log_, "ClientPool::SendAndRecv Server Send to %s failed, error reason: %s" 94 | " Request type %s prev_log_index %lu prev_log_term %lu leader_commit %lu " 95 | "append entries size %d at term %d", server.c_str(), ret.ToString().c_str(), 96 | CmdType(req).c_str(), req.append_entries().prev_log_index(), req.append_entries().prev_log_term(), 97 | req.append_entries().leader_commit(), req.append_entries().entries().size(), req.append_entries().term()); 98 | } else { 99 | LOGV(WARN_LEVEL, info_log_, "ClientPool::SendAndRecv Server Send to %s failed, error reason: %s" 100 | " Request type %s", server.c_str(), ret.ToString().c_str(), CmdType(req).c_str()); 101 | sleep(1); 102 | } 103 | cli->Close(); 104 | return ret; 105 | } 106 | 107 | ret = cli->Recv(res); 108 | if (!ret.ok()) { 109 | if (req.type() == kAppendEntries) { 110 | LOGV(WARN_LEVEL, info_log_, "ClientPool::SendAndRecv Server Recv to %s failed, error reason: %s" 111 | " Request type %s prev_log_index %lu prev_log_term %lu leader_commit %lu " 112 | "append entries size %d at term %d", server.c_str(), ret.ToString().c_str(), 113 | CmdType(req).c_str(), req.append_entries().prev_log_index(), req.append_entries().prev_log_term(), 114 | req.append_entries().leader_commit(), req.append_entries().entries().size(), req.append_entries().term()); 115 | } else { 116 | LOGV(WARN_LEVEL, info_log_, "ClientPool::SendAndRecv Server Recv to %s failed, error reason: %s" 117 | " Request type %s", server.c_str(), ret.ToString().c_str(), CmdType(req).c_str()); 118 | sleep(1); 119 | } 120 | cli->Close(); 121 | return ret; 122 | } 123 | if (ret.ok()) { 124 | if (res->code() == StatusCode::kOk || res->code() == StatusCode::kNotFound) { 125 | return Status::OK(); 126 | } 127 | } 128 | return ret; 129 | } 130 | 131 | ClientPool::~ClientPool() { 132 | slash::MutexLock l(&mu_); 133 | for (auto& iter : client_map_) { 134 | delete iter.second; 135 | } 136 | LOGV(DEBUG_LEVEL, info_log_, "ClientPool dtor"); 137 | } 138 | 139 | Client* ClientPool::GetClient(const std::string& server) { 140 | slash::MutexLock l(&mu_); 141 | auto iter = client_map_.find(server); 142 | if (iter == client_map_.end()) { 143 | std::string ip; 144 | int port; 145 | slash::ParseIpPortString(server, ip, port); 146 | Client* client = new Client(ip, port); 147 | client_map_[server] = client; 148 | return client; 149 | } else { 150 | return iter->second; 151 | } 152 | } 153 | 154 | Status ClientPool::UpHoldCli(Client *client) { 155 | if (client == NULL || client->cli == NULL) { 156 | return Status::Corruption("null PinkCli"); 157 | } 158 | 159 | Status ret; 160 | pink::PinkCli* cli = client->cli; 161 | if (!cli->Available()) { 162 | ret = cli->Connect(); 163 | if (ret.ok()) { 164 | cli->set_send_timeout(timeout_ms_); 165 | cli->set_recv_timeout(timeout_ms_); 166 | } 167 | } 168 | return ret; 169 | } 170 | 171 | } // namespace floyd 172 | -------------------------------------------------------------------------------- /floyd/src/floyd_client_pool.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_FLOYD_CLIENT_POOL_H_ 7 | #define FLOYD_SRC_FLOYD_CLIENT_POOL_H_ 8 | 9 | #include "floyd/src/floyd.pb.h" 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "pink/include/pink_cli.h" 16 | #include "slash/include/slash_status.h" 17 | #include "slash/include/slash_mutex.h" 18 | 19 | namespace floyd { 20 | 21 | using slash::Status; 22 | 23 | class Logger; 24 | 25 | struct Client { 26 | pink::PinkCli* cli; 27 | slash::Mutex mu; 28 | 29 | Client(const std::string& ip, int port) { 30 | cli = pink::NewPbCli(ip, port); 31 | } 32 | }; 33 | class ClientPool { 34 | public: 35 | explicit ClientPool(Logger* info_log_, int timeout_ms = 2000, int retry = 0); 36 | ~ClientPool(); 37 | 38 | // Each try consists of Connect, Send and Recv; 39 | Status SendAndRecv(const std::string& server, const CmdRequest& req, 40 | CmdResponse* res); 41 | 42 | Status UpHoldCli(Client* client); 43 | 44 | private: 45 | Logger* const info_log_; 46 | int timeout_ms_; 47 | int retry_; 48 | slash::Mutex mu_; 49 | std::map client_map_; 50 | 51 | Client* GetClient(const std::string& server); 52 | 53 | ClientPool(const ClientPool&); 54 | bool operator=(const ClientPool&); 55 | }; 56 | 57 | 58 | } // namespace floyd 59 | #endif // FLOYD_SRC_FLOYD_CLIENT_POOL_H_ 60 | -------------------------------------------------------------------------------- /floyd/src/floyd_context.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/src/floyd_context.h" 7 | 8 | #include 9 | 10 | #include "slash/include/env.h" 11 | #include "slash/include/xdebug.h" 12 | 13 | #include "floyd/src/floyd.pb.h" 14 | #include "floyd/src/logger.h" 15 | #include "floyd/src/raft_meta.h" 16 | 17 | namespace floyd { 18 | 19 | void FloydContext::RecoverInit(RaftMeta *raft_meta) { 20 | current_term = raft_meta->GetCurrentTerm(); 21 | voted_for_ip = raft_meta->GetVotedForIp(); 22 | voted_for_port = raft_meta->GetVotedForPort(); 23 | commit_index = raft_meta->GetCommitIndex(); 24 | last_applied = raft_meta->GetLastApplied(); 25 | role = Role::kFollower; 26 | } 27 | 28 | void FloydContext::BecomeFollower(uint64_t new_term, 29 | const std::string _leader_ip, int _leader_port) { 30 | current_term = new_term; 31 | leader_ip = _leader_ip; 32 | leader_port = _leader_port; 33 | role = Role::kFollower; 34 | } 35 | 36 | void FloydContext::BecomeCandidate() { 37 | current_term++; 38 | role = Role::kCandidate; 39 | leader_ip.clear(); 40 | leader_port = 0; 41 | voted_for_ip = options.local_ip; 42 | voted_for_port = options.local_port; 43 | vote_quorum = 1; 44 | } 45 | 46 | void FloydContext::BecomeLeader() { 47 | role = Role::kLeader; 48 | leader_ip = options.local_ip; 49 | leader_port = options.local_port; 50 | } 51 | } // namespace floyd 52 | -------------------------------------------------------------------------------- /floyd/src/floyd_context.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_FLOYD_CONTEXT_H_ 7 | #define FLOYD_SRC_FLOYD_CONTEXT_H_ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "floyd/include/floyd_options.h" 15 | #include "floyd/src/raft_log.h" 16 | 17 | #include "slash/include/slash_status.h" 18 | #include "slash/include/slash_mutex.h" 19 | 20 | namespace floyd { 21 | 22 | using slash::Status; 23 | 24 | enum Role { 25 | kFollower = 0, 26 | kCandidate = 1, 27 | kLeader = 2, 28 | }; 29 | 30 | class RaftMeta; 31 | /* 32 | * we use FloydContext to avoid passing the floyd_impl's this point to other thread 33 | */ 34 | struct FloydContext { 35 | // Role related 36 | explicit FloydContext(const Options& _options) 37 | : options(_options), 38 | voted_for_ip(""), 39 | voted_for_port(0), 40 | leader_ip(""), 41 | leader_port(0), 42 | vote_quorum(0), 43 | commit_index(0), 44 | last_applied(0), 45 | last_op_time(0), 46 | apply_cond(&apply_mu) {} 47 | 48 | void RecoverInit(RaftMeta *raft); 49 | void BecomeFollower(uint64_t new_iterm, 50 | const std::string leader_ip = "", int port = 0); 51 | void BecomeCandidate(); 52 | void BecomeLeader(); 53 | 54 | Options options; 55 | // Role related 56 | uint64_t current_term; 57 | 58 | Role role; 59 | std::string voted_for_ip; 60 | int voted_for_port; 61 | std::string leader_ip; 62 | int leader_port; 63 | uint32_t vote_quorum; 64 | 65 | uint64_t commit_index; 66 | std::atomic last_applied; 67 | uint64_t last_op_time; 68 | 69 | std::set members; 70 | 71 | // mutex protect commit_index 72 | // used in floyd_apply thread and floyd_peer thread 73 | slash::Mutex global_mu; 74 | slash::Mutex apply_mu; 75 | slash::CondVar apply_cond; 76 | }; 77 | 78 | } // namespace floyd 79 | #endif // FLOYD_SRC_FLOYD_CONTEXT_H_ 80 | -------------------------------------------------------------------------------- /floyd/src/floyd_impl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_FLOYD_IMPL_H_ 7 | #define FLOYD_SRC_FLOYD_IMPL_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "slash/include/slash_mutex.h" 15 | #include "slash/include/slash_status.h" 16 | #include "pink/include/bg_thread.h" 17 | 18 | #include "floyd/include/floyd.h" 19 | #include "floyd/include/floyd_options.h" 20 | #include "floyd/src/raft_log.h" 21 | 22 | namespace floyd { 23 | using slash::Status; 24 | 25 | class Log; 26 | class ClientPool; 27 | class RaftMeta; 28 | class Peer; 29 | class FloydPrimary; 30 | class FloydApply; 31 | class FloydWorker; 32 | class FloydWorkerConn; 33 | class FloydContext; 34 | class Logger; 35 | class CmdRequest; 36 | class CmdResponse; 37 | class CmdResponse_ServerStatus; 38 | 39 | typedef std::map PeersSet; 40 | 41 | static const std::string kMemberConfigKey = "#MEMBERCONFIG"; 42 | 43 | class FloydImpl : public Floyd { 44 | public: 45 | explicit FloydImpl(const Options& options); 46 | virtual ~FloydImpl(); 47 | 48 | Status Init(); 49 | 50 | virtual Status Write(const std::string& key, const std::string& value); 51 | virtual Status Delete(const std::string& key); 52 | virtual Status Read(const std::string& key, std::string* value); 53 | virtual Status DirtyRead(const std::string& key, std::string* value); 54 | // ttl is millisecond 55 | virtual Status TryLock(const std::string& name, const std::string& holder, uint64_t ttl) override; 56 | virtual Status UnLock(const std::string& name, const std::string& holder) override; 57 | 58 | // membership change interface 59 | virtual Status AddServer(const std::string& new_server) override; 60 | virtual Status RemoveServer(const std::string& out_server) override; 61 | virtual Status GetAllServers(std::set* nodes) override; 62 | 63 | // return true if leader has been elected 64 | virtual bool GetLeader(std::string* ip_port) override; 65 | virtual bool GetLeader(std::string* ip, int* port) override; 66 | virtual bool HasLeader() override; 67 | virtual bool IsLeader() override; 68 | 69 | int GetLocalPort() { 70 | return options_.local_port; 71 | } 72 | 73 | virtual bool GetServerStatus(std::string* msg); 74 | // log level can be modified 75 | void set_log_level(const int log_level); 76 | // used when membership changed 77 | void AddNewPeer(const std::string& server); 78 | void RemoveOutPeer(const std::string& server); 79 | 80 | private: 81 | // friend class Floyd; 82 | friend class FloydWorkerConn; 83 | friend class FloydWorkerHandle; 84 | friend class Peer; 85 | 86 | rocksdb::DB* db_; 87 | // state machine db point 88 | // raft log 89 | rocksdb::DB* log_and_meta_; // used to store logs and meta data 90 | RaftLog* raft_log_; 91 | RaftMeta* raft_meta_; 92 | 93 | Options options_; 94 | // debug log used for ouput to file 95 | Logger* info_log_; 96 | 97 | FloydContext* context_; 98 | 99 | FloydWorker* worker_; 100 | FloydApply* apply_; 101 | FloydPrimary* primary_; 102 | PeersSet peers_; 103 | ClientPool* worker_client_pool_; 104 | 105 | bool IsSelf(const std::string& ip_port); 106 | 107 | Status DoCommand(const CmdRequest& cmd, CmdResponse *cmd_res); 108 | Status ExecuteCommand(const CmdRequest& cmd, CmdResponse *cmd_res); 109 | bool DoGetServerStatus(CmdResponse_ServerStatus* res); 110 | 111 | /* 112 | * these two are the response to the request vote and appendentries 113 | */ 114 | int ReplyRequestVote(const CmdRequest& cmd, CmdResponse* cmd_res); 115 | int ReplyAppendEntries(const CmdRequest& cmd, CmdResponse* cmd_res); 116 | 117 | bool AdvanceFollowerCommitIndex(uint64_t new_commit_index); 118 | 119 | int InitPeers(); 120 | 121 | // No coping allowed 122 | FloydImpl(const FloydImpl&); 123 | void operator=(const FloydImpl&); 124 | }; // FloydImpl 125 | 126 | } // namespace floyd 127 | #endif // FLOYD_SRC_FLOYD_IMPL_H_ 128 | -------------------------------------------------------------------------------- /floyd/src/floyd_options.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/include/floyd_options.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "slash/include/env.h" 12 | 13 | namespace floyd { 14 | 15 | static void split(const std::string &str, char delim, 16 | std::vector *tokens) { 17 | tokens->clear(); 18 | size_t prev_pos = str.find_first_not_of(delim, 0); 19 | size_t pos = str.find(delim, prev_pos); 20 | 21 | while (prev_pos != std::string::npos || pos != std::string::npos) { 22 | std::string token(str.substr(prev_pos, pos - prev_pos)); 23 | tokens->push_back(token); 24 | 25 | prev_pos = str.find_first_not_of(delim, pos); 26 | pos = str.find_first_of(delim, prev_pos); 27 | } 28 | } 29 | 30 | void Options::SetMembers(const std::string& cluster_string) { 31 | split(cluster_string, ',', &members); 32 | if (members.size() == 1) { 33 | single_mode = true; 34 | } 35 | } 36 | 37 | void Options::Dump() { 38 | for (size_t i = 0; i < members.size(); i++) { 39 | printf(" member %lu : %s\n", i, members[i].c_str()); 40 | } 41 | printf(" local_ip : %s\n" 42 | " local_port : %d\n" 43 | " path : %s\n" 44 | " check_leader_us : %ld\n" 45 | " heartbeat_us : %ld\n" 46 | " append_entries_size_once : %ld\n" 47 | "append_entries_count_once : %lu\n" 48 | " single_mode : %s\n", 49 | local_ip.c_str(), 50 | local_port, 51 | path.c_str(), 52 | check_leader_us, 53 | heartbeat_us, 54 | append_entries_size_once, 55 | append_entries_count_once, 56 | single_mode ? "true" : "false"); 57 | } 58 | 59 | std::string Options::ToString() { 60 | char str[1024]; 61 | int len = 0; 62 | for (size_t i = 0; i < members.size(); i++) { 63 | len += snprintf(str + len, sizeof(str), " member %lu : %s\n", i, members[i].c_str()); 64 | } 65 | snprintf(str + len, sizeof(str), " local_ip : %s\n" 66 | " local_port : %d\n" 67 | " path : %s\n" 68 | " check_leader_us : %ld\n" 69 | " heartbeat_us : %ld\n" 70 | " append_entries_size_once : %ld\n" 71 | "append_entries_count_once : %lu\n" 72 | " single_mode : %s\n", 73 | local_ip.c_str(), 74 | local_port, 75 | path.c_str(), 76 | check_leader_us, 77 | heartbeat_us, 78 | append_entries_size_once, 79 | append_entries_count_once, 80 | single_mode ? "true" : "false"); 81 | return str; 82 | } 83 | 84 | Options::Options() 85 | : local_ip("127.0.0.1"), 86 | local_port(10086), 87 | path("/data/floyd"), 88 | check_leader_us(6000000), 89 | heartbeat_us(3000000), 90 | append_entries_size_once(1048576), // 1MB 91 | append_entries_count_once(3500), 92 | single_mode(false) { 93 | } 94 | 95 | Options::Options(const std::string& cluster_string, 96 | const std::string& _local_ip, int _local_port, 97 | const std::string& _path) 98 | : local_ip(_local_ip), 99 | local_port(_local_port), 100 | path(_path), 101 | check_leader_us(6000000), 102 | heartbeat_us(3000000), 103 | append_entries_size_once(1048576), // 1MB 104 | append_entries_count_once(3500), 105 | single_mode(false) { 106 | std::srand(slash::NowMicros()); 107 | // the default check_leader is [3s, 5s) 108 | // the default heartbeat time is 1s 109 | // we can promise 1s + 2 * rpc < 3s, since rpc time is approximately 10ms 110 | check_leader_us = std::rand() % 2000000 + check_leader_us; 111 | split(cluster_string, ',', &members); 112 | if (members.size() == 1) { 113 | single_mode = true; 114 | } 115 | } 116 | 117 | } // namespace floyd 118 | -------------------------------------------------------------------------------- /floyd/src/floyd_peer_thread.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_FLOYD_PEER_THREAD_H_ 7 | #define FLOYD_SRC_FLOYD_PEER_THREAD_H_ 8 | 9 | #include 10 | #include 11 | 12 | #include "slash/include/slash_status.h" 13 | #include "pink/include/bg_thread.h" 14 | 15 | #include "floyd/src/floyd_context.h" 16 | 17 | namespace floyd { 18 | 19 | using slash::Status; 20 | 21 | class RaftMeta; 22 | class FloydPrimary; 23 | class RaftLog; 24 | class ClientPool; 25 | class FloydApply; 26 | class Peer; 27 | typedef std::map PeersSet; 28 | 29 | class Peer { 30 | public: 31 | Peer(std::string server, PeersSet *peers, FloydContext* context, FloydPrimary* primary, RaftMeta* raft_meta, 32 | RaftLog* raft_log, ClientPool* pool, FloydApply* apply, const Options& options, Logger* info_log); 33 | ~Peer(); 34 | 35 | int Start(); 36 | int Stop(); 37 | 38 | // Apend Entries 39 | // call by other thread, put job to peer_thread's bg_thread_ 40 | void AddAppendEntriesTask(); 41 | void AddRequestVoteTask(); 42 | 43 | /* 44 | * the two main RPC call in raft consensus protocol is here 45 | * AppendEntriesRPC 46 | * RequestVoteRPC 47 | * the response to these two RPC at floyd_impl.h 48 | */ 49 | static void AppendEntriesRPCWrapper(void *arg); 50 | void AppendEntriesRPC(); 51 | // Request Vote 52 | static void RequestVoteRPCWrapper(void *arg); 53 | void RequestVoteRPC(); 54 | 55 | uint64_t GetMatchIndex(); 56 | 57 | void set_next_index(const uint64_t next_index) { 58 | next_index_ = next_index; 59 | } 60 | uint64_t next_index() { 61 | return next_index_; 62 | } 63 | 64 | void set_match_index(const uint64_t match_index) { 65 | match_index_ = match_index; 66 | } 67 | uint64_t match_index() { 68 | return match_index_; 69 | } 70 | 71 | std::string peer_addr() const { 72 | return peer_addr_; 73 | } 74 | 75 | private: 76 | bool CheckAndVote(uint64_t vote_term); 77 | uint64_t QuorumMatchIndex(); 78 | void AdvanceLeaderCommitIndex(); 79 | void UpdatePeerInfo(); 80 | 81 | std::string peer_addr_; 82 | PeersSet* const peers_; 83 | FloydContext* const context_; 84 | FloydPrimary* const primary_; 85 | RaftMeta* const raft_meta_; 86 | RaftLog* const raft_log_; 87 | ClientPool* const pool_; 88 | FloydApply* const apply_; 89 | Options options_; 90 | Logger* const info_log_; 91 | 92 | 93 | std::atomic next_index_; 94 | std::atomic match_index_; 95 | uint64_t peer_last_op_time; 96 | 97 | pink::BGThread bg_thread_; 98 | 99 | // No copying allowed 100 | Peer(const Peer&); 101 | void operator=(const Peer&); 102 | }; 103 | 104 | } // namespace floyd 105 | #endif // FLOYD_SRC_FLOYD_PEER_THREAD_H_ 106 | -------------------------------------------------------------------------------- /floyd/src/floyd_primary_thread.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/src/floyd_primary_thread.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "slash/include/env.h" 17 | #include "slash/include/slash_mutex.h" 18 | 19 | #include "floyd/src/floyd_peer_thread.h" 20 | #include "floyd/src/floyd_apply.h" 21 | #include "floyd/src/floyd_context.h" 22 | #include "floyd/src/floyd_client_pool.h" 23 | #include "floyd/src/raft_meta.h" 24 | #include "floyd/src/floyd.pb.h" 25 | #include "floyd/src/logger.h" 26 | #include "floyd/include/floyd_options.h" 27 | 28 | namespace floyd { 29 | 30 | FloydPrimary::FloydPrimary(FloydContext* context, PeersSet* peers, RaftMeta* raft_meta, 31 | const Options& options, Logger* info_log) 32 | : context_(context), 33 | peers_(peers), 34 | raft_meta_(raft_meta), 35 | options_(options), 36 | info_log_(info_log) { 37 | } 38 | 39 | int FloydPrimary::Start() { 40 | bg_thread_.set_thread_name("R:" + std::to_string(options_.local_port)); 41 | return bg_thread_.StartThread(); 42 | } 43 | 44 | FloydPrimary::~FloydPrimary() { 45 | LOGV(INFO_LEVEL, info_log_, "FloydPrimary::~FloydPrimary Primary thread exit"); 46 | } 47 | 48 | int FloydPrimary::Stop() { 49 | return bg_thread_.StopThread(); 50 | } 51 | 52 | void FloydPrimary::AddTask(TaskType type, bool is_delay) { 53 | /* 54 | * int timer_queue_size, queue_size; 55 | * bg_thread_.QueueSize(&timer_queue_size, &queue_size); 56 | * LOGV(INFO_LEVEL, info_log_, "FloydPrimary::AddTask timer_queue size %d queue_size %d tasktype %d is_delay %d", 57 | * timer_queue_size, queue_size, type, is_delay); 58 | */ 59 | switch (type) { 60 | case kHeartBeat: 61 | if (is_delay) { 62 | uint64_t timeout = options_.heartbeat_us; 63 | bg_thread_.DelaySchedule(timeout / 1000LL, LaunchHeartBeatWrapper, this); 64 | } else { 65 | bg_thread_.Schedule(LaunchHeartBeatWrapper, this); 66 | } 67 | break; 68 | case kCheckLeader: 69 | if (is_delay) { 70 | uint64_t timeout = options_.check_leader_us; 71 | bg_thread_.DelaySchedule(timeout / 1000LL, LaunchCheckLeaderWrapper, this); 72 | } else { 73 | bg_thread_.Schedule(LaunchCheckLeaderWrapper, this); 74 | } 75 | break; 76 | case kNewCommand: 77 | bg_thread_.Schedule(LaunchNewCommandWrapper, this); 78 | break; 79 | default: 80 | LOGV(WARN_LEVEL, info_log_, "FloydPrimary:: unknown task type %d", type); 81 | break; 82 | } 83 | } 84 | 85 | void FloydPrimary::LaunchHeartBeatWrapper(void *arg) { 86 | reinterpret_cast(arg)->LaunchHeartBeat(); 87 | } 88 | 89 | void FloydPrimary::LaunchHeartBeat() { 90 | slash::MutexLock l(&context_->global_mu); 91 | if (context_->role == Role::kLeader) { 92 | NoticePeerTask(kNewCommand); 93 | AddTask(kHeartBeat); 94 | } 95 | } 96 | 97 | void FloydPrimary::LaunchCheckLeaderWrapper(void *arg) { 98 | reinterpret_cast(arg)->LaunchCheckLeader(); 99 | } 100 | 101 | void FloydPrimary::LaunchCheckLeader() { 102 | slash::MutexLock l(&context_->global_mu); 103 | if (context_->role == Role::kFollower || context_->role == Role::kCandidate) { 104 | if (options_.single_mode) { 105 | context_->BecomeLeader(); 106 | context_->voted_for_ip = options_.local_ip; 107 | context_->voted_for_port = options_.local_port; 108 | raft_meta_->SetCurrentTerm(context_->current_term); 109 | raft_meta_->SetVotedForIp(context_->voted_for_ip); 110 | raft_meta_->SetVotedForPort(context_->voted_for_port); 111 | } else if (context_->last_op_time + options_.check_leader_us < slash::NowMicros()) { 112 | context_->BecomeCandidate(); 113 | LOGV(INFO_LEVEL, info_log_, "FloydPrimary::LaunchCheckLeader: %s:%d Become Candidate because of timeout, new term is %d" 114 | " voted for %s:%d", options_.local_ip.c_str(), options_.local_port, context_->current_term, 115 | context_->voted_for_ip.c_str(), context_->voted_for_port); 116 | raft_meta_->SetCurrentTerm(context_->current_term); 117 | raft_meta_->SetVotedForIp(context_->voted_for_ip); 118 | raft_meta_->SetVotedForPort(context_->voted_for_port); 119 | NoticePeerTask(kHeartBeat); 120 | } 121 | } 122 | AddTask(kCheckLeader); 123 | } 124 | 125 | void FloydPrimary::LaunchNewCommandWrapper(void *arg) { 126 | reinterpret_cast(arg)->LaunchNewCommand(); 127 | } 128 | 129 | void FloydPrimary::LaunchNewCommand() { 130 | LOGV(DEBUG_LEVEL, info_log_, "FloydPrimary::LaunchNewCommand"); 131 | if (context_->role != Role::kLeader) { 132 | LOGV(WARN_LEVEL, info_log_, "FloydPrimary::LaunchNewCommand, Not leader yet"); 133 | return; 134 | } 135 | NoticePeerTask(kNewCommand); 136 | } 137 | 138 | // when adding task to peer thread, we can consider that this job have been in the network 139 | // even it is still in the peer thread's queue 140 | void FloydPrimary::NoticePeerTask(TaskType type) { 141 | for (auto& peer : (*peers_)) { 142 | switch (type) { 143 | case kHeartBeat: 144 | LOGV(INFO_LEVEL, info_log_, "FloydPrimary::NoticePeerTask server %s:%d Add request Task to queue to %s at term %d", 145 | options_.local_ip.c_str(), options_.local_port, peer.second->peer_addr().c_str(), context_->current_term); 146 | peer.second->AddRequestVoteTask(); 147 | break; 148 | case kNewCommand: 149 | LOGV(DEBUG_LEVEL, info_log_, "FloydPrimary::NoticePeerTask server %s:%d Add appendEntries Task to queue to %s at term %d", 150 | options_.local_ip.c_str(), options_.local_port, peer.second->peer_addr().c_str(), context_->current_term); 151 | peer.second->AddAppendEntriesTask(); 152 | break; 153 | default: 154 | LOGV(WARN_LEVEL, info_log_, "FloydPrimary::NoticePeerTask server %s:%d Error TaskType to notice peer", 155 | options_.local_ip.c_str(), options_.local_port); 156 | } 157 | } 158 | } 159 | 160 | } // namespace floyd 161 | -------------------------------------------------------------------------------- /floyd/src/floyd_primary_thread.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_FLOYD_PRIMARY_THREAD_H_ 7 | #define FLOYD_SRC_FLOYD_PRIMARY_THREAD_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | #include "slash/include/env.h" 15 | #include "slash/include/slash_status.h" 16 | #include "slash/include/slash_mutex.h" 17 | #include "pink/include/bg_thread.h" 18 | 19 | #include "floyd/src/floyd_context.h" 20 | #include "floyd/src/floyd_peer_thread.h" 21 | 22 | namespace floyd { 23 | 24 | using slash::Status; 25 | 26 | class FloydPrimary; 27 | 28 | class FloydContext; 29 | class FloydApply; 30 | class RaftMeta; 31 | class Peer; 32 | class Options; 33 | 34 | enum TaskType { 35 | kHeartBeat = 0, 36 | kCheckLeader = 1, 37 | kNewCommand = 2 38 | }; 39 | 40 | class FloydPrimary { 41 | public: 42 | FloydPrimary(FloydContext* context, PeersSet* peers, RaftMeta* raft_meta, 43 | const Options& options, Logger* info_log); 44 | virtual ~FloydPrimary(); 45 | 46 | int Start(); 47 | int Stop(); 48 | void AddTask(TaskType type, bool is_delay = true); 49 | private: 50 | FloydContext* const context_; 51 | PeersSet* const peers_; 52 | RaftMeta* const raft_meta_; 53 | Options options_; 54 | Logger* const info_log_; 55 | 56 | std::atomic reset_elect_leader_time_; 57 | std::atomic reset_leader_heartbeat_time_; 58 | pink::BGThread bg_thread_; 59 | 60 | // The Launch* work is done by floyd_peer_thread 61 | // Cron task 62 | static void LaunchHeartBeatWrapper(void *arg); 63 | void LaunchHeartBeat(); 64 | static void LaunchCheckLeaderWrapper(void *arg); 65 | void LaunchCheckLeader(); 66 | static void LaunchNewCommandWrapper(void *arg); 67 | void LaunchNewCommand(); 68 | 69 | void NoticePeerTask(TaskType type); 70 | 71 | // No copying allowed 72 | FloydPrimary(const FloydPrimary&); 73 | void operator=(const FloydPrimary&); 74 | }; 75 | 76 | } // namespace floyd 77 | #endif // FLOYD_SRC_FLOYD_PRIMARY_THREAD_H_ 78 | -------------------------------------------------------------------------------- /floyd/src/floyd_worker.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/src/floyd_worker.h" 7 | 8 | #include 9 | 10 | #include "floyd/src/floyd_impl.h" 11 | #include "floyd/src/logger.h" 12 | #include "slash/include/env.h" 13 | 14 | namespace floyd { 15 | using slash::Status; 16 | 17 | FloydWorker::FloydWorker(int port, int cron_interval, FloydImpl* floyd) 18 | : conn_factory_(floyd), 19 | handle_(floyd) { 20 | thread_ = pink::NewHolyThread(port, &conn_factory_, cron_interval, &handle_); 21 | thread_->set_thread_name("W:" + std::to_string(port)); 22 | } 23 | 24 | FloydWorkerConn::FloydWorkerConn(int fd, const std::string& ip_port, 25 | pink::ServerThread* thread, FloydImpl* floyd) 26 | : PbConn(fd, ip_port, thread), 27 | floyd_(floyd) { 28 | } 29 | 30 | FloydWorkerConn::~FloydWorkerConn() {} 31 | 32 | int FloydWorkerConn::DealMessage() { 33 | if (!request_.ParseFromArray(rbuf_ + 4, header_len_)) { 34 | std::string text_format; 35 | google::protobuf::TextFormat::PrintToString(request_, &text_format); 36 | LOGV(WARN_LEVEL, floyd_->info_log_, "FloydWorker: DealMessage failed:\n%s \n", text_format.c_str()); 37 | return -1; 38 | } 39 | response_.Clear(); 40 | response_.set_type(Type::kRead); 41 | set_is_reply(true); 42 | 43 | // why we still need to deal with message that is not these type 44 | switch (request_.type()) { 45 | case Type::kWrite: 46 | response_.set_type(Type::kWrite); 47 | response_.set_code(StatusCode::kError); 48 | floyd_->DoCommand(request_, &response_); 49 | break; 50 | case Type::kDelete: 51 | response_.set_type(Type::kDelete); 52 | response_.set_code(StatusCode::kError); 53 | floyd_->DoCommand(request_, &response_); 54 | break; 55 | case Type::kRead: 56 | response_.set_type(Type::kRead); 57 | response_.set_code(StatusCode::kError); 58 | floyd_->DoCommand(request_, &response_); 59 | break; 60 | case Type::kTryLock: 61 | response_.set_type(Type::kTryLock); 62 | response_.set_code(StatusCode::kError); 63 | floyd_->DoCommand(request_, &response_); 64 | break; 65 | case Type::kUnLock: 66 | response_.set_type(Type::kUnLock); 67 | response_.set_code(StatusCode::kError); 68 | floyd_->DoCommand(request_, &response_); 69 | break; 70 | case Type::kServerStatus: 71 | response_.set_type(Type::kRead); 72 | break; 73 | response_.set_type(Type::kServerStatus); 74 | response_.set_code(StatusCode::kError); 75 | LOGV(WARN_LEVEL, floyd_->info_log_, "obsolete command kServerStatus"); 76 | break; 77 | case Type::kAddServer: 78 | response_.set_type(Type::kAddServer); 79 | floyd_->DoCommand(request_, &response_); 80 | break; 81 | case Type::kRemoveServer: 82 | response_.set_type(Type::kRemoveServer); 83 | floyd_->DoCommand(request_, &response_); 84 | break; 85 | case Type::kGetAllServers: 86 | response_.set_type(Type::kGetAllServers); 87 | floyd_->DoCommand(request_, &response_); 88 | break; 89 | case Type::kRequestVote: 90 | response_.set_type(Type::kRequestVote); 91 | floyd_->ReplyRequestVote(request_, &response_); 92 | response_.set_code(StatusCode::kOk); 93 | break; 94 | case Type::kAppendEntries: 95 | response_.set_type(Type::kAppendEntries); 96 | floyd_->ReplyAppendEntries(request_, &response_); 97 | response_.set_code(StatusCode::kOk); 98 | break; 99 | default: 100 | response_.set_type(Type::kRead); 101 | LOGV(WARN_LEVEL, floyd_->info_log_, "unknown cmd type"); 102 | break; 103 | } 104 | res_ = &response_; 105 | return 0; 106 | } 107 | 108 | FloydWorkerHandle::FloydWorkerHandle(FloydImpl* f) 109 | : floyd_(f) { 110 | } 111 | 112 | // Only connection from other members should be accepted 113 | bool FloydWorkerHandle::AccessHandle(std::string& ip_port) const { 114 | return true; 115 | } 116 | 117 | } // namespace floyd 118 | -------------------------------------------------------------------------------- /floyd/src/floyd_worker.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_FLOYD_WORKER_H_ 7 | #define FLOYD_SRC_FLOYD_WORKER_H_ 8 | 9 | #include 10 | 11 | #include "floyd/src/floyd.pb.h" 12 | #include "pink/include/server_thread.h" 13 | #include "pink/include/pb_conn.h" 14 | 15 | namespace floyd { 16 | 17 | class FloydImpl; 18 | class FloydWorkerConnFactory; 19 | class FloydWorkerHandle; 20 | 21 | class FloydWorkerConn : public pink::PbConn { 22 | public: 23 | FloydWorkerConn(int fd, const std::string& ip_port, 24 | pink::ServerThread* thread, FloydImpl* floyd); 25 | virtual ~FloydWorkerConn(); 26 | 27 | virtual int DealMessage(); 28 | 29 | private: 30 | FloydImpl* const floyd_; 31 | CmdRequest request_; 32 | CmdResponse response_; 33 | }; 34 | 35 | class FloydWorkerConnFactory : public pink::ConnFactory { 36 | public: 37 | explicit FloydWorkerConnFactory(FloydImpl* floyd) 38 | : floyd_(floyd) {} 39 | 40 | pink::PinkConn *NewPinkConn(int connfd, const std::string &ip_port, 41 | pink::ServerThread *server_thread, void* worker_private_data) const override { 42 | return new FloydWorkerConn(connfd, ip_port, server_thread, floyd_); 43 | } 44 | 45 | private: 46 | FloydImpl* const floyd_; 47 | }; 48 | 49 | class FloydWorkerHandle : public pink::ServerHandle { 50 | public: 51 | explicit FloydWorkerHandle(FloydImpl* f); 52 | using pink::ServerHandle::AccessHandle; 53 | bool AccessHandle(std::string& ip) const override; 54 | private: 55 | FloydImpl* const floyd_; 56 | }; 57 | 58 | class FloydWorker { 59 | public: 60 | FloydWorker(int port, int cron_interval, FloydImpl* floyd); 61 | 62 | ~FloydWorker() { 63 | // thread_->StopThread(); 64 | delete thread_; 65 | } 66 | 67 | int Start() { 68 | return thread_->StartThread(); 69 | } 70 | 71 | int Stop() { 72 | return thread_->StopThread(); 73 | } 74 | 75 | private: 76 | FloydWorkerConnFactory conn_factory_; 77 | FloydWorkerHandle handle_; 78 | pink::ServerThread* thread_; 79 | }; 80 | 81 | } // namespace floyd 82 | #endif // FLOYD_SRC_FLOYD_WORKER_H_ 83 | -------------------------------------------------------------------------------- /floyd/src/logger.cc: -------------------------------------------------------------------------------- 1 | #include "floyd/src/logger.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "floyd/include/floyd_options.h" 8 | 9 | #include "slash/include/env.h" 10 | 11 | namespace floyd { 12 | 13 | const char* LEVEL_TAG = " DIWEF "; 14 | 15 | //static inline char *timenow() { 16 | // static char buffer[64]; 17 | // struct timeval tv; 18 | // gettimeofday(&tv, NULL); 19 | // 20 | // snprintf(buffer, 64, "%ld.%06ld", tv.tv_sec, tv.tv_usec); 21 | // 22 | // return buffer; 23 | //} 24 | // 25 | //static inline pid_t pid() { 26 | // return gettid(); 27 | //} 28 | 29 | // 30 | // A simple Logger of RocksDB's PosixLogger 31 | // 32 | uint64_t NowMicros() { 33 | struct timeval tv; 34 | gettimeofday(&tv, NULL); 35 | return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; 36 | } 37 | 38 | Logger::Logger(FILE* f) 39 | : file_(f), 40 | log_size_(0), 41 | last_flush_micros_(0), 42 | flush_pending_(false), 43 | #ifdef NDEBUG 44 | log_level_(INFO_LEVEL) 45 | #else 46 | log_level_(DEBUG_LEVEL) 47 | #endif 48 | {} 49 | 50 | Logger::~Logger() { 51 | fclose(file_); 52 | } 53 | 54 | void Logger::Flush() { 55 | if (flush_pending_) { 56 | flush_pending_ = false; 57 | fflush(file_); 58 | } 59 | last_flush_micros_ = NowMicros(); 60 | } 61 | 62 | void Logger::Logv(int log_level, const char* format, va_list ap) { 63 | // log_level only between Debug to Fatal 64 | assert(log_level >= 0 && log_level < 6); 65 | const uint64_t thread_id = pid(); 66 | 67 | // We try twice: the first time with a fixed-size stack allocated buffer, 68 | // and the second time with a much larger dynamically allocated buffer. 69 | char buffer[500]; 70 | for (int iter = 0; iter < 2; iter++) { 71 | char* base; 72 | int bufsize; 73 | if (iter == 0) { 74 | bufsize = sizeof(buffer); 75 | base = buffer; 76 | } else { 77 | bufsize = 65536; 78 | base = new char[bufsize]; 79 | } 80 | char* p = base; 81 | char* limit = base + bufsize; 82 | 83 | struct timeval now_tv; 84 | gettimeofday(&now_tv, nullptr); 85 | const time_t seconds = now_tv.tv_sec; 86 | struct tm t; 87 | localtime_r(&seconds, &t); 88 | p += snprintf(p, limit - p, 89 | "%c%02d%02d %02d:%02d:%02d.%06d %6lld ", 90 | LEVEL_TAG[log_level], 91 | t.tm_mon + 1, 92 | t.tm_mday, 93 | t.tm_hour, 94 | t.tm_min, 95 | t.tm_sec, 96 | static_cast(now_tv.tv_usec), 97 | static_cast(thread_id)); 98 | 99 | // Print the message 100 | if (p < limit) { 101 | va_list backup_ap; 102 | va_copy(backup_ap, ap); 103 | p += vsnprintf(p, limit - p, format, backup_ap); 104 | va_end(backup_ap); 105 | } 106 | 107 | // Truncate to available space if necessary 108 | if (p >= limit) { 109 | if (iter == 0) { 110 | continue; // Try again with larger buffer 111 | } else { 112 | p = limit - 1; 113 | } 114 | } 115 | 116 | // Add newline if necessary 117 | if (p == base || p[-1] != '\n') { 118 | *p++ = '\n'; 119 | } 120 | 121 | assert(p <= limit); 122 | const size_t write_size = p - base; 123 | 124 | 125 | size_t sz = fwrite(base, 1, write_size, file_); 126 | flush_pending_ = true; 127 | assert(sz == write_size); 128 | if (sz > 0) { 129 | log_size_ += write_size; 130 | } 131 | uint64_t now_micros = static_cast(now_tv.tv_sec) * 1000000 + 132 | now_tv.tv_usec; 133 | if (now_micros - last_flush_micros_ >= flush_every_seconds_ * 1000000) { 134 | Flush(); 135 | } 136 | if (base != buffer) { 137 | delete[] base; 138 | } 139 | break; 140 | } 141 | } 142 | 143 | int NewLogger(const std::string& fname, Logger** result) { 144 | *result = NULL; 145 | FILE* f = fopen(fname.c_str(), "w"); 146 | if (f == nullptr) { 147 | return -1; 148 | } else { 149 | int fd = fileno(f); 150 | fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 151 | *result = new Logger(f); 152 | return 0; 153 | } 154 | } 155 | 156 | void Logv(const int log_level, Logger* info_log, 157 | const char* format, ...) { 158 | if (info_log && info_log->log_level() <= log_level) { 159 | va_list ap; 160 | va_start(ap, format); 161 | info_log->Logv(log_level, format, ap); 162 | va_end(ap); 163 | } 164 | } 165 | 166 | } // namespace floyd 167 | -------------------------------------------------------------------------------- /floyd/src/logger.h: -------------------------------------------------------------------------------- 1 | #ifndef LOGGER_H_ 2 | #define LOGGER_H_ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // Use class Logger to write to a file 12 | // Usage: 13 | // 1) first create a logger; 14 | // Logger* logger; 15 | // NewLogger(path, &logger); 16 | // 2) use LOGV(LEVEL, logger, fmt, ...); 17 | // eg: LOGV(DEBUG_LEVEL, logger, "%s", "example message"); 18 | namespace floyd { 19 | 20 | class Logger; 21 | 22 | // LOGV 23 | int NewLogger(const std::string& fname, Logger** result); 24 | // void LogFlush(const Logger* info_log); 25 | 26 | 27 | // 28 | // Internal use 29 | // 30 | #define _FILE strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__ 31 | 32 | #define LOG_FMT "%s:%d] " 33 | 34 | #define LOGV(level, info_log, message, args...) \ 35 | Logv(level, info_log, LOG_FMT message, _FILE, __LINE__, ##args) 36 | 37 | //enum { 38 | // DEBUG_LEVEL = 0x01, 39 | // INFO_LEVEL = 0x02, 40 | // WARN_LEVEL = 0x03, 41 | // ERROR_LEVEL = 0x04, 42 | // FATAL_LEVEL = 0x05, 43 | // NONE_LEVEL = 0x06 44 | //}; 45 | 46 | //#define DEBUG_LEVEL 0x01 47 | //#define INFO_LEVEL 0x02 48 | //#define WARN_LEVEL 0x03 49 | //#define ERROR_LEVEL 0x04 50 | //#define FATAL_LEVEL 0x05 51 | //#define NONE_LEVEL 0x06 52 | 53 | void Logv(const int log_level, Logger* info_log, 54 | const char* format, ...); 55 | 56 | extern const char* LEVEL_TAG; 57 | #define gettid() syscall(SYS_gettid) 58 | static inline pid_t pid(); 59 | 60 | 61 | static inline pid_t pid() { 62 | return gettid(); 63 | } 64 | 65 | class Logger { 66 | private: 67 | FILE* file_; 68 | std::atomic_size_t log_size_; 69 | const static uint64_t flush_every_seconds_ = 5; 70 | std::atomic_uint_fast64_t last_flush_micros_; 71 | bool flush_pending_; 72 | int log_level_; 73 | 74 | public: 75 | Logger(FILE* f); 76 | ~Logger(); 77 | 78 | void Flush(); 79 | void Logv(int log_level, const char* format, va_list ap); 80 | size_t GetLogFileSize() const { return log_size_; } 81 | 82 | void set_log_level(const int log_level) { 83 | log_level_ = log_level; 84 | } 85 | int log_level() const { 86 | return log_level_; 87 | } 88 | }; 89 | 90 | } // namespace floyd 91 | #endif 92 | -------------------------------------------------------------------------------- /floyd/src/raft_log.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/src/raft_log.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "rocksdb/db.h" 14 | #include "rocksdb/iterator.h" 15 | #include "slash/include/xdebug.h" 16 | 17 | #include "floyd/src/floyd.pb.h" 18 | #include "floyd/src/logger.h" 19 | #include "floyd/include/floyd_options.h" 20 | 21 | namespace floyd { 22 | extern std::string UintToBitStr(const uint64_t num) { 23 | char buf[8]; 24 | uint64_t num1 = htobe64(num); 25 | memcpy(buf, &num1, sizeof(uint64_t)); 26 | return std::string(buf, 8); 27 | } 28 | 29 | extern uint64_t BitStrToUint(const std::string &str) { 30 | uint64_t num; 31 | memcpy(&num, str.c_str(), sizeof(uint64_t)); 32 | return be64toh(num); 33 | } 34 | 35 | RaftLog::RaftLog(rocksdb::DB *db, Logger *info_log) : 36 | db_(db), 37 | info_log_(info_log), 38 | last_log_index_(0) { 39 | rocksdb::Iterator *it = db_->NewIterator(rocksdb::ReadOptions()); 40 | it->SeekToLast(); 41 | if (it->Valid()) { 42 | it->Prev(); 43 | it->Prev(); 44 | it->Prev(); 45 | it->Prev(); 46 | it->Prev(); 47 | if (it->Valid()) { 48 | last_log_index_ = BitStrToUint(it->key().ToString()); 49 | } 50 | } 51 | delete it; 52 | } 53 | 54 | RaftLog::~RaftLog() { 55 | } 56 | 57 | uint64_t RaftLog::Append(const std::vector &entries) { 58 | slash::MutexLock l(&lli_mutex_); 59 | rocksdb::WriteBatch wb; 60 | LOGV(DEBUG_LEVEL, info_log_, "RaftLog::Append: entries.size %lld", entries.size()); 61 | // try to commit entries in one batch 62 | for (size_t i = 0; i < entries.size(); i++) { 63 | std::string buf; 64 | entries[i]->SerializeToString(&buf); 65 | last_log_index_++; 66 | wb.Put(UintToBitStr(last_log_index_), buf); 67 | } 68 | rocksdb::Status s; 69 | s = db_->Write(rocksdb::WriteOptions(), &wb); 70 | if (!s.ok()) { 71 | last_log_index_ -= entries.size(); 72 | LOGV(ERROR_LEVEL, info_log_, "RaftLog::Append append entries failed, entries size %u, last_log_index_ is %lu", 73 | entries.size(), last_log_index_); 74 | } 75 | return last_log_index_; 76 | } 77 | 78 | uint64_t RaftLog::GetLastLogIndex() { 79 | return last_log_index_; 80 | } 81 | 82 | int RaftLog::GetEntry(const uint64_t index, Entry *entry) { 83 | slash::MutexLock l(&lli_mutex_); 84 | std::string buf = UintToBitStr(index); 85 | std::string res; 86 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), buf, &res); 87 | if (s.IsNotFound()) { 88 | LOGV(ERROR_LEVEL, info_log_, "RaftLog::GetEntry: GetEntry not found, index is %lld", index); 89 | entry = NULL; 90 | return 1; 91 | } 92 | entry->ParseFromString(res); 93 | return 0; 94 | } 95 | 96 | bool RaftLog::GetLastLogTermAndIndex(uint64_t* last_log_term, uint64_t* last_log_index) { 97 | slash::MutexLock l(&lli_mutex_); 98 | if (last_log_index_ == 0) { 99 | *last_log_index = 0; 100 | *last_log_term = 0; 101 | return true; 102 | } 103 | std::string buf; 104 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), UintToBitStr(last_log_index_), &buf); 105 | if (!s.ok() || s.IsNotFound()) { 106 | *last_log_index = 0; 107 | *last_log_term = 0; 108 | return true; 109 | } 110 | Entry entry; 111 | entry.ParseFromString(buf); 112 | *last_log_index = last_log_index_; 113 | *last_log_term = entry.term(); 114 | return true; 115 | } 116 | 117 | /* 118 | * truncate suffix from index 119 | */ 120 | int RaftLog::TruncateSuffix(uint64_t index) { 121 | // we need to delete the unnecessary entry, since we don't store 122 | // last_log_index in rocksdb 123 | rocksdb::WriteBatch batch; 124 | for (; last_log_index_ >= index; last_log_index_--) { 125 | batch.Delete(UintToBitStr(last_log_index_)); 126 | } 127 | if (batch.Count() > 0) { 128 | rocksdb::Status s = db_->Write(rocksdb::WriteOptions(), &batch); 129 | if (!s.ok()) { 130 | LOGV(ERROR_LEVEL, info_log_, "RaftLog::TruncateSuffix Error last_log_index %lu " 131 | "truncate from %lu", last_log_index_, index); 132 | return -1; 133 | } 134 | } 135 | return 0; 136 | } 137 | 138 | } // namespace floyd 139 | -------------------------------------------------------------------------------- /floyd/src/raft_log.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_RAFT_LOG_H_ 7 | #define FLOYD_SRC_RAFT_LOG_H_ 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "rocksdb/db.h" 16 | #include "slash/include/slash_mutex.h" 17 | 18 | namespace floyd { 19 | 20 | class Logger; 21 | class Entry; 22 | 23 | class RaftLog { 24 | public: 25 | RaftLog(rocksdb::DB* db, Logger* info_log); 26 | ~RaftLog(); 27 | 28 | uint64_t Append(const std::vector &entries); 29 | 30 | int GetEntry(uint64_t index, Entry *entry); 31 | 32 | uint64_t GetLastLogIndex(); 33 | bool GetLastLogTermAndIndex(uint64_t* last_log_term, uint64_t* last_log_index); 34 | int TruncateSuffix(uint64_t index); 35 | 36 | private: 37 | rocksdb::DB* const db_; 38 | Logger* const info_log_; 39 | /* 40 | * mutex for last_log_index_ 41 | */ 42 | slash::Mutex lli_mutex_; 43 | uint64_t last_log_index_; 44 | 45 | /* 46 | * we don't store last_log_index_ in rocksdb, since if we store it in rocksdb 47 | * we need update it every time I append an entry. 48 | * so we need update it when we open db 49 | */ 50 | RaftLog(const RaftLog&); 51 | void operator=(const RaftLog&); 52 | }; // RaftLog 53 | 54 | }; // namespace floyd 55 | 56 | #endif // FLOYD_SRC_RAFT_LOG_H_ 57 | -------------------------------------------------------------------------------- /floyd/src/raft_meta.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #include "floyd/src/raft_meta.h" 7 | 8 | #include 9 | 10 | #include "rocksdb/status.h" 11 | 12 | #include "floyd/src/logger.h" 13 | #include "floyd/src/floyd.pb.h" 14 | #include "slash/include/env.h" 15 | #include "slash/include/xdebug.h" 16 | 17 | namespace floyd { 18 | 19 | static const std::string kCurrentTerm = "CURRENTTERM"; 20 | static const std::string kVoteForIp = "VOTEFORIP"; 21 | static const std::string kVoteForPort = "VOTEFORPORT"; 22 | static const std::string kCommitIndex = "COMMITINDEX"; 23 | static const std::string kLastApplied = "APPLYINDEX"; 24 | /* 25 | * fencing token is not part of raft, fencing token is used for implementing distributed lock 26 | */ 27 | static const std::string kFencingToken = "FENCINGTOKEN"; 28 | 29 | RaftMeta::RaftMeta(rocksdb::DB* db, Logger* info_log) 30 | : db_(db), 31 | info_log_(info_log) { 32 | } 33 | 34 | RaftMeta::~RaftMeta() { 35 | } 36 | 37 | void RaftMeta::Init() { 38 | if (GetCurrentTerm() == 0) { 39 | SetCurrentTerm(0); 40 | } 41 | if (GetVotedForIp() == "") { 42 | SetVotedForIp(""); 43 | } 44 | if (GetVotedForPort() == 0) { 45 | SetVotedForPort(0); 46 | } 47 | if (GetCommitIndex() == 0) { 48 | SetCommitIndex(0); 49 | } 50 | if (GetLastApplied() == 0) { 51 | SetLastApplied(0); 52 | } 53 | } 54 | 55 | uint64_t RaftMeta::GetCurrentTerm() { 56 | std::string buf; 57 | uint64_t ans; 58 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), kCurrentTerm, &buf); 59 | if (s.IsNotFound()) { 60 | return 0; 61 | } 62 | memcpy(&ans, buf.data(), sizeof(uint64_t)); 63 | return ans; 64 | } 65 | 66 | void RaftMeta::SetCurrentTerm(const uint64_t current_term) { 67 | char buf[8]; 68 | memcpy(buf, ¤t_term, sizeof(uint64_t)); 69 | db_->Put(rocksdb::WriteOptions(), kCurrentTerm, std::string(buf, 8)); 70 | return; 71 | } 72 | 73 | std::string RaftMeta::GetVotedForIp() { 74 | std::string buf; 75 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), kVoteForIp, &buf); 76 | if (s.IsNotFound()) { 77 | return std::string(""); 78 | } 79 | return buf; 80 | } 81 | 82 | void RaftMeta::SetVotedForIp(const std::string ip) { 83 | db_->Put(rocksdb::WriteOptions(), kVoteForIp, ip); 84 | return; 85 | } 86 | 87 | int RaftMeta::GetVotedForPort() { 88 | std::string buf; 89 | int ans; 90 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), kVoteForPort, &buf); 91 | if (s.IsNotFound()) { 92 | return 0; 93 | } 94 | memcpy(&ans, buf.data(), sizeof(int)); 95 | return ans; 96 | } 97 | 98 | void RaftMeta::SetVotedForPort(const int port) { 99 | char buf[4]; 100 | memcpy(buf, &port, sizeof(int)); 101 | db_->Put(rocksdb::WriteOptions(), kVoteForPort, std::string(buf, sizeof(int))); 102 | return; 103 | } 104 | 105 | uint64_t RaftMeta::GetCommitIndex() { 106 | std::string buf; 107 | uint64_t ans; 108 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), kCommitIndex, &buf); 109 | if (s.IsNotFound()) { 110 | return 0; 111 | } 112 | memcpy(&ans, buf.data(), sizeof(uint64_t)); 113 | return ans; 114 | } 115 | 116 | void RaftMeta::SetCommitIndex(uint64_t commit_index) { 117 | char buf[8]; 118 | memcpy(buf, &commit_index, sizeof(uint64_t)); 119 | db_->Put(rocksdb::WriteOptions(), kCommitIndex, std::string(buf, 8)); 120 | } 121 | 122 | uint64_t RaftMeta::GetLastApplied() { 123 | std::string buf; 124 | uint64_t ans; 125 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), kLastApplied, &buf); 126 | if (s.IsNotFound()) { 127 | return 0; 128 | } 129 | memcpy(&ans, buf.data(), sizeof(uint64_t)); 130 | return ans; 131 | } 132 | 133 | void RaftMeta::SetLastApplied(uint64_t last_applied) { 134 | char buf[8]; 135 | memcpy(buf, &last_applied, sizeof(uint64_t)); 136 | db_->Put(rocksdb::WriteOptions(), kLastApplied, std::string(buf, 8)); 137 | } 138 | 139 | uint64_t RaftMeta::GetNewFencingToken() { 140 | std::string buf; 141 | uint64_t ans; 142 | rocksdb::Status s = db_->Get(rocksdb::ReadOptions(), kFencingToken, &buf); 143 | if (s.IsNotFound()) { 144 | ans = 0; 145 | } 146 | memcpy(&ans, buf.data(), sizeof(uint64_t)); 147 | ans++; 148 | char wbuf[8]; 149 | memcpy(wbuf, &ans, sizeof(uint64_t)); 150 | db_->Put(rocksdb::WriteOptions(), kFencingToken, std::string(wbuf, 8)); 151 | return ans; 152 | } 153 | 154 | } // namespace floyd 155 | -------------------------------------------------------------------------------- /floyd/src/raft_meta.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-present, Qihoo, Inc. All rights reserved. 2 | // This source code is licensed under the BSD-style license found in the 3 | // LICENSE file in the root directory of this source tree. An additional grant 4 | // of patent rights can be found in the PATENTS file in the same directory. 5 | 6 | #ifndef FLOYD_SRC_RAFT_META_H_ 7 | #define FLOYD_SRC_RAFT_META_H_ 8 | 9 | #include 10 | #include 11 | 12 | #include "rocksdb/db.h" 13 | 14 | #include "floyd/include/floyd_options.h" 15 | #include "slash/include/slash_status.h" 16 | #include "slash/include/slash_mutex.h" 17 | 18 | namespace floyd { 19 | 20 | using slash::Status; 21 | 22 | class Logger; 23 | 24 | /* 25 | * we use RaftMeta to avoid passing the floyd_impl's this point to other thread 26 | */ 27 | /* 28 | * main data stored in raftmeta 29 | * static const std::string kcurrentterm = "currentterm"; 30 | * static const std::string kvoteforip = "voteforip"; 31 | * static const std::string kvoteforport = "voteforport"; 32 | * static const std::string kcommitindex = "commitindex"; 33 | * static const std::string klastapplied = "applyindex"; 34 | * fencing token is not part of raft, fencing token is used for implementing distributed lock 35 | * static const std::string kFencingToken = "FENCINGTOKEN"; 36 | */ 37 | class RaftMeta { 38 | public: 39 | RaftMeta(rocksdb::DB *db, Logger* info_log); 40 | ~RaftMeta(); 41 | 42 | void Init(); 43 | 44 | // return persistent state from zeppelin 45 | uint64_t GetCurrentTerm(); 46 | void SetCurrentTerm(const uint64_t current_term); 47 | 48 | std::string GetVotedForIp(); 49 | int GetVotedForPort(); 50 | void SetVotedForIp(const std::string ip); 51 | void SetVotedForPort(const int port); 52 | 53 | uint64_t GetCommitIndex(); 54 | void SetCommitIndex(const uint64_t commit_index); 55 | 56 | uint64_t GetLastApplied(); 57 | void SetLastApplied(uint64_t last_applied); 58 | 59 | uint64_t GetNewFencingToken(); 60 | private: 61 | // db used to data that need to be persistent 62 | rocksdb::DB * const db_; 63 | // used to debug 64 | Logger* info_log_; 65 | 66 | }; 67 | 68 | } // namespace floyd 69 | #endif // FLOYD_SRC_RAFT_META_H_ 70 | -------------------------------------------------------------------------------- /floyd/tools/Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | ifeq ($(__PERF), 1) 3 | CXXFLAGS = -O0 -g -pipe -fPIC -DNDEBUG -DLOG_LEVEL=LEVEL_INFO -W -Wwrite-strings -Wpointer-arith -Wreorder -Wswitch -Wsign-promo -Wredundant-decls -Wformat -Wall -D_GNU_SOURCE -std=c++11 -D__STDC_FORMAT_MACROS -std=c++11 -gdwarf-2 -Wno-redundant-decls -Wno-unused-variable -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DOS_LINUX 4 | else 5 | CXXFLAGS = -pg -O2 -ggdb3 -pipe -fPIC -W -Wwrite-strings -Wpointer-arith -Wreorder -Wswitch -Wsign-promo -Wredundant-decls -Wformat -D_GNU_SOURCE -D__STDC_FORMAT_MACROS -std=c++11 -gdwarf-2 -Wno-redundant-decls -Wno-unused-variable -DROCKSDB_PLATFORM_POSIX -DROCKSDB_LIB_IO_POSIX -DOS_LINUX 6 | endif 7 | 8 | OBJECT = read_rock read_floyd cpt cl cl1 9 | SRC_DIR = ./ 10 | THIRD_PATH = ../third 11 | OUTPUT = ./output 12 | 13 | LIB_PATH = -L../lib/ \ 14 | -L$(THIRD_PATH)/slash/slash/lib/ \ 15 | -L$(THIRD_PATH)/rocksdb/ \ 16 | -L$(THIRD_PATH)/pink/pink/lib/ 17 | 18 | 19 | LIBS = -lpink \ 20 | -lslash \ 21 | -lrocksdb \ 22 | -lsnappy \ 23 | -lprotobuf \ 24 | -lz \ 25 | -lbz2 \ 26 | -lrt \ 27 | -lssl \ 28 | -lcrypto \ 29 | -lpthread 30 | 31 | INCLUDE_PATH = -I../../ \ 32 | -I$(THIRD_PATH)/rocksdb/include \ 33 | -I$(THIRD_PATH)/slash/ \ 34 | -I$(THIRD_PATH)/pink/ 35 | 36 | AM_DEFAULT_VERBOSITY = 0 37 | 38 | AM_V_GEN = $(am__v_GEN_$(V)) 39 | am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) 40 | am__v_GEN_0 = @echo " GEN " $@; 41 | am__v_GEN_1 = 42 | AM_V_at = $(am__v_at_$(V)) 43 | am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) 44 | am__v_at_0 = @ 45 | am__v_at_1 = 46 | 47 | AM_V_CC = $(am__v_CC_$(V)) 48 | am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) 49 | am__v_CC_0 = @echo " CC " $@; 50 | am__v_CC_1 = 51 | CCLD = $(CC) 52 | LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ 53 | AM_V_CCLD = $(am__v_CCLD_$(V)) 54 | am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) 55 | am__v_CCLD_0 = @echo " CCLD " $@; 56 | am__v_CCLD_1 = 57 | AM_V_AR = $(am__v_AR_$(V)) 58 | am__v_AR_ = $(am__v_AR_$(AM_DEFAULT_VERBOSITY)) 59 | am__v_AR_0 = @echo " AR " $@; 60 | am__v_AR_1 = 61 | 62 | AM_LINK = $(AM_V_CCLD)$(CXX) $^ $(EXEC_LDFLAGS) -o $@ $(LDFLAGS) $(COVERAGEFLAGS) 63 | 64 | .PHONY: all clean version 65 | 66 | 67 | BASE_BOJS := $(wildcard $(SRC_DIR)/*.cc) 68 | BASE_BOJS += $(wildcard $(SRC_DIR)/*.c) 69 | BASE_BOJS += $(wildcard $(SRC_DIR)/*.cpp) 70 | OBJS = $(patsubst %.cc,%.o,$(BASE_BOJS)) 71 | 72 | all: $(OBJECT) 73 | rm -rf $(OUTPUT) 74 | mkdir -p $(OUTPUT) 75 | mkdir -p $(OUTPUT)/bin 76 | cp $(OBJECT) $(OUTPUT)/bin/ 77 | rm -rf $(OBJECT) 78 | @echo "Success, go, go, go..." 79 | 80 | read_rock: read_rock.cc 81 | $(AM_V_CC)$(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 82 | cpt: cpt.cc 83 | $(AM_V_CC)$(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 84 | read_floyd: read_floyd.cc ../src/floyd.pb.cc ../src/floyd.pb.h 85 | $(AM_V_CC)$(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 86 | cl: cl.cc ../src/*.cc ../include/* 87 | $(AM_V_CC)$(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 88 | cl1: cl1.cc ../src/*.cc ../include/* 89 | $(AM_V_CC)$(CXX) $(CXXFLAGS) -o $@ $^ $(INCLUDE_PATH) $(LIB_PATH) $(LIBS) 90 | $(OBJS): %.o : %.cc 91 | $(CXX) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_PATH) 92 | 93 | clean: 94 | rm -rf $(OUTPUT) 95 | rm -rf $(SRC_DIR)/log 96 | rm -rf ./data* 97 | rm -f $(SRC_DIR)/*.o 98 | rm -rf $(OBJECT) 99 | -------------------------------------------------------------------------------- /floyd/tools/README: -------------------------------------------------------------------------------- 1 | read_floyd is the tool to read floyd log 2 | read_rock is the tool to read rocksdb data 3 | cpt is a tool to compare two rocksdb, if they have the same data return true, else return false 4 | cl construct 4 same log, ant one log with longer logger 5 | cl1 construct the raft paper's Figure 7 logger, cl1 is the leader, cl2 is (a), cl3 is (c), cl4 is (e), cl5 is (f) 6 | -------------------------------------------------------------------------------- /floyd/tools/cl.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "rocksdb/db.h" 7 | #include "slash/include/env.h" 8 | 9 | #include "floyd/src/raft_log.h" 10 | #include "floyd/src/raft_meta.h" 11 | #include "floyd/src/floyd.pb.h" 12 | #include "floyd/src/logger.h" 13 | 14 | using namespace floyd; 15 | void InitEntry(int term, const std::string &key, const std::string &val, Entry *entry) { 16 | entry->set_term(term); 17 | entry->set_key(key); 18 | entry->set_value(val); 19 | entry->set_optype(Entry_OpType_kWrite); 20 | } 21 | int cl(const std::string path) { 22 | // construct data1 node 23 | Logger *logger; 24 | slash::CreatePath(path); 25 | if (NewLogger(path + "/LOG", &logger) != 0) { 26 | return -1; 27 | } 28 | rocksdb::DB* db; 29 | rocksdb::Options options; 30 | options.create_if_missing = true; 31 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 32 | RaftMeta *raft_meta = new RaftMeta(db, logger); 33 | raft_meta->Init(); 34 | RaftLog *raft_log = new RaftLog(db, logger); 35 | std::vector entries; 36 | char buff[10]; 37 | for (int i = 0; i < 10; i++) { 38 | Entry *entry = new Entry(); 39 | snprintf(buff, sizeof(buff), "%d", i); 40 | InitEntry(10, std::string(buff, sizeof(int)), std::string(buff, sizeof(int)), entry); 41 | entries.push_back(entry); 42 | } 43 | raft_log->Append(entries); 44 | raft_meta->SetCurrentTerm(10); 45 | raft_meta->SetCommitIndex(10); 46 | raft_meta->SetLastApplied(0); 47 | 48 | delete raft_meta; 49 | delete raft_log; 50 | delete db; 51 | delete logger; 52 | } 53 | 54 | int cl_spec(const std::string path) { 55 | // construct data1 node 56 | Logger *logger; 57 | slash::CreatePath(path); 58 | if (NewLogger(path + "/LOG", &logger) != 0) { 59 | return -1; 60 | } 61 | rocksdb::DB* db; 62 | rocksdb::Options options; 63 | options.create_if_missing = true; 64 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 65 | RaftMeta *raft_meta = new RaftMeta(db, logger); 66 | raft_meta->Init(); 67 | RaftLog *raft_log = new RaftLog(db, logger); 68 | std::vector entries; 69 | char buff[10]; 70 | for (int i = 0; i < 21; i++) { 71 | Entry *entry = new Entry(); 72 | snprintf(buff, sizeof(buff), "%d", i); 73 | entry->set_term(10); 74 | entry->set_key(std::string(buff, sizeof(int))); 75 | entry->set_value(std::string(buff, sizeof(int))); 76 | entry->set_optype(Entry_OpType_kWrite); 77 | entries.push_back(entry); 78 | } 79 | raft_log->Append(entries); 80 | raft_meta->SetCurrentTerm(10); 81 | raft_meta->SetCommitIndex(10); 82 | raft_meta->SetLastApplied(0); 83 | 84 | delete raft_meta; 85 | delete raft_log; 86 | delete db; 87 | delete logger; 88 | } 89 | 90 | int main() 91 | { 92 | 93 | cl("./data1/"); 94 | cl("./data2/"); 95 | cl("./data3/"); 96 | cl_spec("./data4/"); 97 | cl("./data5/"); 98 | 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /floyd/tools/cl1.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file cl1.cc 3 | * @brief construct raft log with different log entry 4 | * @author chenzongzhi 5 | * @version 1.0.0 6 | * @date 2017-08-06 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "rocksdb/db.h" 16 | #include "slash/include/env.h" 17 | 18 | #include "floyd/src/raft_log.h" 19 | #include "floyd/src/raft_meta.h" 20 | #include "floyd/src/floyd.pb.h" 21 | #include "floyd/src/logger.h" 22 | 23 | using namespace floyd; 24 | 25 | void InitEntry(int term, const std::string &key, const std::string &val, Entry *entry) { 26 | entry->set_term(term); 27 | entry->set_key(key); 28 | entry->set_value(val); 29 | entry->set_optype(Entry_OpType_kWrite); 30 | } 31 | int cl1(const std::string path) { 32 | // construct data1 node 33 | Logger *logger; 34 | slash::CreatePath(path); 35 | if (NewLogger(path + "/LOG", &logger) != 0) { 36 | return -1; 37 | } 38 | rocksdb::DB* db; 39 | rocksdb::Options options; 40 | options.create_if_missing = true; 41 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 42 | RaftMeta *raft_meta = new RaftMeta(db, logger); 43 | raft_meta->Init(); 44 | RaftLog *raft_log = new RaftLog(db, logger); 45 | 46 | std::vector entries; 47 | Entry *entry = new Entry(); 48 | InitEntry(1, "1", "1", entry); 49 | entries.push_back(entry); 50 | 51 | entry = new Entry(); 52 | InitEntry(1, "2", "2", entry); 53 | entries.push_back(entry); 54 | 55 | entry = new Entry(); 56 | InitEntry(1, "3", "3", entry); 57 | entries.push_back(entry); 58 | 59 | entry = new Entry(); 60 | InitEntry(4, "4", "4", entry); 61 | entries.push_back(entry); 62 | 63 | entry = new Entry(); 64 | InitEntry(4, "5", "5", entry); 65 | entries.push_back(entry); 66 | 67 | entry = new Entry(); 68 | InitEntry(5, "6", "6", entry); 69 | entries.push_back(entry); 70 | 71 | entry = new Entry(); 72 | InitEntry(5, "7", "7", entry); 73 | entries.push_back(entry); 74 | 75 | entry = new Entry(); 76 | InitEntry(6, "8", "8", entry); 77 | entries.push_back(entry); 78 | 79 | entry = new Entry(); 80 | InitEntry(6, "9", "9", entry); 81 | entries.push_back(entry); 82 | 83 | entry = new Entry(); 84 | InitEntry(6, "10", "10", entry); 85 | entries.push_back(entry); 86 | 87 | raft_log->Append(entries); 88 | raft_meta->SetCurrentTerm(6); 89 | raft_meta->SetCommitIndex(9); 90 | raft_meta->SetLastApplied(0); 91 | 92 | delete raft_meta; 93 | delete raft_log; 94 | delete db; 95 | delete logger; 96 | } 97 | 98 | int cl2(const std::string path) { 99 | // construct data1 node 100 | Logger *logger; 101 | slash::CreatePath(path); 102 | if (NewLogger(path + "/LOG", &logger) != 0) { 103 | return -1; 104 | } 105 | rocksdb::DB* db; 106 | rocksdb::Options options; 107 | options.create_if_missing = true; 108 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 109 | RaftMeta *raft_meta = new RaftMeta(db, logger); 110 | raft_meta->Init(); 111 | RaftLog *raft_log = new RaftLog(db, logger); 112 | 113 | std::vector entries; 114 | Entry *entry = new Entry(); 115 | InitEntry(1, "1", "1", entry); 116 | entries.push_back(entry); 117 | 118 | entry = new Entry(); 119 | InitEntry(1, "2", "2", entry); 120 | entries.push_back(entry); 121 | 122 | entry = new Entry(); 123 | InitEntry(1, "3", "3", entry); 124 | entries.push_back(entry); 125 | 126 | entry = new Entry(); 127 | InitEntry(4, "4", "4", entry); 128 | entries.push_back(entry); 129 | 130 | entry = new Entry(); 131 | InitEntry(4, "5", "5", entry); 132 | entries.push_back(entry); 133 | 134 | entry = new Entry(); 135 | InitEntry(5, "6", "6", entry); 136 | entries.push_back(entry); 137 | 138 | entry = new Entry(); 139 | InitEntry(5, "7", "7", entry); 140 | entries.push_back(entry); 141 | 142 | entry = new Entry(); 143 | InitEntry(6, "8", "8", entry); 144 | entries.push_back(entry); 145 | 146 | entry = new Entry(); 147 | InitEntry(6, "9", "9", entry); 148 | entries.push_back(entry); 149 | 150 | raft_log->Append(entries); 151 | raft_meta->SetCurrentTerm(6); 152 | raft_meta->SetCommitIndex(9); 153 | raft_meta->SetLastApplied(0); 154 | 155 | delete raft_meta; 156 | delete raft_log; 157 | delete db; 158 | delete logger; 159 | } 160 | 161 | int cl3(const std::string path) { 162 | // construct data1 node 163 | Logger *logger; 164 | slash::CreatePath(path); 165 | if (NewLogger(path + "/LOG", &logger) != 0) { 166 | return -1; 167 | } 168 | rocksdb::DB* db; 169 | rocksdb::Options options; 170 | options.create_if_missing = true; 171 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 172 | RaftMeta *raft_meta = new RaftMeta(db, logger); 173 | raft_meta->Init(); 174 | RaftLog *raft_log = new RaftLog(db, logger); 175 | 176 | std::vector entries; 177 | Entry *entry = new Entry(); 178 | InitEntry(1, "1", "1", entry); 179 | entries.push_back(entry); 180 | 181 | entry = new Entry(); 182 | InitEntry(1, "2", "2", entry); 183 | entries.push_back(entry); 184 | 185 | entry = new Entry(); 186 | InitEntry(1, "3", "3", entry); 187 | entries.push_back(entry); 188 | 189 | entry = new Entry(); 190 | InitEntry(4, "4", "4", entry); 191 | entries.push_back(entry); 192 | 193 | entry = new Entry(); 194 | InitEntry(4, "5", "5", entry); 195 | entries.push_back(entry); 196 | 197 | entry = new Entry(); 198 | InitEntry(5, "6", "6", entry); 199 | entries.push_back(entry); 200 | 201 | entry = new Entry(); 202 | InitEntry(5, "7", "7", entry); 203 | entries.push_back(entry); 204 | 205 | entry = new Entry(); 206 | InitEntry(6, "8", "8", entry); 207 | entries.push_back(entry); 208 | 209 | entry = new Entry(); 210 | InitEntry(6, "9", "9", entry); 211 | entries.push_back(entry); 212 | 213 | entry = new Entry(); 214 | InitEntry(6, "10", "10", entry); 215 | entries.push_back(entry); 216 | 217 | entry = new Entry(); 218 | InitEntry(6, "11", "11", entry); 219 | entries.push_back(entry); 220 | 221 | raft_log->Append(entries); 222 | raft_meta->SetCurrentTerm(6); 223 | raft_meta->SetCommitIndex(9); 224 | raft_meta->SetLastApplied(0); 225 | 226 | delete raft_meta; 227 | delete raft_log; 228 | delete db; 229 | delete logger; 230 | } 231 | 232 | 233 | int cl4(const std::string path) { 234 | // construct data1 node 235 | Logger *logger; 236 | slash::CreatePath(path); 237 | if (NewLogger(path + "/LOG", &logger) != 0) { 238 | return -1; 239 | } 240 | rocksdb::DB* db; 241 | rocksdb::Options options; 242 | options.create_if_missing = true; 243 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 244 | RaftMeta *raft_meta = new RaftMeta(db, logger); 245 | raft_meta->Init(); 246 | RaftLog *raft_log = new RaftLog(db, logger); 247 | 248 | std::vector entries; 249 | Entry *entry = new Entry(); 250 | InitEntry(1, "1", "1", entry); 251 | entries.push_back(entry); 252 | 253 | entry = new Entry(); 254 | InitEntry(1, "2", "2", entry); 255 | entries.push_back(entry); 256 | 257 | entry = new Entry(); 258 | InitEntry(1, "3", "3", entry); 259 | entries.push_back(entry); 260 | 261 | entry = new Entry(); 262 | InitEntry(4, "4", "4", entry); 263 | entries.push_back(entry); 264 | 265 | entry = new Entry(); 266 | InitEntry(4, "5", "5", entry); 267 | entries.push_back(entry); 268 | 269 | entry = new Entry(); 270 | InitEntry(4, "6", "6", entry); 271 | entries.push_back(entry); 272 | 273 | entry = new Entry(); 274 | InitEntry(4, "7", "7", entry); 275 | entries.push_back(entry); 276 | 277 | raft_log->Append(entries); 278 | raft_meta->SetCurrentTerm(4); 279 | raft_meta->SetCommitIndex(3); 280 | raft_meta->SetLastApplied(0); 281 | 282 | delete raft_meta; 283 | delete raft_log; 284 | delete db; 285 | delete logger; 286 | } 287 | 288 | int cl5(const std::string path) { 289 | // construct data1 node 290 | Logger *logger; 291 | slash::CreatePath(path); 292 | if (NewLogger(path + "/LOG", &logger) != 0) { 293 | return -1; 294 | } 295 | rocksdb::DB* db; 296 | rocksdb::Options options; 297 | options.create_if_missing = true; 298 | rocksdb::Status s = rocksdb::DB::Open(options, path + "/log/", &db); 299 | RaftMeta *raft_meta = new RaftMeta(db, logger); 300 | raft_meta->Init(); 301 | RaftLog *raft_log = new RaftLog(db, logger); 302 | 303 | std::vector entries; 304 | Entry *entry = new Entry(); 305 | InitEntry(1, "1", "1", entry); 306 | entries.push_back(entry); 307 | 308 | entry = new Entry(); 309 | InitEntry(1, "2", "2", entry); 310 | entries.push_back(entry); 311 | 312 | entry = new Entry(); 313 | InitEntry(1, "3", "3", entry); 314 | entries.push_back(entry); 315 | 316 | entry = new Entry(); 317 | InitEntry(2, "4", "4", entry); 318 | entries.push_back(entry); 319 | 320 | entry = new Entry(); 321 | InitEntry(2, "5", "5", entry); 322 | entries.push_back(entry); 323 | 324 | entry = new Entry(); 325 | InitEntry(2, "6", "6", entry); 326 | entries.push_back(entry); 327 | 328 | entry = new Entry(); 329 | InitEntry(3, "7", "7", entry); 330 | entries.push_back(entry); 331 | 332 | entry = new Entry(); 333 | InitEntry(3, "8", "8", entry); 334 | entries.push_back(entry); 335 | 336 | entry = new Entry(); 337 | InitEntry(3, "9", "9", entry); 338 | entries.push_back(entry); 339 | 340 | entry = new Entry(); 341 | InitEntry(3, "10", "10", entry); 342 | entries.push_back(entry); 343 | 344 | entry = new Entry(); 345 | InitEntry(3, "11", "11", entry); 346 | entries.push_back(entry); 347 | 348 | raft_log->Append(entries); 349 | raft_meta->SetCurrentTerm(3); 350 | raft_meta->SetCommitIndex(3); 351 | raft_meta->SetLastApplied(0); 352 | 353 | delete raft_meta; 354 | delete raft_log; 355 | delete db; 356 | delete logger; 357 | } 358 | 359 | int main() 360 | { 361 | 362 | cl1("./data1/"); 363 | cl2("./data2/"); 364 | cl3("./data3/"); 365 | cl4("./data4/"); 366 | cl5("./data5/"); 367 | 368 | return 0; 369 | } 370 | -------------------------------------------------------------------------------- /floyd/tools/cpt.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "rocksdb/db.h" 4 | 5 | using namespace rocksdb; 6 | 7 | int main(int argc, char** argv) 8 | { 9 | rocksdb::DB *db1, *db2; 10 | rocksdb::Options options; 11 | if (argc < 3) { 12 | printf("need three parameter\n"); 13 | return -1; 14 | } 15 | std::cout << argv[1] << " " << argv[2] << std::endl; 16 | rocksdb::Status s1 = rocksdb::DB::OpenForReadOnly(options, argv[1], &db1); 17 | rocksdb::Status s2 = rocksdb::DB::OpenForReadOnly(options, argv[2], &db2); 18 | if (!s1.ok() || !s2.ok()) { 19 | printf("failed, open db error\n"); 20 | return -1; 21 | } 22 | 23 | rocksdb::Iterator* iter1 = db1->NewIterator(rocksdb::ReadOptions()); 24 | rocksdb::Iterator* iter2 = db2->NewIterator(rocksdb::ReadOptions()); 25 | iter1->SeekToFirst(); 26 | iter2->SeekToFirst(); 27 | if (!iter1->Valid() || !iter2->Valid()) { 28 | printf("failed, newiterator error\n"); 29 | return -1; 30 | } 31 | 32 | while (iter1->Valid() && iter2->Valid()) { 33 | if (iter1->key() != iter2->key() || iter1->value() != iter2->value()) { 34 | printf("failed, two rocksdb data not the same\n"); 35 | return -1; 36 | } 37 | iter1->Next(); 38 | iter2->Next(); 39 | } 40 | if (iter1->Valid() || iter2->Valid()) { 41 | printf("failed, two rocksdb data not the same\n"); 42 | return -1; 43 | } 44 | printf("success, two rocksdb data are same\n"); 45 | delete iter2; 46 | delete iter1; 47 | delete db2; 48 | delete db1; 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /floyd/tools/read_floyd.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "rocksdb/db.h" 7 | #include "floyd/src/floyd.pb.h" 8 | #include 9 | 10 | using namespace rocksdb; 11 | extern std::string UintToBitStr(const uint64_t num) { 12 | char buf[8]; 13 | uint64_t num1 = htobe64(num); 14 | memcpy(buf, &num1, sizeof(uint64_t)); 15 | return std::string(buf, 8); 16 | } 17 | 18 | extern uint64_t BitStrToUint(const std::string &str) { 19 | uint64_t num; 20 | memcpy(&num, str.c_str(), sizeof(uint64_t)); 21 | return be64toh(num); 22 | } 23 | 24 | int main(int argc, char** argv) 25 | { 26 | rocksdb::DB* db; 27 | rocksdb::Options options; 28 | std::cout << argv[1] << std::endl; 29 | rocksdb::Status s = rocksdb::DB::OpenForReadOnly(options, argv[1], &db); 30 | rocksdb::Iterator* iter = db->NewIterator(rocksdb::ReadOptions()); 31 | char c; 32 | bool is_meta = false; 33 | int index = 0; 34 | floyd::Entry entry; 35 | while ((c = getopt(argc, argv, "mi:")) != EOF) { 36 | switch (c) { 37 | case 'm': 38 | is_meta = true; 39 | break; 40 | case 'i': 41 | index = atoi(optarg); 42 | } 43 | } 44 | if (is_meta) { 45 | iter->SeekToLast(); 46 | for (int i = 0; i < 5; i++) { 47 | if (iter->key().ToString() == "VOTEFORIP") { 48 | printf("key %s, value %s\n", iter->key().ToString().c_str(), iter->value().ToString().c_str()); 49 | } else { 50 | uint64_t ans; 51 | memcpy(&ans, iter->value().data(), sizeof(uint64_t)); 52 | printf("key %s, value %lu\n", iter->key().ToString().c_str(), ans); 53 | } 54 | iter->Prev(); 55 | } 56 | return 0; 57 | } 58 | if (index) { 59 | std::string val; 60 | rocksdb::Status s = db->Get(rocksdb::ReadOptions(), UintToBitStr(uint64_t(index)), &val); 61 | if (s.IsNotFound()) { 62 | printf("key %d not found\n", index); 63 | } else { 64 | entry.ParseFromString(val); 65 | printf("index %d entry term: %lu key %s value %s\n", index, entry.term(), entry.key().c_str(), entry.value().c_str()); 66 | } 67 | return 0; 68 | } 69 | int cnt = 0; 70 | for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { 71 | cnt++; 72 | if (iter->key().ToString() == "CURRENTTERM" || iter->key().ToString() == "VOTEFORIP" || iter->key().ToString() == "VOTEFORPORT" || iter->key().ToString() == "APPLYINDEX" || iter->key().ToString() == "COMMITINDEX" || iter->key().ToString() == "FENCINGTOKEN") { 73 | if (iter->key().ToString() == "VOTEFORIP") { 74 | printf("key %s, value %s\n", iter->key().ToString().c_str(), iter->value().ToString().c_str()); 75 | } else { 76 | uint64_t ans; 77 | memcpy(&ans, iter->value().data(), sizeof(uint64_t)); 78 | printf("key %s, value %lu\n", iter->key().ToString().c_str(), ans); 79 | } 80 | } else { 81 | entry.ParseFromString(iter->value().ToString()); 82 | uint64_t num = BitStrToUint(iter->key().ToString()); 83 | if (entry.optype() == floyd::Entry_OpType_kTryLock) { 84 | printf("index %lu entry type: trylock term: %lu name: %s holder %s\n", num, entry.term(), entry.key().c_str(), entry.holder().c_str()); 85 | } else if (entry.optype() == floyd::Entry_OpType_kUnLock) { 86 | printf("index %lu entry type: unlock term: %lu name: %s holder %s\n", num, entry.term(), entry.key().c_str(), entry.holder().c_str()); 87 | } else if (entry.optype() == floyd::Entry_OpType_kAddServer) { 88 | printf("index %lu entry type: addserver new_server: %s\n", num, entry.new_server().c_str()); 89 | } else { 90 | printf("index %lu entry type: %d term: %lu key %s value %s\n", num, entry.optype(), entry.term(), entry.key().c_str(), entry.value().c_str()); 91 | } 92 | } 93 | // std::cout << "res " << iter->key().ToString() << ": " << iter->value().ToString() << std::endl; 94 | } 95 | printf("cnt %d\n", cnt); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /floyd/tools/read_rock.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "rocksdb/db.h" 6 | 7 | using namespace rocksdb; 8 | 9 | int main(int argc, char** argv) 10 | { 11 | rocksdb::DB* db; 12 | rocksdb::Options options; 13 | std::cout << argv[1] << std::endl; 14 | rocksdb::Status s = rocksdb::DB::OpenForReadOnly(options, argv[1], &db); 15 | rocksdb::Iterator* iter = db->NewIterator(rocksdb::ReadOptions()); 16 | char c; 17 | int index = 0; 18 | std::string key = ""; 19 | while ((c = getopt(argc, argv, "i:")) != EOF) { 20 | switch (c) { 21 | case 'i': 22 | key = std::string(optarg, strlen(optarg)); 23 | break; 24 | } 25 | } 26 | if (key != "") { 27 | std::string val; 28 | rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key, &val); 29 | if (s.IsNotFound()) { 30 | printf("key %s not found\n", key.c_str()); 31 | } else { 32 | printf("key %s, val %s\n", key.c_str(), val.c_str()); 33 | } 34 | return 0; 35 | } 36 | int cnt = 0; 37 | for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { 38 | cnt++; 39 | std::cout << "key " << iter->key().ToString() << "; val " << iter->value().ToString() << std::endl; 40 | } 41 | printf("cnt %d\n", cnt); 42 | return 0; 43 | } 44 | --------------------------------------------------------------------------------