Accelio 代码笔记

  • 项目概述

Accelio是一套支持rdma协议的通讯框架,并且允许扩展包含client和server,同时支持用户态和内核态。

  • 功能

Simplified API for application developers

High-performance asynchronous APIs

Reliable message delivery (end to end)

Request/Replay or Send/Receive models

Connection and resource abstraction to maximize scalability and availability

Native support for service and storage clustering/scale-out

Maximize multi-threaded application performance allowing dedicated hardware resources per thread

Zero copy data delivery, with optional built-in memory management

Support for multiple transport technologies (RDMA, TCP, Shared-Memory etc.)**

Integration with common event loop mechanisms

Fast event notifications or combined models for lowest message latency

Message combining and batch message processing optimization

User space and kernel implementations

Java bindings**

  • 结构

划分为三层

Application Interface

Easy-to-use primitives for fast and reliable asynchronous message queue or RPC (Remote Procedure Call)

Session and Connection Management

Provides reliable end-to-end connectivity to peer endpoints, with dynamic connection establishment, pooling, fault recovery, and migration/redirection

Pluggable Transport Layer

Allows mapping to different hardware or software transport implementations

  • 主要数据结构

xio_transport

协议类型,目前只有rdma,包含协议名和该协议相关的所有操作函数 ,rdma模块中定义了一个xio_rdma_transport全局变量,实现了xio_transport中所有函数,同时还有一个struct xio_rdma_transport结构,该类型是对底层驱动接口的封装,同时包含了上下文,每个conn对象都包含一个单独的,该结构实际应该是和xio_transport_base在同一层次

struct xio_transport {

const char *name;

struct xio_transport_msg_validators_cls validators_cls;

/* transport ctor/dtor called right after registration */

void (*ctor)(void);

void (*dtor)(void);

/* transport initialization */

int (*init)(struct xio_transport *self);

void (*release)(struct xio_transport *self);

/* running thread (context) is going down */

int (*context_shutdown)(struct xio_transport_base *trans_hndl,

struct xio_context *ctx);

/* observers */

void (*reg_observer)(struct xio_transport_base *trans_hndl,

struct xio_observer *observer);

void (*unreg_observer)(struct xio_transport_base *trans_hndl,

struct xio_observer *observer);

/* task pools managment */

void (*get_pools_setup_ops)(struct xio_transport_base *trans_hndl,

struct xio_tasks_pool_ops **initial_pool_ops,

struct xio_tasks_pool_ops **primary_pool_ops);

void (*set_pools_cls)(struct xio_transport_base *trans_hndl,

struct xio_tasks_pool_cls *initial_pool_cls,

struct xio_tasks_pool_cls *primary_pool_cls);

/* connection */

struct xio_transport_base *(*open)(struct xio_transport *self,

struct xio_context *ctx,

struct xio_observer *observer);

int (*connect)(struct xio_transport_base *trans_hndl,

const char *portal_uri,

const char *out_if);

int (*listen)(struct xio_transport_base *trans_hndl,

const char *portal_uri, uint16_t *src_port,

int backlog);

int (*accept)(struct xio_transport_base *trans_hndl);

int (*poll)(struct xio_transport_base *trans_hndl,

long min_nr, long nr,

struct timespec *timeout);

int (*reject)(struct xio_transport_base *trans_hndl);

void (*close)(struct xio_transport_base *trans_hndl);

int (*send)(struct xio_transport_base *trans_hndl,

struct xio_task *task);

int (*set_opt)(void *xio_obj,

int optname, const void *optval, int optlen);

int (*get_opt)(void *xio_obj,

int optname, void *optval, int *optlen);

int (*cancel_req)(struct xio_transport_base *trans_hndl,

struct xio_msg *req, uint64_t stag,

void *ulp_msg, size_t ulp_msg_len);

int (*cancel_rsp)(struct xio_transport_base *trans_hndl,

struct xio_task *task, enum xio_status result,

void *ulp_msg, size_t ulp_msg_len);

struct list_head transports_list_entry;

};

xio_transport_base

底层通信的上下文,每个conn对应一个

struct xio_transport_base {

struct xio_context *ctx;

struct xio_observable observable;

uint32_t is_client;  /* client or server */

atomic_t refcnt;

char *portal_uri;

struct sockaddr_storage peer_addr;

enum   xio_proto proto;

int pad;

};

xio_conn

对transport_base的简单封装,管理task缓存,处理框架内部定义的一些消息,握手消息之类

struct xio_conn {

struct xio_transport *transport;

struct xio_transport_base *transport_hndl;

struct xio_tasks_pool *primary_tasks_pool;

struct xio_tasks_pool_ops *primary_pool_ops;

struct xio_tasks_pool *initial_tasks_pool;

struct xio_tasks_pool_ops *initial_pool_ops;

struct xio_observer *server_observer;

struct xio_observer trans_observer;

struct xio_observer ctx_observer;

struct xio_observable observable;

struct kref kref;

int cid;

enum xio_conn_state state;

int is_first_req;

int is_listener;

int pad;

xio_ctx_timer_handle_t close_time_hndl;

struct list_head observers_htbl;

HT_ENTRY(xio_conn, xio_key_int32) conns_htbl;

};

xio_connection

对xio_conn的封装,管理msg缓存,对外提供访问接口

struct xio_connection {

struct xio_conn *conn;

struct xio_session *session;

struct xio_context *ctx; /* connection context */

struct xio_session_ops ses_ops;

/* server‘s session may have multiple connections each has

* private data assignd by bind

*/

void *cb_user_context;

int conn_idx;

int state;

int32_t send_req_toggle; // 选择发送请求还是回应

int pad;

struct kref kref;

struct kref fin_kref;

struct xio_msg_list reqs_msgq; // 待发送的请求队列

struct xio_msg_list rsps_msgq; //  待发送的回应队列

struct xio_msg_list in_flight_reqs_msgq; // 已经发送的请求队列

struct xio_msg_list in_flight_rsps_msgq; // 已经发送的回应队列

struct xio_msg_list one_way_msg_pool;

struct xio_msg *msg_array;

struct list_head io_tasks_list;

struct list_head post_io_tasks_list;

struct list_head pre_send_list;

struct list_head connections_list_entry;

struct list_head ctx_list_entry;

};

xio_session

网络session,一个addr对应一个session,每个session管理多个xio_connection,但是每个session中的多个connection不能由同一个context管理,多线程的使用模式是,由一个主线程创建session,每个工作线程创建context,并建立连接(Client端)

struct xio_session {

uint64_t trans_sn; /* transaction sn */

uint32_t session_id;

uint32_t peer_session_id;

uint32_t session_flags;

uint32_t connections_nr;

struct list_head sessions_list_entry;

struct list_head connections_list;

HT_ENTRY(xio_session, xio_key_int32) sessions_htbl;

struct xio_session_ops ses_ops;

struct xio_transport_msg_validators_cls *validators_cls;

struct xio_msg *setup_req;

struct xio_observer observer;

enum xio_session_type type;

volatile enum xio_session_state state;

struct xio_new_session_rsp new_ses_rsp;

char *uri;

char **portals_array;

char **services_array;

void *user_context;

void *cb_user_context;

uint16_t user_context_len;

uint16_t uri_len;

uint16_t portals_array_len;

uint16_t services_array_len;

uint16_t last_opened_portal;

uint16_t last_opened_service;

uint16_t in_notify;

uint16_t pad[3];

uint32_t reject_reason;

struct mutex                    lock;    /* lock open connection */

spinlock_t                      connections_list_lock;

int disable_teardown;

struct xio_connection *lead_connection;

struct xio_connection *redir_connection;

};

xio_server

服务端,xio_bind调用时返回,处理session未建立前的一些事件

struct xio_server {

struct xio_conn *listener;

struct xio_observer observer;

char *uri;

struct xio_context *ctx;

struct xio_session_ops ops;

uint32_t session_flags;

uint32_t pad;

void *cb_private_data;

};

xio_context

主线程循环的上下文,

struct xio_context {

void *ev_loop;

int cpuid;

int nodeid;

int polling_timeout;

unsigned int flags;

uint64_t worker;

struct xio_statistics stats;

struct xio_context_params params;

struct xio_schedwork *sched_work;

struct list_head ctx_list;  /* per context storage */ 用来记录该ctx上的xio_connection

/* list of sessions using this connection */

struct xio_observable observable;

void *netlink_sock;

};

xio_msg

用户需要发送的内容

struct xio_msg {

struct xio_vmsg in;

struct xio_vmsg out;

union {

uint64_t sn; /* unique message serial number

* returned by the library

*/

struct xio_msg *request;  /* on server side - attached

* request

*/

};

enum xio_msg_type type;

int         more_in_batch; /* more messages are expected */

int status;

int flags;

enum xio_receipt_result receipt_res;

uint64_t timestamp; /**< submission timestamp     */

int reserved;

void *user_context; /* for user usage - not sent */

struct xio_msg_pdata pdata; /**< accelio private data     */

struct xio_msg *next;          /* internal use */

};

xio_task

打包msg,加入消息头

struct xio_task {

struct list_head tasks_list_entry;

void *dd_data; // 传输协议扩展,记录协议内所用到的数据,例如rdma_task

struct xio_mbuf mbuf; // 由各协议自己初始化,使用pool_init_item

struct xio_task *sender_task;  /* client only on receiver */

struct xio_msg *omsg; /* pointer from user */

struct xio_session *session;

struct xio_conn *conn;

struct xio_connection *connection;

void *pool;

release_task_fn release;

enum xio_task_state state; /* task state enum */

struct kref kref;

uint64_t magic;

uint64_t stag; /* session unique tag */

uint32_t is_control;

uint32_t tlv_type;

uint32_t ltid; /* local task id */

uint32_t rtid; /* remote task id */

uint32_t omsg_flags;

uint32_t pad;

struct xio_msg imsg; /* message to the user */

};

Xio_rdma_task

struct xio_rdma_task {

struct xio_rdma_transport *rdma_hndl;

enum xio_ib_op_code ib_op;

u16 more_in_batch;

u16 sn;

u16 phantom_idx;

u16 pad[3];

//struct xio_data_buffer sdb;

/* The buffer mapped with the 3 xio_work_req

* used to transfer the headers

*/

void *buf;

unsigned long size;

struct xio_work_req txd;

struct xio_work_req rxd;

struct xio_work_req rdmad;

/* User (from vmsg) or pool buffer used for */

u32 read_num_sge;

u32 write_num_sge;

u32 recv_num_sge;

struct xio_rdma_mem_desc read_sge;

struct xio_rdma_mem_desc write_sge;

/* What this side got from the peer for RDMA R/W

* Currently limitd to 1

*/

u32 req_write_num_sge;

u32 req_read_num_sge;

u32 req_recv_num_sge;

struct xio_sge req_read_sge[XIO_MAX_IOV];

struct xio_sge req_write_sge[XIO_MAX_IOV];

/* What this side got from the peer for SEND

*/

struct xio_sge req_recv_sge[XIO_MAX_IOV];

};

Req_*_sge说明,用来记录对端或者自己这边的使用的存放数据的地址

如果是要发送写请求,这种场景发生在回应response时,在收到req时,就将rdma_task中的req_read_sge设置为对端的存放数据的内存地址,那么req_write_sge就为本地存放用户写入数据的内存地址。

如果为读请求,之前对端发送过来的req中必然携带了对方存放数据的内存地址,req_write_sge,本地的用来存放读取过来数据的地址为req_read_sge。这时候对端发送过来的req_read_sge是没用的,会在解析头部的时候重置为NULL。

Read_sge和write_seq是用来存放数据的内存控制描述符。真正的内存buf控制结构。Req_*_sge只是记录了内存地址。

xio_tasks_pool

struct xio_tasks_pool {

/* pool of tasks */

struct xio_task **array;

/* LIFO */

struct list_head stack;

/* max number of elements */

int max;

int nr;

void *dd_data; // 底层协议扩展,例如在rdma协议时,指向rdma_task_pool

void *pool_ops; // 底层协议扩展,注册创建(初始化),回收底层pool,以及初始化pool中每个成员等函数

};

xio_observer

事件观察者,

struct xio_observer {

void *impl;

notify_fn_t notify;

};

xio_observable

被观察者

struct xio_observable {

void *impl;

struct list_head observers_list;

struct xio_observer_node *observer_node; /* for one observer */

};

xio_work_req

struct xio_work_req {

union {

struct ib_send_wr send_wr;

struct ib_recv_wr recv_wr;

};

struct ib_sge sge[XIO_MAX_IOV + 1];

struct scatterlist sgl[XIO_MAX_IOV + 1];

int nents; /* number of sgl entries */

int mapped; /* number of mapped entries */

};

底层ib通讯时使用的参数的封装,ib_sge用来设置send_wr或者recv_wr的sge通过ib接口映射过的地址,sgl原始地址

rxd->recv_wr.sg_list = rxd->sge;

sg_set_page(rxd->sgl, virt_to_page(buf), size, offset_in_page(buf));

xd->sge[i].addr   = ib_sg_dma_address(ib_dev, &xd->sgl[i]);

xio_map_work_req

  • 机制

事件处理

Xio框架负责处理主线程的调度,在调用xio_context_create时,初始化主处理线程,并设置添加事件的回调接口add_event,线程启动接口run,以及停止接口stop

struct xio_loop_ops {

void *ev_loop;

int (*run)(void *loop);

void (*stop)(void *loop);

int (*add_event)(void *loop, struct xio_ev_data *data);

};

struct xio_context *xio_context_create(unsigned int flags,

struct xio_loop_ops *loop_ops,

struct task_struct *worker,

int polling_timeout,

int cpu_hint);

底层协议层,如果有网络事件产生,通过add_event接口把要处理的事件和处理函数加入到主处理线程(也可以通过定时器加入事件),add_event会将事件加入队列中,并唤醒正在等待的主线程,主线程逐一调用事件处理函数

Rdma在初始化cq时,xio_cq_init会设置回调函数xio_cq_data_callback,当rdma事件产生时把事件处理函数xio_data_handler通过add_event加入主处理线程,xio_data_handler会依次检查每个连接

void xio_data_handler(void *user_context)

{

struct xio_cq *tcq = (struct xio_cq *) user_context;

struct xio_rdma_transport *rdma_hndl;

xio_cq_event_handler(tcq, tcq->ctx->polling_timeout);

list_for_each_entry(rdma_hndl, &tcq->trans_list, trans_list_entry) {

xio_rdma_idle_handler(rdma_hndl);

}

return;

}

观察者

当被观察者上发生事件时,会通知观察者,观察者如果对某一对象上面的一些事件感兴趣,需要注册自己到该对象上的观察者列表中。例如:

xio_context_reg_observer:观察者注册自己到ctx中,观察者会收到ctx事件的通知

xio_conn_reg_observer:xio_connection_set_conn函数会在执行时把session注册到conn中,而client端,会在调用xio_conn_open时把session注册到conn中(server端同样会调用这个函数,但是传递的observer是空)

tcq和transprot也会关注context的事件

client端,在执行xio_conn_open时,把conn注册到transport中

server端,会在执行xio_conn_create,时注册conn到transport中

并发和多线程

一个session只能有一个URI,每个session管理多个xio_connection,但是每个session中的多个connection不能由同一个context管理,多线程的使用模式是,由一个主线程创建session,每个工作线程创建context,并建立连接(Client端),同一个ctx中,URI相同的不同session可以在同一个工作线程中,此时这些session的xio_connection公用同一个xio_conn,每个context中,一个地址只能对应一个xio_conn,同一个session中,每个xio_connection对应一个xio_conn

Xio_on_setup_rsp_recv里面的两个分支代表两个场景,portals_array为空,但是session->connections_nr > 1的场景是:多个线程同时对一个session建立连接,这时候已经产生了多个xio_connection,但是只生成了一个xio_conn去发送建立session的信息,其他的xio_connection在session建立之后再进行连接,另外一个场景,portals_array不为空,对端有多个网络线程工作线程,一个监听线程,但session建立之后,对端又指定了多个地址,这个时候就需要重新创建xio_connection,并建立连接。

内存管理

Accelio使用两类buf,一种用于消息头部或者小数据量,每个大小为4-8k,另外一类用于rdma的大数据io,第二类buf,可以由库或者程序自己申请。

l 程序管理的buf

需要提前通过reg_mr接口注册

l 库管理的buf

要使用程序自己申请的内存,需要传入mr信息,如果没传入,那么会把传入的内存拷贝到库维护的缓存中,多一次内存拷贝。

消息合并和批处理

消息的批量发送,可以发送消息时,遍历待发送队列,把send_wr用next指针连接起来,使用ibv_post_send接口批量发送消息,ibv_poll_cq接口,批量获取收到的请求

Has_more标记,在几个地方会使用,在底层有事件发生时,如果has_more标记为0,那么表示当前网络空闲,可以把待发送的消息发送给对方,还有就是在rdma_send_req和rdma_send_rsp中,作用都是相同的。

On_msg接口中,会带有has_more_batch参数,来标记是否还有其他消息需要处理,应用程序可以根据这个参数来做一些合并工作。

访问接口

几个重要标记

l XIO_IB_RDMA_READ的使用场景,当请求方的数据大小,超过了设置的缓存大小时,请求方发送IBV_WR_SEND请求,并设置ib_op类型为XIO_IB_RDMA_READ。接收方在收到该请求后,发送IBV_WR_RDMA_READ请求给发送方,并设置ib_op为XIO_IB_RDMA_READ,直接读取远处内存中的数据,不在处理recv消息。

l XIO_IB_RDMA_WRITE的使用场景,当接收方处理完成发送回应时,如果需要回应的数据大小超过了设置的缓存大小时,接收方发送IB_WR_RDMA_WRITE请求,并设置ib_op类型为XIO_IB_RDMA_WRITE

l XIO_IB_RECV的使用场景,接收方用来接收请求的task都设置该标记,有一种使用场景检查了这个标记,当接收方收到了一个XIO_IB_RDMA_READ请求之后,发送请求去发送方读取数据,这时会重新生成一个tmp_task,它的ib_op为XIO_IB_RDMA_READ,与原始的task请求时不同的,这时候需要把接收方收到的原始task加入rdma_rd_list中,等待读取数据完成。接收方在发送task请求时,根据这个标记位来进去判断哪些读请求时要发送给发送方的。哪些只是等待读取完成。

l XIO_IB_SEND的使用场景,发送方的task都设置该标记

另外需要说明的是,为了保证消息的到达顺序,接收方在等待接收消息时,也就是rdma_rd_list非空时,是不处理收到的POST消息的,否则就可能出现后POST的消息,先处理,而之前的消息,还在读取过程中。

回调函数

l on_msg_send_complete

该函数由请求的接收方调用,当发送回应完成时调用该回调函数,这里说的发送完成是指ib层认为数据发送完毕,不涵盖其他逻辑。

l on_msg_delivered

该函数由请求的发送方调用,当发送方收到了接收方的回应时,调用该函数,接收方在收到请求时,会调用xio_connection_send_read_receipt,发送回应,one_way_msg必须设置该标记,request可选择是否设置,通过检查task状态是否为XIO_TASK_STATE_DELIVERED确保只发送一次确认消息

xio_on_req_recv-- connection->ses_ops.on_msg-- xio_connection_send_read_receipt

接收方处理完成之后发送receipt

l on_msg

在收到消息时

Request/reply

发送方

l xio_send_request

检查session状态

检查参数合法性

统计数据

获取序列号xio_session_get_sn

把消息加入待发送队列中,xio_msg_list_insert_tail

连接在线,则执行xio_connection_xmit

l xio_connection_xmit

根据标记选择要发送的队列

遍历队列,逐一发送每个msg  xio_connection_send

发送失败,重试或者返回错误

发送成功,把消息加入已发送队列中

l xio_connection_send

a) 发送的是response,并且消息的标记仅设置XIO_MSG_RSP_FLAG_FIRST转下一步,否则转d

b) 从primary_task_pool中申请一个xio_task

c) 从该response对应的请求msg中获取请求task,并设置xio_task的sender_task成员,转f

d) 发送的是request,转下一步,否则转h

e) 从primary_task_pool中申请一个xio_task

f) 设置序列号

g) 把新申请的xio_task加入pre_send_list中,转i

h) 把原始task加入pre_send_list中

i) 修改消息头,设置序列号,task类型

j) 重置task的mbuf在xio_rdma_initial_pool_init_task生成task的时候从kmem_cache中分配一段内存,后面用该内存初始化mbuf

k) 把头部写入mbuf

l) xio_conn_send

m) xio_rdma_send

l xio_rdma_send_req

如果已经发送的请求数超过了最大限制,返回EAGIN的错误

准备接受回应的缓冲区,xio_rdma_prep_req_in_data

准备发送请求的缓存冲,之前的缓冲区只填充了消息头,没有写入msg内容,xio_rdma_prep_req_out_data

修改buf长度xio_mbuf_tlv_payload_len

最好要完整填充txd->send_wr

最后把task加入底层传输的待发送队列中rdma_hndl->tx_ready_list

判断待发送列大小,超过的警戒值,则批量发送xio_rdma_xmit

l xio_rdma_prep_req_out_data

a) 判断要发送的数据量是否超过了发送缓存的大小,没有超过转下一步,超过转d

b) xio_rdma_prep_req_header 写入头部到mbuf中,用户写入的数据非空转下一步,否则转h

c) xio_rdma_write_send_data,用传入的buf地址设置sge[1]起始的数组,或者没有mr则把用户数据拷贝到mbuf中,转g

d) 超过缓存大小,rdma_task->ib_op = XIO_IB_RDMA_READ;由对方来主动读取数据

e) 检查用户是否设置mr,设置转下一步,没有设置转g

f) 逐一设置addr,rdma_task->write_sge[i].addr = vmsg->data_iov[i].iov_base;转h

g) 用户没有设置mr,需要逐一为write_sge分配内存,并拷贝数据

h) 返回

之前在初始化txd时,通过sg_set_page(rxd->sgl, virt_to_page(buf), size, offset_in_page(buf)),把buf和sgl做过映射,后面再执行xio_rdma_xmit时,会用sgl数组元素的addr来设置sge数组元素的addr,如果用户写入的数据直接设置了sge,那么sgl数组应该只有元素0存放消息头部

l xio_rdma_xmit

接收方

l xio_handle_wc

xio_rdma_rx_handler

xio_rdma_on_recv_req

xio_rdma_notify_observer(xio_rdma_datapath.c)

xio_on_new_message(xio_conn.c)

xio_conn_on_recv_req(xio_conn.c)

xio_observable_notify_any_observer

参数说明

Req.in.header或者req.in.iov[i].iov_base如果设置为NULL,那么当收到消息时,iov_base会设置为task->mbuf的地址,参看函数xio_rdma_on_recv_req

Send/recv

流程和上面的类似,除了没有response,接收方收到消息后,会触发一个回调,可选的确认通知

连接管理

状态变迁

Session状态变迁

XIO_SESSION_STATE_INIT 初始创建

XIO_SESSION_STATE_CONNECT 尝试建立连接(调用xio_connect接口之后,立即设置)

XIO_SESSION_STATE_ONLINE (该session上的所有connection都已经建立连接)

XIO_SESSION_STATE_ACCEPTED (该session上的部分connection已经建立连接)

处于INIT状态时,client调用xio_connect,会创建xio_connection,同时也会创建xio_conn

Xio_connect调用之后,状态变为CONNECT,此时有另外的线程再调用xio_connect,只会创建xio_connection,不会创建xio_conn,

enum xio_transport_state {

XIO_STATE_INIT,

XIO_STATE_CONNECTED,

XIO_STATE_DISCONNECTED,

XIO_STATE_CLOSED,

XIO_STATE_DESTROYED,

};

连接建立

l Xio_conn建立

Client端:

1.xio_on_connection_established -- xio_conn_initial_pool_setup

xio_conn_send_setup_req

2.xio_conn_on_recv_setup_rsp -- xio_conn_primary_pool_setup

3.xio_on_client_conn_established

如果SESSION状态不为ACCEPTED或ONLINE转到下面的session建立,否则转xio_connection建立

Server端:

1.xio_on_new_connection—xio_conn_create(listener创建新连接)-- xio_conn_initial_pool_setup

xio_on_new_conn--xio_conn_accept(accept新创建的连接)

2.xio_conn_on_recv_setup_req-- xio_conn_primary_pool_setup

xio_conn_write_setup_rsp

3.xio_conn_on_send_setup_rsp_comp

4.xio_on_server_conn_established

转到下面的session建立

l Xio_connection建立

Client端:

xio_connection_send_hello_req

Server端:

xio_on_new_message

xio_session_alloc_connection

xio_session_assign_conn(xio_conn.c)

xio_on_connection_hello_req_recv(xio_session)

xio_connection_send_hello_rsp(xio_session.c)

xio_session_notify_new_connection(xio_session.c)

l Xio_session建立:

Client端:

xio_session_write_setup_req

xio_conn_on_recv_rsp(xio_conn.c)

xio_on_setup_rsp_recv(xio_session.c)

session->state = XIO_SESSION_STATE_ACCEPTED;或者XIO_SESSION_STATE_ONLINE

Server端:

xio_conn_on_recv_req(xio_conn.c)

xio_on_new_message(xio_server.c)

xio_session_init(xio_server.c)

xio_session_alloc_connection(xio_server.c)

xio_session_assign_conn(xio_server.c)

xio_on_setup_req_recv(xio_session_server.c)

on_new_session或者(xio_accept)(xio_session_server.c)

xio_session_write_accept_rsp(XIO_SESSION_SETUP_RSP)

xio_on_setup_rsp_send_comp

xio_session_notify_new_connection(xio_session.c)

疑问:

xio_conn_connect 中为什么要判断XIO_CONN_STATE_CONNECTED这个状态

同一个ctx中,不同session的xio_connection公用同一个xio_conn,每个ctx中,一个地址只能对应一个xio_conn

连接销毁

l 检测掉线

a) Transport层有事件产生,通知观察者

b) xio_on_connection_disconnected(xio_conn.c)

c) 如果xio_conn没有注册任何观察者,转i,否则转c

d) xio_on_conn_event_client(xio_on_conn_event_server)(xio_session_client.c)

e) xio_on_conn_disconnected(xio_session.c)

f) 还存在xio_connection和xio_conn关联,xio_session_notify_connection_disconnected,状态发生变换,通知session做相应处理,不存和xio_connection关联的xio_conn转f

g) xio_session_disconnect-- xio_session_notify_connection_teardown-- session->ses_ops.on_session_event --xio_connection_destroy,执行xio_conn_close,转h,xio_connection_close,并判断是否需要销毁session,xio_session_notify_teardown-- xio_session_destroy-- xio_session_post_teardown

h) 没有xio_connection和xio_conn关联(listener的情况),直接调用xio_conn_close关闭连接,计算引用数,不为1时转o

i) xio_conn_release

j) transport->close

k) xio_rdma_close

l) xio_rdma_notify_observer

m) xio_on_conn_closed

n) kfree(conn)

o) Session是客户端,针对session中的其他xio_connection逐一调用xio_session_notify_connection_disconnected

l 主动关闭一

a) xio_disconnect-- xio_send_fin_req

xio_session_notify_connection_closed

b) xio_on_fin_rsp_recv-- xio_connection_fin_put-- xio_fin_complete-- xio_session_disconnect-- xio_session_notify_connection_teardown,其他部分同上

l 主动关闭二

c) xio_connection_destroy-- xio_connection_flush_tasks

xio_conn_close

xio_connection_close

l 销毁session

a) 释放资源,

说明,只释放资源,因此需要等连接都已经关闭之后才能调用,

Rdma_hndl的释放,主动关闭时,调用xio_conn_close最终会调用xio_rdma_close,这个函数会根据当前conn的状态进行处理,如果是connected状态则调用disconnect函数,其他情况,这里还有init状态和disconnected状态,则通过notify调用xio_on_conn_closed释放资源最后修改状态为destroy状态,,

当断线时,disconnected处理函数最终会调用xio_conn_release来释放conn,会调用到函数xio_rdma_close,这时候就不需要再调用disconnect函数,直接释放资源,

  • 资料

首页:http://www.accelio.org/

代码:https://github.com/accelio/

Accelio技术白皮书

声明:本文所用图片和部分内容来自accelio官网和白皮书。转载本博文章须在文章明显处注明作者及附上原文链接,便于读者找到原文的更新版。

时间: 2024-10-15 05:23:50

Accelio 代码笔记的相关文章

多线程二(GCD)代码笔记

// // TWFXViewController.h // Demo_GCD // // Created by Lion User on 12-12-11. // Copyright (c) 2012年 Lion User. All rights reserved. // #import <UIKit/UIKit.h> @interface TWFXViewController : UIViewController @property (retain, nonatomic) IBOutlet

JfinalUIB 代码笔记 (4)--- 高仿ibatis(mybatis)实现sql的集中管理

实现sql的集中管理,简单的把一些固定长度的sql移植进xml很简单,这没有什么好多说的,关键问题是我们平时处理的sql,有大量是动态长度的,比如说最常见的就是多条件的分页查询,往往我们会在代码中写大量的if else,想把这些移植进xml就比较困难了,完全仿制ibatis来做xml标签工作量太大,最省事的处理方法就是能不能直接把Java代码的逻辑处理方式移植进xml,然后对逻辑代码进行解析,绕开那一大堆的xml标签定义,下面就是jfinaluib中的处理方式: 1.0 暂时还是用的拼接,没有预

汇编代码笔记 动态更新中

汇编考完了,悲剧的93分,,,,,以后的汇编就用的少了,凡是用到都来这里做点代码笔记: 一.错误总结: 1.程序最后END +起始标号,否则U的时候需要自己手动找起始位置而且有可能程序翻译指令错误 2.对内存单元进行操作的时候,注意类型的指定,比如inc [si]必然是错的因为没有类型,还有处理数据计数器si注意加一 3.凡是用到[si]这种形式的,都注意声明BYTEPTR,WORD PTR 4.同3的错误,如果声明了COUNTDB 3,那么mov cx,count就是不对的,因为类型不匹配 5

《linux 内核完全剖析》 vsprintf.c 代码笔记

Flex1 到 Flex3 使用的都是 Halo组件,这里将介绍Halo 组件中的List 和 DataGrid .其中 DataGrid 是显示多列数据中最常用的方式.但是在Spark中还有没对应DataGrid的组件. 先写个"食物"的模型 Dinner.as . package model { [Bindable] public class Dinner { public var name:String; public var food:String; public var du

资源 | 数十种TensorFlow实现案例汇集:代码+笔记

选自 Github 机器之心编译 参与:吴攀.李亚洲 这是使用 TensorFlow 实现流行的机器学习算法的教程汇集.本汇集的目标是让读者可以轻松通过案例深入 TensorFlow. 这些案例适合那些想要清晰简明的 TensorFlow 实现案例的初学者.本教程还包含了笔记和带有注解的代码. 项目地址:https://github.com/aymericdamien/TensorFlow-Examples 教程索引 0 - 先决条件 机器学习入门: 笔记:https://github.com/

【代码笔记】Java连连看项目的实现(2)——JTable 、TableModel的使用

博客有时间就写写,所以一篇可能会拆成很多篇,写完后计划再合在一起. 首先肯定是要实现连连看的界面. 先准备连连看要的图片.. “LianLianKan”就是项目名称. 当然,如果小白看我的博客想学到什么,我会说还是放弃,因为文字描述会忽视很多细节,而细节决定bug…… 所以,包括以前的和以后的,博文都会是给自己看看或者内行触类旁通的,也就是——笔记. 我也是今天才明白博文的真正意义吧,所以以后的博文风格会大改……尽量会用自己语言风格来描述以便自己能看懂. 废话少说,现在的第2步: 创建数组,一个

mysql20170410练习代码+笔记

今天的几道高级sql查询真的挺难的,感觉好像视频里讲过,当时也没有练,已经淡化了很多,sql还是要多练习啊!确实逻辑性挺强的. SELECT studentResult,studentNO FROM result WHERE result.`subjectNo`=(SELECT subjectNo FROM `subject`) SELECT studentResult FROM result WHERE result.subjectNo = (SELECT subjectNo FROM SUB

【代码笔记】Java深入学习——实现客户端发送文件到服务器的文件传输

Server.java package com.huaxin.lesson02; import java.io.FileOutputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.net.ServerSocket; import java.net.Socket; /** * @thing 实现客户端发送文件到服务器 * @thing 客户端发送到客户端(本代码未实现) * @aut

数十种TensorFlow实现案例汇集:代码+笔记

这是使用 TensorFlow 实现流行的机器学习算法的教程汇集.本汇集的目标是让读者可以轻松通过案例深入 TensorFlow. 这些案例适合那些想要清晰简明的 TensorFlow 实现案例的初学者.本教程还包含了笔记和带有注解的代码. 项目地址:https://github.com/aymericdamien/TensorFlow-Examples 教程索引 0 - 先决条件 机器学习入门: 笔记:https://github.com/aymericdamien/TensorFlow-Ex