memdbcluster 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #!/usr/bin/env node
  2. // Copyright 2015 The MemDB Authors.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  13. // implied. See the License for the specific language governing
  14. // permissions and limitations under the License. See the AUTHORS file
  15. // for names of contributors.
  16. 'use strict';
  17. var minimist = require('minimist');
  18. var P = require('bluebird');
  19. var path = require('path');
  20. var util = require('util');
  21. var utils = require('../app/utils');
  22. var helpContent = '\
  23. MemDB - Distributed transactional in memory database\n\n\
  24. Usage: memdbcluster [command] [options]\n\n\
  25. Commands:\n\
  26. start Start cluster\n\
  27. stop Stop cluster\n\
  28. status Show cluster status\n\
  29. drop Drop all data in cluster\n\n\
  30. Options:\n\
  31. -c, --conf path Config file path\n\
  32. -s, --shard shardId Operate on specific shard only\n\
  33. -h, --help Display this help\n\n\
  34. WARN: Make sure memdb is installed using the same folder and same config on all servers\n';
  35. var start = function(confPath, shardConfig){
  36. var memdbd = path.join(__dirname, 'memdbd');
  37. var nodePath = process.execPath;
  38. var cmd = util.format('%s %s --conf=%s --shard=%s --daemon', nodePath, memdbd, confPath || '', shardConfig.shardId);
  39. return utils.remoteExec(shardConfig.host, cmd, {user : shardConfig.user});
  40. };
  41. var stop = function(shardConfig){
  42. var cmd = 'PID=`lsof -i:%s -sTCP:LISTEN -t`;\
  43. if [ $PID ]; then\
  44. kill $PID;\
  45. while ps -p $PID > /dev/null; do\
  46. sleep 0.2;\
  47. done;\
  48. fi';
  49. if (process.platform == 'win32') {
  50. cmd = "taskkill -f -pid $(netstat -ano | findstr :%s.*LISTENING | awk '{print $5}') 2>/dev/null; exit 0";
  51. }
  52. cmd = util.format(cmd, shardConfig.port);
  53. return utils.remoteExec(shardConfig.host, cmd, {user : shardConfig.user});
  54. };
  55. var mongodb = null;
  56. var drop = function(backendConf){
  57. if(!backendConf){
  58. throw new Error('global backend config not found');
  59. }
  60. if(!mongodb){
  61. mongodb = P.promisifyAll(require('mongodb'));
  62. }
  63. return P.promisify(mongodb.MongoClient.connect)(backendConf.url)
  64. .then(function(db){
  65. return db.dropDatabaseAsync()
  66. .then(function(){
  67. return db.closeAsync();
  68. });
  69. });
  70. };
  71. var backendLocker = null;
  72. var getActiveShards = function(lockingConf){
  73. if(!lockingConf){
  74. throw new Error('global locking config not found');
  75. }
  76. if(!backendLocker){
  77. backendLocker = require('../app/backendlocker');
  78. }
  79. var bl = new backendLocker(lockingConf);
  80. return P.try(function(){
  81. return bl.start();
  82. })
  83. .then(function(){
  84. return bl.getActiveShards();
  85. })
  86. .then(function(ret){
  87. bl.stop();
  88. return ret;
  89. });
  90. };
  91. if (require.main === module) {
  92. var argv = minimist(process.argv.slice(2));
  93. var cmd = process.argv[2];
  94. if(process.argv.length <= 2 || argv.help || argv.h){
  95. console.log(helpContent);
  96. process.exit(0);
  97. }
  98. var confPath = argv.conf || argv.c;
  99. if(confPath){
  100. confPath = path.resolve(confPath);
  101. }
  102. var config = require('../app/config');
  103. config.init(confPath);
  104. var shardIds = argv.shard || argv.s;
  105. if(!shardIds){
  106. shardIds = config.getShardIds();
  107. }
  108. else if(!Array.isArray(shardIds)){
  109. shardIds = [shardIds];
  110. }
  111. // prevent from exit
  112. process.on('SIGTERM', function(){});
  113. process.on('SIGINT', function(){});
  114. P.try(function(){
  115. if(cmd === 'start'){
  116. return P.map(shardIds, function(shardId){
  117. var shardConfig = config.shardConfig(shardId);
  118. console.log('starting %s on %s:%s...', shardId, shardConfig.host, shardConfig.port);
  119. return start(confPath, shardConfig)
  120. .then(function(){
  121. console.log('%s started', shardId);
  122. }, function(e){
  123. console.error(e.stack);
  124. });
  125. });
  126. }
  127. else if(cmd === 'stop'){
  128. return P.map(shardIds, function(shardId){
  129. var shardConfig = config.shardConfig(shardId);
  130. console.log('stopping %s on %s:%s...', shardConfig.shardId, shardConfig.host, shardConfig.port);
  131. return stop(shardConfig)
  132. .then(function(){
  133. console.log('%s stoped', shardId);
  134. }, function(e){
  135. console.error(e.stack);
  136. });
  137. });
  138. }
  139. else if(cmd === 'status'){
  140. var clusterConfig = config.clusterConfig();
  141. console.log('config: %s', config.path);
  142. console.log('backend: %s', clusterConfig.backend.url);
  143. console.log('locking: %s:%s:%s', clusterConfig.locking.host, clusterConfig.locking.port, clusterConfig.locking.db);
  144. console.log('shards:');
  145. return getActiveShards(clusterConfig.locking)
  146. .then(function(activeShardIds){
  147. shardIds.forEach(function(shardId){
  148. var shardConfig = config.shardConfig(shardId);
  149. var display = activeShardIds.indexOf(shardId) !== -1 ? 'running' : 'down';
  150. console.log('%s (%s:%s)\t%s', shardId, shardConfig.host, shardConfig.port, display);
  151. });
  152. });
  153. }
  154. else if(cmd === 'drop'){
  155. return getActiveShards(config.clusterConfig().locking)
  156. .then(function(activeShardIds){
  157. if(activeShardIds.length > 0){
  158. throw new Error('please stop all shards first');
  159. }
  160. return drop(config.clusterConfig().backend)
  161. .then(function(){
  162. console.log('all data has been droped');
  163. });
  164. });
  165. }
  166. else{
  167. throw new Error('invalid command - ' + cmd);
  168. }
  169. })
  170. .catch(function(e){
  171. console.error(e.stack);
  172. process.exit(1);
  173. })
  174. .finally(process.exit);
  175. }