ceph Async 網絡通信源代碼分析(二)

在上文中,主要介紹了相關的類,本文介紹相關流程。

連接相關的流程介紹

Server端監聽和接受連接的過程

這段代碼來自 src/test/msgr/perf_msgr_server.cc,主要用於建立Server端的msgr:

 void start() {
    entity_addr_t addr;
    addr.parse(bindaddr.c_str());
    msgr->bind(addr);
    msgr->add_dispatcher_head(&dispatcher);
    msgr->start();
    msgr->wait();
 }

上面的代碼是典型的服務端的啓動流程:

  1. 綁定服務端地址 msgr->bind(addr)
  2. 添加消息分發類型 dispatcher
  3. 啓動 msgr->start()

下面從內部具體如何實現。

  • 調用processor的bind 函數,對於PosixStack, 只需要一個porcessor就可以了。
int AsyncMessenger::bind(const entity_addr_t &bind_addr)
{
 ......
     for (auto &&p : processors) {
         int r = p->bind(bind_addr, avoid_ports, &bound_addr);
       }
 ......
}
int Processor::bind(const entity_addr_t &bind_addr,
            const set<int>& avoid_ports,
            entity_addr_t* bound_addr)
{
...
  //向Processor對於的工作者線程 投遞外部事件,其回調函數爲 worker的 listen函數
   worker->center.submit_to(worker->center.get_id(), [this, &listen_addr, &opts, &r]() {
        r = worker->listen(listen_addr, opts, &listen_socket);
      }, false);
...
}

當該外部事件被worker線程調度執行後,worker->listen完成了該Processor的listen_socket的創建。

  • 添加 dispatcher
 void add_dispatcher_head(Dispatcher *d) { 
        if (first)
      ready();
}

在ready 函數裏調用了Processor::start函數

void AsyncMessenger::ready()
{
  ldout(cct,10) << __func__ << " " << get_myaddr() << dendl;

  stack->start();
  Mutex::Locker l(lock);
  for (auto &&p : processors)
    p->start();
  dispatch_queue.start();
}

在Processor::start函數裏,向EventCenter 投遞了外部事件,該外部事件的回調函數裏實現了向 EventCenter註冊listen socket 的讀事件監聽。 該事件的處理函數爲 listen_handeler

void Processor::start()
{
  ldout(msgr->cct, 1) << __func__ << dendl;

  // start thread
  if (listen_socket) {
    worker->center.submit_to(worker->center.get_id(), [this]() {
      worker->center.create_file_event(
        listen_socket.fd(), EVENT_READABLE, listen_handler); 
    }, false);
  }
}

listen_handler對應的 處理函數爲 processor::accept函數,其處理接收連接的事件。

class Processor::C_processor_accept : public EventCallback {
  Processor *pro;

 public:
  explicit C_processor_accept(Processor *p): pro(p) {}
  void do_request(int id) {
    pro->accept();
  }
};
void Processor::accept()
{
 ......
   if (!msgr->get_stack()->support_local_listen_table())
      w = msgr->get_stack()->get_worker();

    int r = listen_socket.accept(&cli_socket, opts, &addr, w);
    if (r == 0) {
      msgr->add_accept(w, std::move(cli_socket), addr);
      continue;
     }
}

在函數Processor::accept裏, 首先獲取了一個worker,通過調用accept函數接收該連接。並調用 msgr->add_accept 函數。

void AsyncMessenger::add_accept(Worker *w, 
                               ConnectedSocket cli_socket,
                               entity_addr_t &addr)
{
  lock.Lock();
  //創建連接,該Connection已經指定了 worker處理該Connection上所有的事件。
  AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
  conn->accept(std::move(cli_socket), addr);
  accepting_conns.insert(conn);
  lock.Unlock();
}

Client端主動連接的過程

AsyncConnectionRef AsyncMessenger::create_connect(const entity_addr_t& addr, int type)
{

  // 獲取一個 worker,根據負載均衡
  Worker *w = stack->get_worker();
  //創建Connection
  AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
  //
  conn->connect(addr, type);
  //添加到conns列表中
  conns[addr] = conn;


  return conn;
}
void AsyncConnection::_connect()
{
  ldout(async_msgr->cct, 10) << __func__ << " csq=" << connect_seq << dendl;

  state = STATE_CONNECTING;
  // rescheduler connection in order to avoid lock dep
  // may called by external thread(send_message)
  center->dispatch_event_external(read_handler);
}

函數 AsyncConnection::_connect 設置了狀態爲 STATE_CONNECTING,向對應的 EventCenter投遞 外部外部事件,其read_handler爲 void AsyncConnection::process()函數。

void AsyncConnection::process()
{
   ......
    default:
        {
          if (_process_connection() < 0)
            goto fail;
          break;
        }
}
ssize_t AsyncConnection::_process_connection()
{
......
  r = worker->connect(get_peer_addr(), opts, &cs);
        if (r < 0)
          goto fail;

        center->create_file_event(cs.fd(), EVENT_READABLE, read_handler);
}

消息的接收和發送

消息的接收

消息的接收比較簡單,因爲消息的接收都是 內部事件,也就是都是由 epoll_wait觸發的事件。其對應的回調函數 AsyncConnection::process() 去處理相應的接收事件。

消息的發送

消息的發送比較特殊,它涉及到外部事件和內部事件的相關的調用。

int AsyncConnection::send_message(Message *m){
     ......
     //把消息添加到 內部發送隊列裏
      out_q[m->get_priority()].emplace_back(std::move(bl), m);
     //添加外部事件給對應的的CenterEvent,並觸發外部事件
      if (can_write != WriteStatus::REPLACING)
         center->dispatch_event_external(write_handler);
}

發送相關的調用函數

void AsyncConnection::handle_write()
       ssize_t AsyncConnection::write_message(Message *m,
                       bufferlist& bl, bool more)
         ssize_t AsyncConnection::_try_send(bool more)
ssize_t AsyncConnection::_try_send(bool more)
{
......
   if (!open_write && is_queued()) {
    center->create_file_event(cs.fd(), EVENT_WRITABLE, 
                            write_handler);
    open_write = true;
  }

  if (open_write && !is_queued()) {
    center->delete_file_event(cs.fd(), EVENT_WRITABLE);
    open_write = false;
    if (state_after_send != STATE_NONE)
      center->dispatch_event_external(read_handler);
  }

}

函數_try_send裏比較關鍵的是:

  1. 當還有消息沒有發送時, 就把該socket的 fd 添加到 EVENT_WRITABLE 事件中。
  2. 如果沒有消息發送, 就把該 socket的 fd 的 EVENT_WRITABLE 事件監聽刪除

也就是當有發送請求時, 添加外部事件,並觸發線程去處理髮送事件。當外部事件一次可以完成發送消息的請求時,就不需要添加該fd對應的EVENT_WRITABLE 事件監聽。當沒有發送完消息時,就添加該fd的EVENT_WRITABLE 事件監聽來觸發內部事件去繼續完成消息的發送。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章