十博最佳体育平台「诚|信」

  • <acronym id="khmkt"><label id="khmkt"></label></acronym>

      <table id="khmkt"></table>
        Chinaunix首页 | 论坛 | 博客
        • 博客访问: 3294162
        • 博文数量: 146
        • 博客积分: 3918
        • 博客等级: 少校
        • 技术积分: 8557
        • 用 户 组: 普通用户
        • 注册时间: 2010-10-17 13:52
        个人简介

        个人微薄: weibo.com/manuscola

        文章分类

        全部博文(146)

        文章存档

        2016年(3)

        2015年(2)

        2014年(5)

        2013年(42)

        2012年(31)

        2011年(58)

        2010年(5)

        分类: 服务器与存储

        2015-05-31 02:05:57


        任何一个成熟的项目,必须要提供出接口,就像探针一样,可以让我们探查进程内部的运行情况,进程不能是一个黑盒子。对于ceph而言,Admin Socket 提供了该功能。Admin Socket 不仅可以查看当前的配置,进程运行的状态,而且,还可以修改配置,获取log等。

        下面help可以看出,ceph给出了很多命令,来了解ceph内部的运行情况。
        1. root@test3:~# ceph daemon /var/run/ceph/ceph-osd.4.asok help
        2. { "config get": "config get : get the config value",
        3.   "config set": "config set [ ...]: set a config variable",
        4.   "config show": "dump current config settings",
        5.   "dump_blacklist": "dump blacklisted clients and times",
        6.   "dump_historic_ops": "show slowest recent ops",
        7.   "dump_op_pq_state": "dump op priority queue state",
        8.   "dump_ops_in_flight": "show the ops currently in flight",
        9.   "dump_watchers": "show clients which have active watches, and on which objects",
        10.   "get_command_descriptions": "list available commands",
        11.   "getomap": "output entire object map",
        12.   "git_version": "get git sha1",
        13.   "help": "list available commands",
        14.   "injectdataerr": "inject data error into omap",
        15.   "injectmdataerr": "inject metadata error",
        16.   "log dump": "dump recent log entries to log file",
        17.   "log flush": "flush log entries to log file",
        18.   "log reopen": "reopen log file",
        19.   "perf dump": "dump perfcounters value",
        20.   "perf schema": "dump perfcounters schema",
        21.   "rmomapkey": "remove omap key",
        22.   "setomapheader": "set omap header",
        23.   "setomapval": "set omap key",
        24.   "truncobj": "truncate object to length",
        25.   "version": "get ceph version"}
        26. root@test3:~# ceph daemon /var/run/ceph/ceph-mon.*.asok help
        27. { "add_bootstrap_peer_hint": "add peer address as potential bootstrap peer for cluster bringup",
        28.   "config get": "config get : get the config value",
        29.   "config set": "config set [ ...]: set a config variable",
        30.   "config show": "dump current config settings",
        31.   "get_command_descriptions": "list available commands",
        32.   "git_version": "get git sha1",
        33.   "help": "list available commands",
        34.   "log dump": "dump recent log entries to log file",
        35.   "log flush": "flush log entries to log file",
        36.   "log reopen": "reopen log file",
        37.   "mon_status": "show current monitor status",
        38.   "perf dump": "dump perfcounters value",
        39.   "perf schema": "dump perfcounters schema",
        40.   "quorum_status": "show current quorum status",
        41.   "sync_force": "force sync of and clear monitor store",
        42.   "version": "get ceph version"}
        43. root@test3:~# ceph daemon /var/run/ceph/ceph-mds.*.asok help
        44. { "config get": "config get : get the config value",
        45.   "config set": "config set [ ...]: set a config variable",
        46.   "config show": "dump current config settings",
        47.   "get_command_descriptions": "list available commands",
        48.   "git_version": "get git sha1",
        49.   "help": "list available commands",
        50.   "log dump": "dump recent log entries to log file",
        51.   "log flush": "flush log entries to log file",
        52.   "log reopen": "reopen log file",
        53.   "objecter_requests": "show in-progress osd requests",
        54.   "perf dump": "dump perfcounters value",
        55.   "perf schema": "dump perfcounters schema",
        56.   "version": "get ceph version"}

        比如可以查看 ceph的各个模块的当前配置

        1. ceph daemon /var/run/ceph/ceph-mds.*.asok config show
        2. ceph daemon /var/run/ceph/ceph-mon.*.asok config show
        3. ceph daemon /var/run/ceph/ceph-osd.4.asok config show
        这个是怎么实现的呢? 这是依靠ceph的AdminSocket机制完成。
        CephContext中会创建一个AdminSocket对象,该对象本质是一个线程。ceph-mon/ceph-osd/ceph-mds这些进程都会有创建一个AdminSocket的线程,负责响应用户的探查命令。

        从上面的OSD MON MDS help的不同输出可以看出,他们支持的命令有共同的,也有各自独立的。
        首先是共同支持的命令有:
        • config show        显示所有的配置项
        • config get           获取某个配置项
        • config set           设置某个配置项
        • log flush        将log 刷入日志文件
        • log dump           将最近的若干笔log刷入到log文件
        • log reopen         重新打开log文件
        • perf dump         输出统计信息
        • perf schema      输出统计信息的类型
        • version             版本信息
        • git_version   :    git 版本信息
        支持的大部分common的命令,注册发生在 CephContext的构造函数:
        1.   _admin_hook = new CephContextHook(this);
        2.   _admin_socket->register_command("perfcounters_dump", "perfcounters_dump", _admin_hook, "");
        3.   _admin_socket->register_command("1", "1", _admin_hook, "");
        4.   _admin_socket->register_command("perf dump", "perf dump", _admin_hook, "dump perfcounters value");
        5.   _admin_socket->register_command("perfcounters_schema", "perfcounters_schema", _admin_hook, "");
        6.   _admin_socket->register_command("2", "2", _admin_hook, "");
        7.   _admin_socket->register_command("perf schema", "perf schema", _admin_hook, "dump perfcounters schema");
        8.   _admin_socket->register_command("config show", "config show", _admin_hook, "dump current config settings");
        9.   _admin_socket->register_command("config set", "config set name=var,type=CephString name=val,type=CephString,n=N", _admin_hook, "config set [ ...]: set a config variable");
        10.   _admin_socket->register_command("config get", "config get name=var,type=CephString", _admin_hook, "config get : get the config value");
        11.   _admin_socket->register_command("log flush", "log flush", _admin_hook, "flush log entries to log file");
        12.   _admin_socket->register_command("log dump", "log dump", _admin_hook, "dump recent log entries to log file");
        13.   _admin_socket->register_command("log reopen", "log reopen", _admin_hook, "reopen log file")

        首先定义了个CephContextHook,注册该Hook也作为一个参数传递进去,这个register_command比较简单,就是建立了command字符串和Hook的关联,这个关联有何作用,后面会分析到,暂时按下不表。

        1. int AdminSocket::register_command(std::string command, std::string cmddesc, AdminSocketHook *hook, std::string help)
        2. {
        3.   int ret;
        4.   m_lock.Lock();
        5.   if (m_hooks.count(command)) {
        6.     ldout(m_cct, 5) << "register_command " << command << " hook " << hook << " EEXIST" << dendl;
        7.     ret = -EEXIST;
        8.   } else {
        9.     ldout(m_cct, 5) << "register_command " << command << " hook " << hook << dendl;
        10.     m_hooks[command] = hook;
        11.     m_descs[command] = cmddesc;
        12.     m_help[command] = help;
        13.     ret = 0;
        14.   }
        15.   m_lock.Unlock();
        16.   return ret;
        17. }

        后面从注册部分的代码我们可以知道下面三个命令是等效的。

        1. ceph daemon /var/run/ceph/ceph-mds.bfudz.asok perf dump
        2. ceph daemon /var/run/ceph/ceph-mds.bfudz.asok perfcounters_dump
        3. ceph daemon /var/run/ceph/ceph-mds.bfudz.asok 1
        还有下面三个命令是等效的:

        1. ceph daemon /var/run/ceph/ceph-mds.bfudz.asok perf schema
        2. ceph daemon /var/run/ceph/ceph-mds.bfudz.asok perfcounters_schema
        3. ceph daemon /var/run/ceph/ceph-mds.bfudz.asok 2
         ceph-osd/ceph-mon/ceph-mds有一些自己的独特的注册函数,大家检索register_command可以检索的到这些独特的命令。


        这个AdminSocket 对应的线程,在common_init_finish函数中负责创建。

        1. void common_init_finish(CephContext *cct)
        2. {
        3.   ceph::crypto::init(cct);
        4.   cct->start_service_thread();
        5.   if (cct->_conf->lockdep) {
        6.     g_lockdep = true;
        7.     ldout(cct,0) << "lockdep is enabled" << dendl;
        8.     lockdep_register_ceph_context(cct);
        9.   }
        10. }
        而在start_service_thread函数中会调用adminsocket的init函数:

        1. void CephContext::start_service_thread()
        2. {
        3.   pthread_spin_lock(&_service_thread_lock);
        4.   if (_service_thread) {
        5.     pthread_spin_unlock(&_service_thread_lock);
        6.     return;
        7.   }
        8.   _service_thread = new CephContextServiceThread(this);
        9.   _service_thread->create();
        10.   pthread_spin_unlock(&_service_thread_lock);
        11.   // make logs flush on_exit()
        12.   if (_conf->log_flush_on_exit)
        13.     _log->set_flush_on_exit();
        14.   // Trigger callbacks on any config observers that were waiting for
        15.   // it to become safe to start threads.
        16.   _conf->set_val("internal_safe_to_start_threads", "true");
        17.   _conf->call_all_observers();
        18.   // start admin socket
        19.   if (_conf->admin_socket.length())
        20.     _admin_socket->init(_conf->admin_socket);
        21. }

        接下来可以分析下admin_socket的初始化函数init:

        1. bool AdminSocket::init(const std::string &path)
        2. {
        3.   ldout(m_cct, 5) << "init " << path << dendl;
        4.   /* Set up things for the new thread */
        5.   std::string err;
        6.   int pipe_rd = -1, pipe_wr = -1;
        7.   err = create_shutdown_pipe(&pipe_rd, &pipe_wr);
        8.   if (!err.empty()) {
        9.     lderr(m_cct) << "AdminSocketConfigObs::init: error: " << err << dendl;
        10.     return false;
        11.   }
        12.   int sock_fd;
        13.   err = bind_and_listen(path, &sock_fd);
        14.   if (!err.empty()) {
        15.     lderr(m_cct) << "AdminSocketConfigObs::init: failed: " << err << dendl;
        16.     close(pipe_rd);
        17.     close(pipe_wr);
        18.     return false;
        19.   }
        20.   /* Create new thread */
        21.   m_sock_fd = sock_fd;
        22.   m_shutdown_rd_fd = pipe_rd;
        23.   m_shutdown_wr_fd = pipe_wr;
        24.   m_path = path;
        25.   m_version_hook = new VersionHook;
        26.   register_command("0", "0", m_version_hook, "");
        27.   register_command("version", "version", m_version_hook, "get ceph version");
        28.   register_command("git_version", "git_version", m_version_hook, "get git sha1");
        29.   m_help_hook = new HelpHook(this);
        30.   register_command("help", "help", m_help_hook, "list available commands");
        31.   m_getdescs_hook = new GetdescsHook(this);
        32.   register_command("get_command_descriptions", "get_command_descriptions",
        33.   m_getdescs_hook, "list available commands");
        34.   create();
        35.   add_cleanup_file(m_path.c_str());
        36.   return true;
        37. }

        首先是创建了管道,读取端的文件描述符记录在m_shutdown_rd_fd中,写入端的文件描述符记录在m_shutdown_wr_fd中。
        从变量名字也可以看出,该文件描述符的作用是收取关闭信息。因为adminsocket一旦创建,必须能够通知到该线程及时退出。
        退出的事情会写入管道的写入端,而线程会通过多路复用接口,监听读取端,一旦发现m_shutdown_rd_fd中读出内容,线程就知道,可以退出了。
        按下不表。

        AdminSocket最重要的是监听发过来的请求,它是用socket来实现的,初始化在bind_and_listen 函数:

        1. std::string AdminSocket::bind_and_listen(const std::string &sock_path, int *fd)
        2. {
        3.   ldout(m_cct, 5) << "bind_and_listen " << sock_path << dendl;

        4.   struct sockaddr_un address;
        5.   if (sock_path.size() > sizeof(address.sun_path) - 1) {
        6.     ostringstream oss;
        7.     oss << "AdminSocket::bind_and_listen: "
        8.     << "The UNIX domain socket path " << sock_path << " is too long! The "
        9.     << "maximum length on this system is "
        10.     << (sizeof(address.sun_path) - 1);
        11.     return oss.str();
        12.   }
        13.   int sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
        14.   if (sock_fd < 0) {
        15.     int err = errno;
        16.     ostringstream oss;
        17.     oss << "AdminSocket::bind_and_listen: "
        18.     << "failed to create socket: " << cpp_strerror(err);
        19.     return oss.str();
        20.   }
        21.   int r = fcntl(sock_fd, F_SETFD, FD_CLOEXEC);
        22.   if (r < 0) {
        23.     r = errno;
        24.     TEMP_FAILURE_RETRY(::close(sock_fd));
        25.     ostringstream oss;
        26.     oss << "AdminSocket::bind_and_listen: failed to fcntl on socket: " << cpp_strerror(r);
        27.     return oss.str();
        28.   }
        29.   memset(&address, 0, sizeof(struct sockaddr_un));
        30.   address.sun_family = AF_UNIX;
        31.   snprintf(address.sun_path, sizeof(address.sun_path),
        32.      "%s", sock_path.c_str());
        33.   if (bind(sock_fd, (struct sockaddr*)&address,
        34.      sizeof(struct sockaddr_un)) != 0) {
        35.     int err = errno;
        36.     if (err == EADDRINUSE) {
        37.       AdminSocketClient client(sock_path);
        38.       bool ok;
        39.       client.ping(&ok);
        40.       if (ok) {
        41.     ldout(m_cct, 20) << "socket " << sock_path << " is in use" << dendl;
        42.     err = EEXIST;
        43.       } else {
        44.     ldout(m_cct, 20) << "unlink stale file " << sock_path << dendl;
        45.     TEMP_FAILURE_RETRY(unlink(sock_path.c_str()));
        46.     if (bind(sock_fd, (struct sockaddr*)&address,
        47.          sizeof(struct sockaddr_un)) == 0) {
        48.      err = 0;
        49.     } else {
        50.      err = errno;
        51.     }
        52.       }
        53.     }
        54.     if (err != 0) {
        55.       ostringstream oss;
        56.       oss << "AdminSocket::bind_and_listen: "
        57.      << "failed to bind the UNIX domain socket to '" << sock_path
        58.      << "': " << cpp_strerror(err);
        59.       close(sock_fd);
        60.       return oss.str();
        61.     }
        62.   }
        63.   if (listen(sock_fd, 5) != 0) {
        64.     int err = errno;
        65.     ostringstream oss;
        66.     oss << "AdminSocket::bind_and_listen: "
        67.      << "failed to listen to socket: " << cpp_strerror(err);
        68.     close(sock_fd);
        69.     TEMP_FAILURE_RETRY(unlink(sock_path.c_str()));
        70.     return oss.str();
        71.   }
        72.   *fd = sock_fd;
        73.   return "";
        74. }

        这个函数做的事情并不难理解,做的事情比较老套:
        1 创建一个socket,该函数需要一个入参,指定socket路径名:
        2  bind
        3 listen
        而传入的路径名是这个
        1. root@test3:/var/run/ceph# ceph daemon /var/run/ceph/ceph-mds.bfudz.asok config get admin_socket
        2. { "admin_socket": "\/var\/run\/ceph\/ceph-mds.bfudz.asok"}
        socket建好之后,因为线程还没有创建,所以至今还没有accept接口 。然后我们再次回到init函数,该函数又注册了几个函数:

        1. m_version_hook = new VersionHook;
        2.   register_command("0", "0", m_version_hook, "");
        3.   register_command("version", "version", m_version_hook, "get ceph version");
        4.   register_command("git_version", "git_version", m_version_hook, "get git sha1");
        5.   m_help_hook = new HelpHook(this);
        6.   register_command("help", "help", m_help_hook, "list available commands");
        7.   m_getdescs_hook = new GetdescsHook(this);
        8.   register_command("get_command_descriptions", "get_command_descriptions",
        9.   m_getdescs_hook, "list available commands");
        这几个函数的重要性并不大,基本是用来查版本信息的,如下所示,按下不表。

        1. root@test3:/var/run/ceph# ceph daemon /var/run/ceph/ceph-mds.bfudz.asok version
        2. {"version":"0.67.9-222-g014b35f"}
        3. root@test3:/var/run/ceph# ceph daemon /var/run/ceph/ceph-mds.bfudz.asok git_version
        4. {"git_version":"014b35fc1ee0a1ad1f699a3705f3481a88614d36"}
        5. root@test3:/var/run/ceph#

        init函数最后调用了create函数。create函数是老朋友,前面分析Log的时候已经提到,对于Thread这个类,做的事情无非就是创建线程。关键内容是,线程执行的函数是哪个?
        和Log一样,是entry函数。AdminSocket类也有entry函数,该函数是AdminSocket 对应线程指定的函数:

        1. void* AdminSocket::entry()
        2. {
        3.   ldout(m_cct, 5) << "entry start" << dendl;
        4.   while (true) {
        5.     struct pollfd fds[2];
        6.     memset(fds, 0, sizeof(fds));
        7.     fds[0].fd = m_sock_fd;
        8.     fds[0].events = POLLIN | POLLRDBAND;
        9.     fds[1].fd = m_shutdown_rd_fd;
        10.     fds[1].events = POLLIN | POLLRDBAND;
        11.     int ret = poll(fds, 2, -1);
        12.     if (ret < 0) {
        13.       int err = errno;
        14.       if (err == EINTR) {
        15. continue;
        16.       }
        17.       lderr(m_cct) << "AdminSocket: poll(2) error: '"
        18.   << cpp_strerror(err) << dendl;
        19.       return PFL_FAIL;
        20.     }
        21.     if (fds[0].revents & POLLIN) {
        22.       // Send out some data
        23.       do_accept();
        24.     }
        25.     if (fds[1].revents & POLLIN) {
        26.       // Parent wants us to shut down
        27.       return PFL_SUCCESS;
        28.     }
        29.   }
        30.   ldout(m_cct, 5) << "entry exit" << dendl;
        31. }

        这个线程函数比较简单,它监听socket fd和管道的读取端。
        1 管道的读取端负责管理何时退出
        2 socket fd 负责监听用户发过来的指令。

        处理用户发过来的命令,是do_accept函数干的事情:

        1. bool AdminSocket::do_accept()
        2. {
        3.   struct sockaddr_un address;
        4.   socklen_t address_length = sizeof(address);
        5.   ldout(m_cct, 30) << "AdminSocket: calling accept" << dendl;
        6.   int connection_fd = accept(m_sock_fd, (struct sockaddr*) &address,
        7.              &address_length);
        8.   ldout(m_cct, 30) << "AdminSocket: finished accept" << dendl;
        9.   if (connection_fd < 0) {
        10.     int err = errno;
        11.     lderr(m_cct) << "AdminSocket: do_accept error: '"
        12.              << cpp_strerror(err) << dendl;
        13.     return false;
        14.   }

        15.   char cmd[1024];
        16.   int pos = 0;
        17.   string c;
        18.   while (1) {
        19.     int ret = safe_read(connection_fd, &cmd[pos], 1);
        20.     if (ret <= 0) {
        21.       lderr(m_cct) << "AdminSocket: error reading request code: "
        22.          << cpp_strerror(ret) << dendl;
        23.       close(connection_fd);
        24.       return false;
        25.     }
        26.     //ldout(m_cct, 0) << "AdminSocket read byte " << (int)cmd[pos] << " pos " << pos << dendl;
        27.     if (cmd[0] == '\0') {
        28.       // old protocol: __be32
        29.       if (pos == 3 && cmd[0] == '\0') {
        30.     switch (cmd[3]) {
        31.     case 0:
        32.      c = "0";
        33.      break;
        34.     case 1:
        35.      c = "perfcounters_dump";
        36.      break;
        37.     case 2:
        38.      c = "perfcounters_schema";
        39.      break;
        40.     default:
        41.      c = "foo";
        42.      break;
        43.     }
        44.     break;
        45.       }
        46.     } else {
        47.       // new protocol: null or \n terminated string
        48.       if (cmd[pos] == '\n' || cmd[pos] == '\0') {
        49.     cmd[pos] = '\0';
        50.     c = cmd;
        51.     break;
        52.       }
        53.     }
        54.     pos++;
        55.   }

        56.   bool rval = false;

        57.   map<string, cmd_vartype> cmdmap;
        58.   string format;
        59.   vector<string> cmdvec;
        60.   stringstream errss;
        61.   cmdvec.push_back(cmd);
        62.   if (!cmdmap_from_json(cmdvec, &cmdmap, errss)) {
        63.     ldout(m_cct, 0) << "AdminSocket: " << errss << dendl;
        64.     return false;
        65.   }
        66.   cmd_getval(m_cct, cmdmap, "format", format);
        67.   if (format != "json" && format != "json-pretty" &&
        68.       format != "xml" && format != "xml-pretty")
        69.     format = "json-pretty";
        70.   cmd_getval(m_cct, cmdmap, "prefix", c);

        71.   string firstword;
        72.   if (c.find(" ") == string::npos)
        73.     firstword = c;
        74.   else
        75.     firstword = c.substr(0, c.find(" "));

        76.   m_lock.Lock();
        77.   map<string,AdminSocketHook*>::iterator p;
        78.   string match = c;
        79.   while (match.size()) {
        80.     p = m_hooks.find(match);
        81.     if (p != m_hooks.end())
        82.       break;
        83.     
        84.     // drop right-most word
        85.     size_t pos = match.rfind(' ');
        86.     if (pos == std::string::npos) {
        87.       match.clear(); // we fail
        88.       break;
        89.     } else {
        90.       match.resize(pos);
        91.     }
        92.   }

        93.   bufferlist out;
        94.   if (p == m_hooks.end()) {
        95.     lderr(m_cct) << "AdminSocket: request '" << c << "' not defined" << dendl;
        96.   } else {
        97.     string args;
        98.     if (match != c)
        99.       args = c.substr(match.length() + 1);
        100.     bool success = p->second->call(match, cmdmap, format, out);
        101.     if (!success) {
        102.       ldout(m_cct, 0) << "AdminSocket: request '" << match << "' args '" << args
        103.          << "' to " << p->second << " failed" << dendl;
        104.       out.append("failed");
        105.     } else {
        106.       ldout(m_cct, 5) << "AdminSocket: request '" << match << "' '" << args
        107.          << "' to " << p->second
        108.          << " returned " << out.length() << " bytes" << dendl;
        109.     }
        110.     uint32_t len = htonl(out.length());
        111.     int ret = safe_write(connection_fd, &len, sizeof(len));
        112.     if (ret < 0) {
        113.       lderr(m_cct) << "AdminSocket: error writing response length "
        114.          << cpp_strerror(ret) << dendl;
        115.     } else {
        116.       if (out.write_fd(connection_fd) >= 0)
        117.     rval = true;
        118.     }
        119.   }
        120.   m_lock.Unlock();

        121.   TEMP_FAILURE_RETRY(close(connection_fd));
        122.   return rval;
        123. }

        这个函数有点长,但是并不复杂。简单说,如果有个client尝试 connect ,该线程就poll就会感知到,然后进入do_accept函数。
        do_accept首先执行accept,和client 搭上线,然后开始通信。 

        safe_read负责 读取客户发过来的指令。前面已经提到过,AdminSocket支持的命令是有限的,初始化之前都已注册过了。
        如果client 发来的指令时注册过的指令,就见招拆招,返回相应的结果给客户端。

        每一个命令的字符串,都是和一个AdminSocketHook 的类型关联的,但是一个AdminSocketHook可以对应多个command

        1. std::map<std::string,AdminSocketHook*> m_hooks
        比如说 config show  / config get   / perf dump对应的多事 CephContextHook,前面已经提到过。

        见招拆招的函数,就记录在对应的Hook上:

        1. class CephContextHook : public AdminSocketHook {
        2.   CephContext *m_cct;
        3. public:
        4.   CephContextHook(CephContext *cct) : m_cct(cct) {}
        5.   bool call(std::string command, cmdmap_t& cmdmap, std::string format,
        6.    bufferlist& out) {
        7.     m_cct->do_command(command, cmdmap, format, &out);
        8.     return true;
        9.   }
        10. };


        do_accept函数中黄色的一行,具体是实现,就是对应Hook的call函数,对于CephContextHook,就是这个类的call方法。

        下面我们看下CephContextHook的call方法:即它的do_command函数:

        1. void CephContext::do_command(std::string command, cmdmap_t& cmdmap,
        2.              std::string format, bufferlist *out)
        3. {
        4.   Formatter *f = new_formatter(format);
        5.   if (!f)
        6.     f = new_formatter("json-pretty");
        7.   stringstream ss;
        8.   for (cmdmap_t::iterator it = cmdmap.begin(); it != cmdmap.end(); ++it) {
        9.     if (it->first != "prefix") {
        10.       ss << it->first << ":" << cmd_vartype_stringify(it->second) << " ";
        11.     }
        12.   }
        13.   lgeneric_dout(this, 1) << "do_command '" << command << "' '"
        14.              << ss.str() << dendl;
        15.   if (command == "perfcounters_dump" || command == "1" ||
        16.       command == "perf dump") {
        17.     _perf_counters_collection->dump_formatted(f, false);
        18.   }
        19.   else if (command == "perfcounters_schema" || command == "2" ||
        20.     command == "perf schema") {
        21.     _perf_counters_collection->dump_formatted(f, true);
        22.   }
        23.   else {
        24.     f->open_object_section(command.c_str());
        25.     if (command == "config show") {
        26.       _conf->show_config(f);
        27.     }
        28.     else if (command == "config set") {
        29.       std::string var;
        30.       std::vector<std::string> val;

        31.       if (!(cmd_getval(this, cmdmap, "var", var)) ||
        32.           !(cmd_getval(this, cmdmap, "val", val))) {
        33.         f->dump_string("error", "syntax error: 'config set '");
        34.       } else {
        35.     // val may be multiple words
        36.     string valstr = str_join(val, " ");
        37.         int r = _conf->set_val(var.c_str(), valstr.c_str());
        38.         if (r < 0) {
        39.           f->dump_stream("error") << "error setting '" << var << "' to '" << valstr << "': " << cpp_strerror(r);
        40.         } else {
        41.           ostringstream ss;
        42.           _conf->apply_changes(&ss);
        43.           f->dump_string("success", ss.str());
        44.         }
        45.       }
        46.     } else if (command == "config get") {
        47.       std::string var;
        48.       if (!cmd_getval(this, cmdmap, "var", var)) {
        49.     f->dump_string("error", "syntax error: 'config get '");
        50.       } else {
        51.     char buf[4096];
        52.     memset(buf, 0, sizeof(buf));
        53.     char *tmp = buf;
        54.     int r = _conf->get_val(var.c_str(), &tmp, sizeof(buf));
        55.     if (r < 0) {
        56.      f->dump_stream("error") << "error getting '" << var << "': " << cpp_strerror(r);
        57.     } else {
        58.      f->dump_string(var.c_str(), buf);
        59.     }
        60.       }
        61.     } else if (command == "log flush") {
        62.       _log->flush();
        63.     }
        64.     else if (command == "log dump") {
        65.       _log->dump_recent();
        66.     }
        67.     else if (command == "log reopen") {
        68.       _log->reopen_log_file();
        69.     }
        70.     else {
        71.       assert(0 == "registered under wrong command?");
        72.     }
        73.     f->close_section();
        74.   }
        75.   f->flush(*out);
        76.   delete f;
        77.   lgeneric_dout(this, 1) << "do_command '" << command << "' '" << ss.str()
        78.          << "result is " << out->length() << " bytes" << dendl;
        79. };
          毫不意外,前面注册的每一个方法,在do_command函数中都做了处理。
          
        阅读(12267) | 评论(1) | 转发(3) |
        给主人留下些什么吧!~~

        bjq10162015-07-13 15:43:14

        赞!!!!

        十博最佳体育平台