Chinaunix首页 | 论坛 | 博客
  • 博客访问: 87337
  • 博文数量: 12
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 200
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-23 09:57
文章分类

全部博文(12)

文章存档

2015年(11)

2014年(1)

我的朋友

分类: 服务器与存储

2015-05-09 14:21:57

SSDB源码版本:1.9.0  

SSDB启动:

SSDB启动代码在ssdb-server.cpp中,启动代码如下:

点击(此处)折叠或打开

  1. int main(int argc, char **argv){
  2.     MyApplication app;
  3.     return app.main(argc, argv);
  4. }
实际上是调用MyApplication的main函数完成,MyApplication(继承自Application),Application作为基类实现了服务端的通用功能。

Application类

Application类的头文件和实现文件都放在util目录下,分别为app.h和app.cpp,它实现的功能主要有:解析命令行参数,解析配置文件,记录服务器进程pid,利用信号杀死服务器进程,定义接口由派生类实现。

    

点击(此处)折叠或打开

  1. class Application{
  2. public:
  3.     Application(){};
  4.     virtual ~Application(){};
  5.     // 通用启动流程
  6.     int main(int argc, char **argv);

  7.     // 输出帮助
  8.     virtual void usage(int argc, char **argv);

  9.     // 输出欢迎信息
  10.     virtual void welcome() = 0;

  11.     // 具体的启动流程
  12.     virtual void run() = 0;

  13. protected:
  14.     // 程序配置参数
  15.     struct AppArgs{
  16.         // 是否以守护进程启动
  17.         bool is_daemon;
  18.         std::string pidfile;
  19.         std::string conf_file;
  20.         std::string work_dir;
  21.         std::string start_opt;

  22.         AppArgs(){
  23.             is_daemon = false;
  24.             start_opt = "start";
  25.         }
  26.     };

  27.     Config *conf;
  28.     AppArgs app_args;
  29.     
  30. private:
  31.     // 解析命令行参数
  32.     void parse_args(int argc, char **argv);
  33.     void init();

  34.     int read_pid();
  35.     void write_pid();
  36.     void check_pidfile();
  37.     void remove_pidfile();
  38.     void kill_process();
  39. };   
   
 main函数中定义了通用的启动流程:
         

点击(此处)折叠或打开

  1. int Application::main(int argc, char **argv){
  2.     conf = NULL;

  3.     welcome();
  4.     parse_args(argc, argv);
  5.     // init函数完成整个初始化流程
  6.     init();

  7.     write_pid();
  8.     // 调用派生类实现的run函数启动具体功能
  9.     run();
  10.     
  11.     // 进程退出时会删除pidfile
  12.     remove_pidfile();
  13.     
  14.     delete conf;
  15.     return 0;
  16. }

Application类中最重要的函数就是init,它完成了整个初始化流程:
    1. 导入配置文件(配置文件路径通过parse_args解析命令行参数获得)
    2. 根据配置的目录,修改当前进程的工作目录
    3. 如果参数为"restart"或"stop",则重启或终止服务进程,重启服务进程就是杀死已经存在服务进程然后继续执行,然后当前进程成为新的服务进程。
    4. 检查是否存在保存pid的文件,如果存在,则说明服务进程还在运行(杀死服务进程会删除pid 文件),当前进程异常退出。
    5. 打开记录日志。
    6. 根据daemon参数判断是否需要变成守护进程(注意:这一步必须在创建任何线程之前执行)。
        

点击(此处)折叠或打开

  1. void Application::init(){
  2.     if(!is_file(app_args.conf_file.c_str())){
  3.         fprintf(stderr, "'%s' is not a file or not exists!\n", app_args.conf_file.c_str());
  4.         exit(1);
  5.     }
  6.     // 导入配置文件
  7.     conf = Config::load(app_args.conf_file.c_str());
  8.     if(!conf){
  9.         fprintf(stderr, "error loading conf file: '%s'\n", app_args.conf_file.c_str());
  10.         exit(1);
  11.     }
  12.     {
  13.         //获取配置文件路径,然后修改当前工作目录为配置文件目录
  14.         std::string conf_dir = real_dirname(app_args.conf_file.c_str());
  15.         if(chdir(conf_dir.c_str()) == -1){
  16.             fprintf(stderr, "error chdir: %s\n", conf_dir.c_str());
  17.             exit(1);
  18.         }
  19.     }
  20.      
  21.     // 获取配置的pidfile文件路径
  22.     app_args.pidfile = conf->get_str("pidfile");
  23.     
  24.     // 如果参数为stop,则杀死服务进程,然后自己退出
  25.     if(app_args.start_opt == "stop"){
  26.         kill_process();
  27.         exit(0);
  28.     }
  29.     
  30.     // 如果参数为restart,则杀死服务进程,自己继续执行
  31.     if(app_args.start_opt == "restart"){
  32.         if(file_exists(app_args.pidfile)){
  33.             kill_process();
  34.         }
  35.     }
  36.     
  37.     // 检查pid文件是否存在,判断服务进程是否被杀死
  38.     check_pidfile();
  39.     
  40.     // 根据日志配置打开日志功能
  41.     { // logger
  42.         std::string log_output;
  43.         std::string log_level_;
  44.         int64_t log_rotate_size;

  45.         log_level_ = conf->get_str("logger.level");
  46.         strtolower(&log_level_);
  47.         if(log_level_.empty()){
  48.             log_level_ = "debug";
  49.         }
  50.         int level = Logger::get_level(log_level_.c_str());
  51.         log_rotate_size = conf->get_int64("logger.rotate.size");
  52.         log_output = conf->get_str("logger.output");
  53.         if(log_output == ""){
  54.             log_output = "stdout";
  55.         }
  56.         if(log_open(log_output.c_str(), level, true, log_rotate_size) == -1){
  57.             fprintf(stderr, "error opening log file: %s\n", log_output.c_str());
  58.             exit(1);
  59.         }
  60.     }

  61.     app_args.work_dir = conf->get_str("work_dir");
  62.     if(app_args.work_dir.empty()){
  63.         app_args.work_dir = ".";
  64.     }
  65.     if(!is_dir(app_args.work_dir.c_str())){
  66.         fprintf(stderr, "'%s' is not a directory or not exists!\n", app_args.work_dir.c_str());
  67.         exit(1);
  68.     }

  69.     // 守护进程化
  70.     // deamonize() MUST be called before any thread is
  71.     if(app_args.is_daemon){
  72.         daemonize();
  73.     }
  74. }
        
利用kill_process杀死服务进程的流程:发送SIGTERM信号,服务进程在收到SIGTERM信号后会调用注册的signal_handle,然后将quit置为true,最后退出事件循环。
            

点击(此处)折叠或打开

  1. void Application::kill_process(){
  2.     // 从pid_file中读取正在运行的APP的pid
  3.     int pid = read_pid();
  4.     if(pid == -1){
  5.         fprintf(stderr, "could not read pidfile: %s(%s)\n", app_args.pidfile.c_str(), strerror(errno));
  6.         exit(1);
  7.     }

  8.     // 检查进程是否存在
  9.     if(kill(pid, 0) == -1 && errno == ESRCH){
  10.         fprintf(stderr, "process: %d not running\n", pid);
  11.         remove_pidfile();
  12.         return;
  13.     }
  14.     // server在收到SIGTERM信号会结束事件循环,见\src\net\server.cpp 中signal_handler函数
  15.     // 结束事件循环导致Application::main函数中调用的run函数退出,然后remove_pidfile删除文件
  16.     int ret = kill(pid, SIGTERM);
  17.     if(ret == -1){
  18.         fprintf(stderr, "could not kill process: %d(%s)\n", pid, strerror(errno));
  19.         exit(1);
  20.     }
  21.     
  22.     // 如果pidfile还存在,说明被杀死的服务进程还没有退出,继续等待。
  23.     while(file_exists(app_args.pidfile)){
  24.         usleep(100 * 1000);
  25.     }
  26. }

点击(此处)折叠或打开

  1. void signal_handler(int sig){
  2.     switch(sig){
  3.         case SIGTERM:
  4.         case SIGINT:{
  5.             quit = true;
  6.             break;
  7.         }
  8.         case SIGALRM:{
  9.             g_ticks ++;
  10.             break;
  11.         }
  12.     }
  13. }

NetworkServer::serve()函数会在事件循环中检测quit变量,发现为true则退出。

        

MyApplication类

MyApplication类主要实现了run函数用来执行具体的操作:

    1. 打开数据库文件(ssdb的底层存储基于leveldb)
    2.打开数据库元数据文件
    3.创建网络服务对象NetworkServer并调用serve函数启动事件循环,serve函数在收到SIGTERM,SIGINT信号时会退出
        

点击(此处)折叠或打开

  1. oid MyApplication::run(){
  2.     Options option;
  3.     option.load(*conf);

  4.     std::string data_db_dir = app_args.work_dir + "/data";
  5.     std::string meta_db_dir = app_args.work_dir + "/meta";

  6.     log_info("ssdb-server %s", APP_VERSION);
  7.     log_info("conf_file : %s", app_args.conf_file.c_str());
  8.     log_info("log_level : %s", Logger::shared()->level_name().c_str());
  9.     log_info("log_output : %s", Logger::shared()->output_name().c_str());
  10.     log_info("log_rotate_size : %" PRId64, Logger::shared()->rotate_size());

  11.     log_info("main_db : %s", data_db_dir.c_str());
  12.     log_info("meta_db : %s", meta_db_dir.c_str());
  13.     log_info("cache_size : %d MB", option.cache_size);
  14.     log_info("block_size : %d KB", option.block_size);
  15.     log_info("write_buffer : %d MB", option.write_buffer_size);
  16.     log_info("max_open_files : %d", option.max_open_files);
  17.     log_info("compaction_speed : %d MB/s", option.compaction_speed);
  18.     log_info("compression : %s", option.compression.c_str());
  19.     log_info("binlog : %s", option.binlog? "yes" : "no");
  20.     log_info("sync_speed : %d MB/s", conf->get_num("replication.sync_speed"));

  21.     SSDB *data_db = NULL;
  22.     SSDB *meta_db = NULL;
  23.     // 打开数据文件
  24.     data_db = SSDB::open(option, data_db_dir);
  25.     if(!data_db){
  26.         log_fatal("could not open data db: %s", data_db_dir.c_str());
  27.         fprintf(stderr, "could not open data db: %s\n", data_db_dir.c_str());
  28.         exit(1);
  29.     }

  30.     // 打开元数据文件
  31.     meta_db = SSDB::open(Options(), meta_db_dir);
  32.     if(!meta_db){
  33.         log_fatal("could not open meta db: %s", meta_db_dir.c_str());
  34.         fprintf(stderr, "could not open meta db: %s\n", meta_db_dir.c_str());
  35.         exit(1);
  36.     }
  37.     
  38.     // 启动网络服务
  39.     NetworkServer *net = NULL;    
  40.     SSDBServer *server;
  41.     net = NetworkServer::init(*conf);
  42.     server = new SSDBServer(data_db, meta_db, *conf, net);
  43.     
  44.     log_info("pidfile: %s, pid: %d", app_args.pidfile.c_str(), (int)getpid());
  45.     log_info("ssdb server started.");
  46.     net->serve();
  47.     
  48.     delete net;
  49.     delete server;
  50.     delete meta_db;
  51.     delete data_db;

  52.     log_info("%s exit.", APP_NAME);
  53. }


 
阅读(2571) | 评论(0) | 转发(0) |
0

上一篇:资料收集

下一篇:SSDB源码分析(2):SSDB

给主人留下些什么吧!~~