SSDB源码版本:1.9.0
SSDB启动:
SSDB启动代码在ssdb-server.cpp中,启动代码如下:
-
int main(int argc, char **argv){
-
MyApplication app;
-
return app.main(argc, argv);
-
}
实际上是调用MyApplication的main函数完成,
MyApplication(继承自Application),Application作为基类实现了服务端的通用功能。
Application类
Application类的头文件和实现文件都放在util目录下,分别为app.h和app.cpp,它实现的功能主要有:解析命令行参数,解析配置文件,记录服务器进程pid,利用信号杀死服务器进程,定义接口由派生类实现。
-
class Application{
-
public:
-
Application(){};
-
virtual ~Application(){};
-
// 通用启动流程
-
int main(int argc, char **argv);
-
-
// 输出帮助
-
virtual void usage(int argc, char **argv);
-
-
// 输出欢迎信息
-
virtual void welcome() = 0;
-
-
// 具体的启动流程
-
virtual void run() = 0;
-
-
protected:
-
// 程序配置参数
-
struct AppArgs{
-
// 是否以守护进程启动
-
bool is_daemon;
-
std::string pidfile;
-
std::string conf_file;
-
std::string work_dir;
-
std::string start_opt;
-
-
AppArgs(){
-
is_daemon = false;
-
start_opt = "start";
-
}
-
};
-
-
Config *conf;
-
AppArgs app_args;
-
-
private:
-
// 解析命令行参数
-
void parse_args(int argc, char **argv);
-
void init();
-
-
int read_pid();
-
void write_pid();
-
void check_pidfile();
-
void remove_pidfile();
-
void kill_process();
-
};
main函数中定义了通用的启动流程:
-
int Application::main(int argc, char **argv){
-
conf = NULL;
-
-
welcome();
-
parse_args(argc, argv);
-
// init函数完成整个初始化流程
-
init();
-
-
write_pid();
-
// 调用派生类实现的run函数启动具体功能
-
run();
-
-
// 进程退出时会删除pidfile
-
remove_pidfile();
-
-
delete conf;
-
return 0;
-
}
Application类中最重要的函数就是init,它完成了整个初始化流程:
1. 导入配置文件(配置文件路径通过parse_args解析命令行参数获得)
2. 根据配置的目录,修改当前进程的工作目录
3. 如果参数为"restart"或"stop",则重启或终止服务进程,重启服务进程就是杀死已经存在服务进程然后继续执行,然后当前进程成为新的服务进程。
4. 检查是否存在保存pid的文件,如果存在,则说明服务进程还在运行(杀死服务进程会删除pid 文件),当前进程异常退出。
5. 打开记录日志。
6. 根据daemon参数判断是否需要变成守护进程(
注意:这一步必须在创建任何线程之前执行)。
-
void Application::init(){
-
if(!is_file(app_args.conf_file.c_str())){
-
fprintf(stderr, "'%s' is not a file or not exists!\n", app_args.conf_file.c_str());
-
exit(1);
-
}
-
// 导入配置文件
-
conf = Config::load(app_args.conf_file.c_str());
-
if(!conf){
-
fprintf(stderr, "error loading conf file: '%s'\n", app_args.conf_file.c_str());
-
exit(1);
-
}
-
{
-
//获取配置文件路径,然后修改当前工作目录为配置文件目录
-
std::string conf_dir = real_dirname(app_args.conf_file.c_str());
-
if(chdir(conf_dir.c_str()) == -1){
-
fprintf(stderr, "error chdir: %s\n", conf_dir.c_str());
-
exit(1);
-
}
-
}
-
-
// 获取配置的pidfile文件路径
-
app_args.pidfile = conf->get_str("pidfile");
-
-
// 如果参数为stop,则杀死服务进程,然后自己退出
-
if(app_args.start_opt == "stop"){
-
kill_process();
-
exit(0);
-
}
-
-
// 如果参数为restart,则杀死服务进程,自己继续执行
-
if(app_args.start_opt == "restart"){
-
if(file_exists(app_args.pidfile)){
-
kill_process();
-
}
-
}
-
-
// 检查pid文件是否存在,判断服务进程是否被杀死
-
check_pidfile();
-
-
// 根据日志配置打开日志功能
-
{ // logger
-
std::string log_output;
-
std::string log_level_;
-
int64_t log_rotate_size;
-
-
log_level_ = conf->get_str("logger.level");
-
strtolower(&log_level_);
-
if(log_level_.empty()){
-
log_level_ = "debug";
-
}
-
int level = Logger::get_level(log_level_.c_str());
-
log_rotate_size = conf->get_int64("logger.rotate.size");
-
log_output = conf->get_str("logger.output");
-
if(log_output == ""){
-
log_output = "stdout";
-
}
-
if(log_open(log_output.c_str(), level, true, log_rotate_size) == -1){
-
fprintf(stderr, "error opening log file: %s\n", log_output.c_str());
-
exit(1);
-
}
-
}
-
-
app_args.work_dir = conf->get_str("work_dir");
-
if(app_args.work_dir.empty()){
-
app_args.work_dir = ".";
-
}
-
if(!is_dir(app_args.work_dir.c_str())){
-
fprintf(stderr, "'%s' is not a directory or not exists!\n", app_args.work_dir.c_str());
-
exit(1);
-
}
-
-
// 守护进程化
-
// deamonize() MUST be called before any thread is
-
if(app_args.is_daemon){
-
daemonize();
-
}
-
}
利用kill_process杀死服务进程的流程:发送SIGTERM信号,服务进程在收到SIGTERM信号后会调用注册的signal_handle,然后将quit置为true,最后退出事件循环。
-
void Application::kill_process(){
-
// 从pid_file中读取正在运行的APP的pid
-
int pid = read_pid();
-
if(pid == -1){
-
fprintf(stderr, "could not read pidfile: %s(%s)\n", app_args.pidfile.c_str(), strerror(errno));
-
exit(1);
-
}
-
-
// 检查进程是否存在
-
if(kill(pid, 0) == -1 && errno == ESRCH){
-
fprintf(stderr, "process: %d not running\n", pid);
-
remove_pidfile();
-
return;
-
}
-
// server在收到SIGTERM信号会结束事件循环,见\src\net\server.cpp 中signal_handler函数
-
// 结束事件循环导致Application::main函数中调用的run函数退出,然后remove_pidfile删除文件
-
int ret = kill(pid, SIGTERM);
-
if(ret == -1){
-
fprintf(stderr, "could not kill process: %d(%s)\n", pid, strerror(errno));
-
exit(1);
-
}
-
-
// 如果pidfile还存在,说明被杀死的服务进程还没有退出,继续等待。
-
while(file_exists(app_args.pidfile)){
-
usleep(100 * 1000);
-
}
-
}
-
void signal_handler(int sig){
-
switch(sig){
-
case SIGTERM:
-
case SIGINT:{
-
quit = true;
-
break;
-
}
-
case SIGALRM:{
-
g_ticks ++;
-
break;
-
}
-
}
-
}
NetworkServer::serve()函数会在事件循环中检测quit变量,发现为true则退出。
MyApplication类
MyApplication类主要实现了run函数用来执行具体的操作:
1. 打开数据库文件(ssdb的底层存储基于leveldb)
2.打开数据库元数据文件
3.创建网络服务对象NetworkServer并调用serve函数启动事件循环,serve函数在收到SIGTERM,SIGINT信号时会退出
-
oid MyApplication::run(){
-
Options option;
-
option.load(*conf);
-
-
std::string data_db_dir = app_args.work_dir + "/data";
-
std::string meta_db_dir = app_args.work_dir + "/meta";
-
-
log_info("ssdb-server %s", APP_VERSION);
-
log_info("conf_file : %s", app_args.conf_file.c_str());
-
log_info("log_level : %s", Logger::shared()->level_name().c_str());
-
log_info("log_output : %s", Logger::shared()->output_name().c_str());
-
log_info("log_rotate_size : %" PRId64, Logger::shared()->rotate_size());
-
-
log_info("main_db : %s", data_db_dir.c_str());
-
log_info("meta_db : %s", meta_db_dir.c_str());
-
log_info("cache_size : %d MB", option.cache_size);
-
log_info("block_size : %d KB", option.block_size);
-
log_info("write_buffer : %d MB", option.write_buffer_size);
-
log_info("max_open_files : %d", option.max_open_files);
-
log_info("compaction_speed : %d MB/s", option.compaction_speed);
-
log_info("compression : %s", option.compression.c_str());
-
log_info("binlog : %s", option.binlog? "yes" : "no");
-
log_info("sync_speed : %d MB/s", conf->get_num("replication.sync_speed"));
-
-
SSDB *data_db = NULL;
-
SSDB *meta_db = NULL;
-
// 打开数据文件
-
data_db = SSDB::open(option, data_db_dir);
-
if(!data_db){
-
log_fatal("could not open data db: %s", data_db_dir.c_str());
-
fprintf(stderr, "could not open data db: %s\n", data_db_dir.c_str());
-
exit(1);
-
}
-
-
// 打开元数据文件
-
meta_db = SSDB::open(Options(), meta_db_dir);
-
if(!meta_db){
-
log_fatal("could not open meta db: %s", meta_db_dir.c_str());
-
fprintf(stderr, "could not open meta db: %s\n", meta_db_dir.c_str());
-
exit(1);
-
}
-
-
// 启动网络服务
-
NetworkServer *net = NULL;
-
SSDBServer *server;
-
net = NetworkServer::init(*conf);
-
server = new SSDBServer(data_db, meta_db, *conf, net);
-
-
log_info("pidfile: %s, pid: %d", app_args.pidfile.c_str(), (int)getpid());
-
log_info("ssdb server started.");
-
net->serve();
-
-
delete net;
-
delete server;
-
delete meta_db;
-
delete data_db;
-
-
log_info("%s exit.", APP_NAME);
-
}
阅读(2571) | 评论(0) | 转发(0) |