ZooKeeperQuorumServer.cc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with this
  4. * work for additional information regarding copyright ownership. The ASF
  5. * licenses this file to you under the Apache License, Version 2.0 (the
  6. * "License"); you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  13. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  14. * License for the specific language governing permissions and limitations under
  15. * the License.
  16. */
  17. #include "ZooKeeperQuorumServer.h"
  18. #include <cassert>
  19. #include <cstdio>
  20. #include <cstdlib>
  21. #include <fstream>
  22. #include <sstream>
  23. #include <vector>
  24. #include <utility>
  25. #include <unistd.h>
  26. ZooKeeperQuorumServer::
  27. ZooKeeperQuorumServer(uint32_t id, uint32_t numServers, std::string config, std::string env) :
  28. id_(id),
  29. env_(env),
  30. numServers_(numServers) {
  31. const char* root = getenv("ZKROOT");
  32. if (root == NULL) {
  33. assert(!"Environment variable 'ZKROOT' is not set");
  34. }
  35. root_ = root;
  36. createConfigFile(config);
  37. createDataDirectory();
  38. start();
  39. }
  40. ZooKeeperQuorumServer::
  41. ~ZooKeeperQuorumServer() {
  42. stop();
  43. }
  44. std::string ZooKeeperQuorumServer::
  45. getHostPort() {
  46. std::stringstream ss;
  47. ss << "localhost:" << getClientPort();
  48. return ss.str();
  49. }
  50. uint32_t ZooKeeperQuorumServer::
  51. getClientPort() {
  52. return CLIENT_PORT_BASE + id_;
  53. }
  54. void ZooKeeperQuorumServer::
  55. start() {
  56. std::string command = root_ + "/bin/zkServer.sh start " +
  57. getConfigFileName();
  58. if (!env_.empty()) {
  59. command = env_ + " " + command;
  60. }
  61. assert(system(command.c_str()) == 0);
  62. }
  63. void ZooKeeperQuorumServer::
  64. stop() {
  65. std::string command = root_ + "/bin/zkServer.sh stop " +
  66. getConfigFileName();
  67. assert(system(command.c_str()) == 0);
  68. }
  69. std::string ZooKeeperQuorumServer::
  70. getMode() {
  71. char buf[1024];
  72. std::string result;
  73. std::string command = root_ + "/bin/zkServer.sh status " +
  74. getConfigFileName();
  75. FILE* output = popen(command.c_str(), "r");
  76. do {
  77. if (fgets(buf, 1024, output) != NULL) {
  78. result += buf;
  79. }
  80. } while (!feof(output));
  81. pclose(output);
  82. if (result.find("Mode: leader") != std::string::npos) {
  83. return "leader";
  84. } else if (result.find("Mode: follower") != std::string::npos) {
  85. return "follower";
  86. } else {
  87. printf("%s\n", result.c_str());
  88. return "";
  89. }
  90. }
  91. bool ZooKeeperQuorumServer::
  92. isLeader() {
  93. return getMode() == "leader";
  94. }
  95. bool ZooKeeperQuorumServer::
  96. isFollower() {
  97. return getMode() == "follower";
  98. }
  99. void ZooKeeperQuorumServer::
  100. createConfigFile(std::string config) {
  101. std::string command = "mkdir -p " + root_ + "/build/test/test-cppunit/conf";
  102. assert(system(command.c_str()) == 0);
  103. std::ofstream confFile;
  104. std::stringstream ss;
  105. ss << id_ << ".conf";
  106. std::string fileName = root_ + "/build/test/test-cppunit/conf/" + ss.str();
  107. confFile.open(fileName.c_str());
  108. confFile << "tickTime=2000\n";
  109. confFile << "clientPort=" << getClientPort() << "\n";
  110. confFile << "initLimit=5\n";
  111. confFile << "syncLimit=2\n";
  112. confFile << "dataDir=" << getDataDirectory() << "\n";
  113. for (uint32_t i = 0; i < numServers_; i++) {
  114. confFile << getServerString(i) << "\n";
  115. }
  116. // Append additional config, if any.
  117. if (!config.empty()) {
  118. confFile << config << std::endl;
  119. }
  120. confFile.close();
  121. }
  122. std::string ZooKeeperQuorumServer::
  123. getConfigFileName() {
  124. std::stringstream ss;
  125. ss << id_ << ".conf";
  126. return root_ + "/build/test/test-cppunit/conf/" + ss.str();
  127. }
  128. void ZooKeeperQuorumServer::
  129. createDataDirectory() {
  130. std::string dataDirectory = getDataDirectory();
  131. std::string command = "rm -rf " + dataDirectory;
  132. assert(system(command.c_str()) == 0);
  133. command = "mkdir -p " + dataDirectory;
  134. assert(system(command.c_str()) == 0);
  135. std::ofstream myidFile;
  136. std::string fileName = dataDirectory + "/myid";
  137. myidFile.open(fileName.c_str());
  138. myidFile << id_ << "\n";
  139. myidFile.close();
  140. setenv("ZOO_LOG_DIR", dataDirectory.c_str(), true);
  141. }
  142. std::string ZooKeeperQuorumServer::
  143. getServerString() {
  144. return getServerString(id_);
  145. }
  146. std::string ZooKeeperQuorumServer::
  147. getServerString(uint32_t id) {
  148. std::stringstream ss;
  149. ss << "server." << id << "=localhost:" << SERVER_PORT_BASE + id <<
  150. ":" << ELECTION_PORT_BASE + id << ":participant;localhost:" <<
  151. CLIENT_PORT_BASE + id;
  152. return ss.str();
  153. }
  154. std::string ZooKeeperQuorumServer::
  155. getDataDirectory() {
  156. std::stringstream ss;
  157. ss << "data" << id_;
  158. return root_ + "/build/test/test-cppunit/" + ss.str();
  159. }
  160. std::vector<ZooKeeperQuorumServer*> ZooKeeperQuorumServer::
  161. getCluster(uint32_t numServers) {
  162. std::vector<ZooKeeperQuorumServer*> cluster;
  163. for (uint32_t i = 0; i < numServers; i++) {
  164. cluster.push_back(new ZooKeeperQuorumServer(i, numServers));
  165. }
  166. // Wait until all the servers start, and fail if they don't start within 10
  167. // seconds.
  168. for (uint32_t i = 0; i < 10; i++) {
  169. uint32_t j = 0;
  170. for (; j < cluster.size(); j++) {
  171. if (cluster[j]->getMode() == "") {
  172. // The server hasn't started.
  173. sleep(1);
  174. break;
  175. }
  176. }
  177. if (j == cluster.size()) {
  178. return cluster;
  179. }
  180. }
  181. assert(!"The cluster didn't start for 10 seconds");
  182. return {};
  183. }
  184. std::vector<ZooKeeperQuorumServer*> ZooKeeperQuorumServer::
  185. getCluster(uint32_t numServers, ZooKeeperQuorumServer::tConfigPairs configs, std::string env) {
  186. std::vector<ZooKeeperQuorumServer*> cluster;
  187. std::string config;
  188. for (ZooKeeperQuorumServer::tConfigPairs::const_iterator iter = configs.begin(); iter != configs.end(); ++iter) {
  189. std::pair<std::string, std::string> pair = *iter;
  190. config += (pair.first + "=" + pair.second + "\n");
  191. }
  192. for (uint32_t i = 0; i < numServers; i++) {
  193. cluster.push_back(new ZooKeeperQuorumServer(i, numServers, config, env));
  194. }
  195. // Wait until all the servers start, and fail if they don't start within 10
  196. // seconds.
  197. for (uint32_t i = 0; i < 10; i++) {
  198. uint32_t j = 0;
  199. for (; j < cluster.size(); j++) {
  200. if (cluster[j]->getMode() == "") {
  201. // The server hasn't started.
  202. sleep(1);
  203. break;
  204. }
  205. }
  206. if (j == cluster.size()) {
  207. return cluster;
  208. }
  209. }
  210. assert(!"The cluster didn't start for 10 seconds");
  211. }