diff --git a/flow/daos_flow_plant_uml.md b/flow/daos_flow_plant_uml.pu similarity index 100% rename from flow/daos_flow_plant_uml.md rename to flow/daos_flow_plant_uml.pu diff --git a/flow/daos_flow_vos.pu b/flow/daos_flow_vos.pu new file mode 100644 index 00000000000..2ec3f830816 --- /dev/null +++ b/flow/daos_flow_vos.pu @@ -0,0 +1,39 @@ +'在线渲染: https://www.planttext.com/' +'使用文档: https://plantuml.com/zh/sequence-diagram' + + +@startwbs + +title DAOS_VOS单元测试 + ++ vos_tests.c + + main + + daos_debug_init + + vos_self_init + + ABT_init(0, NULL) 初始化Argobots执行环境 + + vos_start_epoch = 0 + + vos_standalone_tls_init(DAOS_TGT_TAG) 运行target XS + + self_mode.self_tls = vos_tls_init(tags, 0 /* xs_id */, -1 /* target_id */) + + 分配tls, 初始化gc池链表头 + + vos_obj_cache_create(LRU_CACHE_BITS, &tls->vtl_ocache) pm内存对象缓存(大小16, nr=8192) + + daos_lru_cache_create(cache_size, D_HASH_FT_NOLOCK, &obj_lru_ops, occ) + + d_hash_table_create_inplace + + d_uhash_create(D_HASH_FT_NOLOCK, VOS_POOL_HHASH_BITS, &tls->vtl_pool_hhash) 池hash + + d_uhash_create vtl_cont_hhash 容器hash + + umem_init_txd(&tls->vtl_txd) -> 为了避免为每个事务分配阶段数据,umem 用户应该准备每个 xstream 阶段数据并通过 umem_init_txd() 对其进行初始化,该每个 xstream 阶段数据将用于同一 xstream 中的所有事务 + + vos_self_init + + vos_self_nvme_init(db_path) + + vos_mod_init() + + vos_db_init_ex(db_path, "self_db", true, true) + + db = vos_db_get() + + rc = smd_init(db) + + bio_xsctxt_alloc(&self_mode.self_xs_ctxt, tgt_id, true) + + Using distance with closest side split for evtree + + run_all_tests(int keys) -> 运行所有的测试 + + dts_create_config(cfg_desc_io, "keys=%d", keys) + + run_ts_tests -> lru + + ... + + run_wal_tests(cfg_desc_io) + + ... + +@endwbs diff --git a/daos_io_path.md b/flow/daos_io_path_dfuse_write_array_write.pu similarity index 91% rename from daos_io_path.md rename to flow/daos_io_path_dfuse_write_array_write.pu index e0c22c981db..cb0dae98413 100644 --- a/daos_io_path.md +++ b/flow/daos_io_path_dfuse_write_array_write.pu @@ -29,7 +29,11 @@ fuse_buf_copy(&ibuf, bufv, 0) 拷贝用户数据 dfuse -> dfs: dfs_write(oh->doh_dfs, oh->doh_obj, &ev->de_sgl, position, &ev->de_ev) \n\ daos_array_write(obj->oh, DAOS_TX_NONE, &iod, sgl, ev) \n\ -dc_task_create(dc_array_write, NULL, ev, &task) 创建任务 \n\ +dc_task_create(dc_array_write, NULL, ev, &task) 写数组任务 \n\ + tse_task_create(func, sched, NULL, &task) \n\ + tse_task_register_comp_cb(task, task_comp_event, NULL, 0) 注册写数组任务回调(任务发送完成回调) \n\ +args->iod = iod \n\ +args->sgl = sgl 将SGL设置到任务参数上 \n\ dc_task_schedule(task, true) 调度客户端写数组任务 dfs -> array: dc_array_write 写数组(IO) diff --git a/flow/tse_eq/tse_eq_ev_task_data_struct_and_api.c b/flow/tse_eq/tse_eq_ev_task_data_struct_and_api.c deleted file mode 100644 index d593e375c8b..00000000000 --- a/flow/tse_eq/tse_eq_ev_task_data_struct_and_api.c +++ /dev/null @@ -1,373 +0,0 @@ -/* 事件队列 */ -typedef struct daos_eq { - /* After event is completed, it will be moved to the eq_comp list */ - d_list_t eq_comp; - int eq_n_comp; - - /** Launched events will be added to the running list */ - d_list_t eq_running; - int eq_n_running; - - int use_lock; - int is_polling; - int eq_fd; - - struct { - uint64_t space[72]; - } eq_private; - -} daos_eq_t; - - -/* EQ私有数据 */ -struct daos_eq_private { - /* link chain in the global hash list */ - struct d_hlink eqx_hlink; - pthread_mutex_t eqx_lock; - unsigned int eqx_lock_init:1, - eqx_finalizing:1; - - /* CRT context associated with this eq */ - crt_context_t eqx_ctx; - - /* Scheduler associated with this EQ */ - tse_sched_t eqx_sched; -}; - - - - - -/* 任务类型 */ -typedef struct tse_task { - int dt_result; - /** padding bytes */ - int dt_pad32; - /* daos schedule internal */ - struct { - char dt_space[TSE_PRIV_SIZE]; - } dt_private; -} tse_task_t; - - -/* 任务私有数据 */ -struct tse_task_private { - struct tse_sched_private *dtp_sched; - - /* function for the task */ - tse_task_func_t dtp_func; - - /* links to user task list like tse_task_list_add/_del etc APIs */ - d_list_t dtp_task_list; - - /* links to scheduler */ - d_list_t dtp_list; - - /* time to start running this task */ - uint64_t dtp_wakeup_time; - - /* list of tasks that depend on this task */ - d_list_t dtp_dep_list; - - /* daos prepare task callback list */ - d_list_t dtp_prep_cb_list; - - /* daos complete task callback list */ - d_list_t dtp_comp_cb_list; - - /* task has been completed */ - ATOMIC uint8_t dtp_completed; - /* task is in running state */ - ATOMIC uint8_t dtp_running; - /* Don't propagate err-code from dependent tasks */ - uint8_t dtp_no_propagate; - uint8_t dtp_pad; - /* number of dependent tasks */ - uint16_t dtp_dep_cnt; - /* refcount of the task */ - uint16_t dtp_refcnt; - /** - * task parameter pointer, it can be assigned while creating task, - * or explicitly call API tse_task_priv_set. User can just use - * \a dtp_buf instead of this if parameter structure is enough to - * fit in. - */ - void *dtp_priv; - /** - * DAOS internal task parameter pointer. - */ - void *dtp_priv_internal; - /** - * reserved buffer for user to assign embedded parameters, it also can - * be used as task stack space that can push/pop parameters to - * facilitate I/O handling. The embedded parameter uses buffer from the - * bottom, and the stack space grows down from top. - * - * The sum of dtp_stack_top and dtp_embed_top should not exceed - * TSE_TASK_ARG_LEN. - */ - uint16_t dtp_stack_top; - uint16_t dtp_embed_top; - /* generation of the task, +1 every time when task re-init or add dependent task */ - ATOMIC uint32_t dtp_generation; - char dtp_buf[TSE_TASK_ARG_LEN]; -}; - - -/* 调度器类型 */ -typedef struct { - int ds_result; - - /* user data associated with the scheduler (completion cb data, etc.) */ - void *ds_udata; - - /* daos schedule internal */ - struct { - uint64_t ds_space[48]; - } ds_private; -} tse_sched_t; - - - -/* 调度器私有数据 */ -struct tse_sched_private { - /* lock to protect schedule status and sub task list */ - pthread_mutex_t dsp_lock; - - /* The task will be added to init list when it is initially - * added to scheduler without any delay. A task with a delay - * will be added to dsp_sleeping_list. - */ - d_list_t dsp_init_list; - - /* The task will be moved to complete list after the - * complete callback is being executed - **/ - d_list_t dsp_complete_list; - - /** - * The task running list. - **/ - d_list_t dsp_running_list; - - /* list of sleeping tasks sorted by dtp_wakeup_time */ - d_list_t dsp_sleeping_list; - - /* the list for complete callback */ - d_list_t dsp_comp_cb_list; - - /* 目标引擎异常, task暂存到homeless队列 */ - d_list_t dsp_homeless_list; - - int dsp_refcount; - - /* number of tasks being executed */ - int dsp_inflight; - - uint32_t dsp_cancelling:1, - dsp_completing:1; -}; - - -/* 调度器完成回调 */ -typedef int (*tse_sched_comp_cb_t)(void *args, int rc); - -/* 任务主体函数 */ -typedef int (*tse_task_func_t)(tse_task_t *); - -/* 任务回调 */ -typedef int (*tse_task_cb_t)(tse_task_t *, void *arg); - - -/////////////////////////////////////////////////////////// - -/* 创建EQ, 创建网络上下文, 初始化调度器(初始/运行/完成/休眠/完成回调等队列), 设置调度器引用计数和飞行计数, 注册调度器回调, 为调度器绑定私有数据(如网络上下文), 注册完成回调 -> 完成回调等队列 */ -int daos_eq_create(daos_eq_t *eq_out, int use_lock, int is_polling) -{ - struct daos_eq_private *eqx; - struct daos_eq *eq; - int rc = 0; - - D_ALLOC_PTR(eq); - D_INIT_LIST_HEAD(&eq->eq_running); - D_INIT_LIST_HEAD(&eq->eq_comp); - eq->eq_n_running = 0; - eq->eq_n_comp = 0; - - eq->use_lock = use_lock; - eq->is_polling = is_polling; - - eqx = daos_eq2eqx(eq); - rc = D_MUTEX_INIT(&eqx->eqx_lock, NULL); - eqx->eqx_lock_init = 1; - - // 创建网络上下文 - rc = crt_context_create(&eqx->eqx_ctx); - eq->eq_fd = hrpc_mod_fd_get(&eqx->eqx_ctx); - /* 为EQ初始化调度器 */ - rc = tse_sched_init(&eqx->eqx_sched, NULL, eqx->eqx_ctx); - *eq_out = eq; -} - - - -/* 初始化调度器 (初始/运行/完成/休眠/完成回调等队列), 设置调度器引用计数和飞行计数, 注册调度器回调, 为调度器绑定私有数据(如网络上下文) */ -int tse_sched_init(tse_sched_t *sched, tse_sched_comp_cb_t comp_cb, void *udata) -{ - struct tse_sched_private *dsp = tse_sched2priv(sched); - int rc; - - - D_INIT_LIST_HEAD(&dsp->dsp_init_list); - D_INIT_LIST_HEAD(&dsp->dsp_running_list); - D_INIT_LIST_HEAD(&dsp->dsp_complete_list); - D_INIT_LIST_HEAD(&dsp->dsp_sleeping_list); - D_INIT_LIST_HEAD(&dsp->dsp_comp_cb_list); - - D_INIT_LIST_HEAD(&dsp->dsp_homeless_list); - - - if (comp_cb != NULL) { - rc = tse_sched_register_comp_cb(sched, comp_cb, udata); - if (rc != 0) - return rc; - } - - sched->ds_udata = udata; - sched->ds_result = 0; -} - -/* 事件EV */ -typedef struct daos_event { - /** return code of non-blocking operation */ - int ev_error; - /** Internal use - 152 + 8 bytes pad for pthread_mutex_t size difference on __aarch64__ */ - struct { - uint64_t space[20]; - } ev_private; - /** Used for debugging */ - uint64_t ev_debug; -} daos_event_t; - -/* 事件私有数据 */ -struct daos_event_private { - daos_handle_t evx_eqh; - d_list_t evx_link; - /** children list */ - d_list_t evx_child; - unsigned int evx_nchild; - unsigned int evx_nchild_running; - unsigned int evx_nchild_comp; - /** flag to indicate whether event is a barrier event */ - unsigned int is_barrier:1; - /** flag to indicate whether to convert DER to errno */ - unsigned int is_errno:1; - - unsigned int evx_flags; - ATOMIC daos_ev_status_t evx_status; - - struct daos_event_private *evx_parent; - - crt_context_t evx_ctx; - struct daos_event_callback evx_callback; - - tse_sched_t *evx_sched; - /** Lock for events that are not in an EQ, including the thread private event */ - pthread_mutex_t evx_lock; -}; - - -// 事件完成回调 -typedef int (*daos_event_comp_cb_t)(void *, daos_event_t *, int); - -// 事件初始化 -int daos_event_init(struct daos_event *ev, daos_eq_t eq, struct daos_event *parent) -{ - atomic_init(&evx->evx_status, DAOS_EVS_READY); - evx->evx_ctx = daos_eq_ctx; // 全局网络上下文或eqx上的网络 - evx->evx_sched = &daos_sched_g; // 全局调度器或eqx上的调度器 -} - -// 为事件注册完成回调 -int daos_event_register_comp_cb(struct daos_event *ev, daos_event_comp_cb_t cb, void *arg) -{ - ecl->op_comp_cb = cb; - d_list_add_tail(&ecl->op_comp_list, &evx->evx_callback.evx_comp_list); -} - - -// 启动事件 -int daos_event_launch(struct daos_event *ev) -{ - // 启动事件, 已就绪事件才能启动, 检查子事件个数, 如果运行中+已完成的子事件个数小于子事件总数, 则返回, 即所有子事件启动后才能启动父事件; 如果事件在终止中,则退出, - evx->evx_status = DAOS_EVS_RUNNING; - - // 将事件加入EQ运行队列, EQ运行计数+1 - d_list_add_tail(&evx->evx_link, &eq->eq_running); - eq->eq_n_running++; -} - -// 完成事件, 任务完成时一般会调用EV完成 -void daos_event_complete(struct daos_event *ev, int rc) -{ - // 遍历事件回调上的完成队列并执行回调, 原子标记事件为已完成, 如有父事件, 更新父事件上子事件的运行和完成计数, 修改父事件状态, 完成被屏障拦住的父事件, 将自己设置为父事件等, 将事件从EQ运行队列移动到EQ的完成队列, EQ完成计数+1,同时EQ运行计数-1 - // 封装函数: daos_event_complete_cb - d_list_for_each_entry_safe(ecl, tmp, &evx->evx_callback.evx_comp_list, op_comp_list) { - d_list_del_init(&ecl->op_comp_list); - err = ecl->op_comp_cb(ecl->op_comp_arg, daos_evx2ev(evx), rc); - D_FREE(ecl); - } -} - -// 销毁EQ(或强制,及不检查EQ运行和完成队列为空),运行和完成队列不为空且非强制模式, 则返回设备繁忙错误(DER_BUSY), 将EQ标记为终止中防止其他线程启动事件, 下刷EQ上网络上下文中的RPC, 终止所有启动的EV(运行队列上的EV), 如果该EQ上的网络不是全局的网络上下文, 则将该网络上下文销毁,即保留全局的那个网络上下文, 将EQ的网络上下文指针置空 -int daos_eq_destroy(daos_eq_t eq, int flags); - - - -// 轮询EQ, 返回事件个数和事件列表, 内部区分中断和轮训模式 -int daos_eq_poll(daos_eq_t eq, int wait_running, int64_t timeout, unsigned int n_events, struct daos_event **events) - - -// 终止事件, 从各种列表、parent_list、子列表和事件队列哈希列表中取消事件链接,并销毁所有子事件, EV不能是运行中, 销毁EV锁, 处理子EV, 处理父EV, 删除EV的链表, EV上的网络上下文置空, EQ引用-1 -int daos_event_fini(struct daos_event *ev) // 终止事件, 从各种列表、parent_list、子列表和事件队列哈希列 - - -// 创建任务, 依次传入: 任务函数, 调度器, 私有参数(一般是NULL), 任务二级指针(待返回的任务), 主要逻辑: 拿到调度器私有数据, 新建一个任务, 初始化该任务的链表, 任务队列, 依赖队列, 完成回调队列, 任务前置回调函数队列, 任务引用+1, 设置主体函数, 私有参数和调度器, 返回该任务 -int tse_task_create(tse_task_func_t task_func, tse_sched_t *sched, void *priv, tse_task_t **taskp) -// 参考用法: tse_task_create(check_func_n, &sched, counter, &task) - - -// 为任务注册完成回调, 参考用法: tse_task_register_comp_cb(task, task_comp_event, NULL, 0) -int tse_task_register_comp_cb(tse_task_t *task, tse_task_cb_t comp_cb, void *arg, daos_size_t arg_size) - - - -// 调度任务, 参数: 任务, 立即调度, 主流程: 从task拿到调度器, 如果该任务没有依赖任务且任务前置工作也做完了, 则该任务已就绪, 则将调度器飞行计数+1, 设置调度器为运行中, 设置唤醒时间为0, 将任务加入调度器的运行队列, 可立即执行主体任务(忽略任务返回值) -int tse_task_schedule(tse_task_t *task, bool instant) -// 参考用法: tse_task_schedule(task, true) - - - -// 获取调度器进展(进度): 如果调度器是取消中, 则直接返回, 否则, 运行调度器 -> tse_sched_run(sched) -void tse_sched_progress(tse_sched_t *sched) -// 参考用法: tse_sched_progress(&sched) - - -// 在调度器上运行一轮任务(依次执行初始化调度器进展, 处理调度器完成, 检查完成): 完成调度器或没有任务处理时才返回 -static void tse_sched_run(tse_sched_t *sched) -// 初始化调度器进展: 将休眠中唤醒的任务加入初始队列, 遍历初始队列, 将没有依赖的主任务, 或者调度器处于取消状态时, 将该任务加入临时队列, 遍历临时队列, 如果调度器被取消, 则直接完成该任务(修改计数器, 标记任务完成, 加入调度器完成队列), 否则加入运行队列, 接着如果执行任务主体函数, 返回处理的个数 -static int tse_sched_process_init(struct tse_sched_private *dsp) - -// 处理调度器完成: 将任务从调度器完成队列移除, 设置任务调度器结果, 检查任务依赖, 修改计数器 -tse_sched_process_complete(dsp) - -// 检查调度器是否完成(所有任务执行完成, 初始和休眠队列为空,且无飞行中的任务) -bool tse_sched_check_complete(tse_sched_t *sched) - - -// 完成任务: 传入任务和返回值, 执行任务回调 -> tse_task_complete_callback(task), 完成任务, 更新调度器列表, 将该任务从调度器的完成列表移除 -tse_task_complete(task, rc) - -// 执行任务回调: 遍历任务上的完成回调列表,如果所有CB都执行完毕并且不重新初始化任务,则返回true。 如果任务被用户重新初始化,则意味着它再次处于运行状态,因此我们在重新初始化它的当前 CB 处中断,并返回 false,这意味着任务尚未完成。 所有剩余未执行的 CB 仍保持附加状态,但已执行的 CB 此时已从列表中删除, -static bool tse_task_complete_callback(tse_task_t *task) - diff --git a/readme b/readme index 6a420165675..8f534fb099b 100644 --- a/readme +++ b/readme @@ -40,7 +40,7 @@ cart流程: 1. 日志初始化/注册协议和操作码 crt_init_opt 2. 创建上下文(fabric->domain->endpoint->cq...) crt_context_create 3. 创建请求 crt_req_create / crt_corpc_req_create RPC请求集合 传入目的端点 -> ep_rank -4. 发送请求(请求跟踪和取消跟踪) crt_req_send / dss_rpc_send +4. 发送请求(请求跟踪和取消跟踪) crt_req_send / dss_rpc_send, 客户端发送: daos_rpc_send 5. 查看请求进度和回调(progress和trigger) crt_progress 6. 发送回复 crt_reply_send / crt_reply_get @@ -722,12 +722,12 @@ crt_req_send(req, shard_update_req_cb, remote_arg) 将用户回调设置为完 dmg server set-logmasks err -vos_tests: gdb /opt/daos/bin/vos_tests -> main -> vos_tests.c -> test_ut_vos.test.sh +vos_tests: gdb /opt/daos/bin/vos_tests -> main -> vos_tests.c -> vos单元测试 set args -p -daos_debug_init +daos_debug_init -> 日志初始化, 同步日志掩码, 默认日志文件:/tmp/daos.log strcpy(vos_path, "/mnt/daos") -vos_self_init(vos_path, false, BIO_STANDALONE_TGT_ID) - ABT_init(0, NULL) +vos_self_init(vos_path, false, BIO_STANDALONE_TGT_ID) -> 初始化vos, 不用系统数据库, 初始化VOS实例的环境 必须在启动VOS实例之前调用一次 注意:仅当使用VOS作为独立库时需要 + ABT_init(0, NULL) -> 初始化Argobots执行环境, ABT_init() 初始化 Argobots 执行环境。 如果 Argobots 尚未初始化,ABT_init() 的第一个调用者将成为在主执行流上运行的主 ULT。 如果 Argobots 已经初始化,ABT_init() 会原子地递增引用计数器。 即使 Argobots 已经初始化,此例程也会返回 ABT_SUCCESS vos_standalone_tls_init(DAOS_TGT_TAG) vos_self_nvme_init(db_path) dbtree_class_register(DBTREE_CLASS_IV, BTR_FEAT_UINT_KEY | BTR_FEAT_DIRECT_KEY, &dbtree_iv_ops) @@ -757,7 +757,7 @@ vos_self_init(vos_path, false, BIO_STANDALONE_TGT_ID) rc = smd_init(db) bio_xsctxt_alloc(&self_mode.self_xs_ctxt, tgt_id, true) Using distance with closest side split for evtree -run_all_tests(int keys) -> 所有的测试 +run_all_tests(int keys) -> 运行所有的测试 dts_create_config(cfg_desc_io, "keys=%d", keys) run_ts_tests -> lru ... @@ -959,21 +959,6 @@ d_slab_restock(eqt->de_write_slab) -> 重用slab -vos_blob_format_cb - bio_write_blob_hdr - bio_write - bio_rw - bio_rwv - bio_iod_post 提交io描述 - dma_rw - nvme_rw - spdk_blob_io_write rw_completion - blob_request_submit_op - blob_request_submit_op_single - bs_batch_write_dev - blob_bdev->bs_dev.write - bdev_blob_write - spdk_bdev_write_blocks @@ -1080,7 +1065,7 @@ dfuse_main.c -> main dfuse_progress_thread rc = sem_wait(&fs_handle->dpi_sem) 等dpi_sem信号 - daos_eq_poll + daos_eq_poll -> 先轮训事件, 然后自己调回调 daos_event_fini 完成一个事件。 如果事件已被传递到任何 DAOS API,则它只能在从 EQ 中轮询出来时才能完成,即使通过调用 daos_event_abort() 中止也是如此。 如果事件是用父事件初始化的,那么该事件将从父事件的子列表中删除。 如果ev本身是一个父事件,那么这个函数会finalize所有的子事件和ev, 此调用返回后,ev 中的条目不应被视为有效 ev->de_complete_cb(ev) -> dfuse_cb_write_complete 写完成回调 @@ -3206,7 +3191,7 @@ dss_srv_handler 服务控制器,设置cpu亲和性,初始化TLS,crt, nvm for (;;) 死循环 crt_progress -vos_tls_init 初始化vos本地线程存储 +vos_tls_init 初始化vos本地线程存储 D_INIT_LIST_HEAD(&tls->vtl_gc_pools) vos_obj_cache_create(LRU_CACHE_BITS 创建lru d_uhash_create vtl_pool_hhash vtl_cont_hhash @@ -3791,7 +3776,14 @@ tgt_vos_create_one struct bio_xs_context *xs_ctxt = vos_xsctxt_get() -> 每个xs一个nvme上下文 store.store_type = umempobj_get_backend_type() -> 默认pm作后端, daos_md_backend = DAOS_MD_PMEM bio_mc_create(xs_ctxt, pool_id, meta_sz, wal_sz, nvme_sz, mc_flags) - bio_mc_open(xs_ctxt, pool_id, mc_flags, &mc) + bio_mc_open(xs_ctxt, pool_id, mc_flags, &mc) -> smd_pool_get_blob -> pool_get_blob + db_fetch(struct sys_db *db, char *table, d_iov_t *key, d_iov_t *val) + db_io_init(&io, table, key, val) + vos_obj_fetch -> vos_obj_fetch_ex + vos_fetch_begin + vos_ioc_create + vos_dth_set + vos_ts_set_add -> vos_ts_get_negative -> 当子树不存在时,我们需要一个负条目。 在这种情况下,条目由哈希值标识。 这会查找负条目并在必要时分配它。 将 te_create_idx 重置为 NULL bio_meta_get_attr(mc, &store.stor_size, &store.stor_blk_size, &store.stor_hdr_blks) pop = umempobj_create(path, layout, UMEMPOBJ_ENABLE_STATS, scm_sz, 0600, &store) pop = pmemobj_create(path, layout_name, poolsize, mode) -> 创建持久内存对象,取scm大小 -> pmdk笔记: https://blog.csdn.net/Sylvia_Wu51/article/details/117442789, 创建pm内存池: https://manpages.debian.org/experimental/libpmemobj-dev/pmemobj_create.3.en.html, 参考:持久内存编程开发人员综合指南 @@ -4177,8 +4169,8 @@ do { vos_blob_format_cb - bio_write_blob_hdr - bio_write + bio_write_blob_hdr -> 完成设置 blob 标头并将信息写入 blob 偏移量 0。 + bio_write -> 写入每个vos实例的blob bio_rw bio_rwv bio_iod_post 提交io描述 @@ -4256,6 +4248,10 @@ dfuse_progress_thread daos_eq_poll daos_event_fini 完成一个事件。 如果事件已被传递到任何 DAOS API,则它只能在从 EQ 中轮询出来时才能完成,即使通过调用 daos_event_abort() 中止也是如此。 如果事件是用父事件初始化的,那么该事件将从父事件的子列表中删除。 如果ev本身是一个父事件,那么这个函数会finalize所有的子事件和ev。 ev->de_complete_cb(ev) -> dfuse_cb_write_complete 写完成回调 + daos_event_fini(&ev->de_ev) -> 终止事件 + d_slab_release(ev->de_eqt->de_write_slab, ev) -> 将EV释放回EV池 + d_list_t *entry = ptr + type->st_reg.sr_offset -> 拿到条目, 放回阻塞链表 + d_list_add_tail(entry, &type->st_pending_list) struct fuse_lowlevel_ops dfuse_ops dfuse低层操作对象 .create = df_ll_create @@ -5516,14 +5512,34 @@ dlv attach `ps aux|grep 'daos_agent'|grep -v grep|awk '{print$2}'` bio_ut.c -> main -> bio单元测试 -run_wal_tests -wal_ut_setup -wal_uts +ut_args.bua_seed = (unsigned int)(time(NULL) & 0xFFFFFFFFUL) +run_wal_tests() +wal_ut_setup -> 前置函数 + ut_init(&ut_args) + daos_debug_init + vos_self_init(db_path, false, BIO_STANDALONE_TGT_ID); + ABT_init(0, NULL) + vos_start_epoch = 0 + vos_standalone_tls_init(DAOS_TGT_TAG) + vos_self_nvme_init(db_path) + vos_mod_init() -> 初始化vos模块 + vos_db_init_ex(db_path, "self_db", true, true) + smd_init(db) + bio_xsctxt_alloc(&self_mode.self_xs_ctxt, tgt_id, true) + if (!bio_nvme_configured(SMD_DEV_TYPE_MAX)) + ctxt->bxc_dma_buf = dma_buffer_create(bio_chk_cnt_init, tgt_id) -> DAOS-10372 bio:以 FIFO 顺序等待 DMA 缓冲区 (#9584) 当 DMA 缓冲区因繁重的工作负载而耗尽时,未能抓取 DMA 缓冲区的 IO 请求将不得不等待先前 IO 的完成,在以下情况下可能会发生饥饿:- 请求A无法抓取缓冲区,它开始等待先前的IO完成; - 后来请求B到达服务器,被推送到ABT池的先进先出队列中执行; - Prior IO完成,唤醒请求A,并将请求A推入ABT池的FIFO队列中执行; - 请求B将在请求A之前被处理,如果DMA缓冲区被请求B用完,请求A可能需要等待另一轮; 另一个问题是,一旦先前的 IO 完成,即使释放的缓冲区只能满足较少的等待者,所有等待者也会被唤醒,这会不必要地浪费 CPU 周期。 该补丁通过确保当有任何先前请求等待 DMA 缓冲区时所有传入请求都在 FIFO 队列中等待,解决了饥饿问题,并且等待者将按照 FIFO 顺序一一唤醒。 该补丁还引入了 DMA 缓冲区管理的遥测技术,抓取缓冲区失败时发出的错误消息受到速率限制 + ABT_cond_create(&buf->bdb_wait_iod) + bulk_cache_create(buf) + dma_metrics_init(buf, tgt_id) + dma_buffer_grow(buf, init_cnt) +wal_uts -> 单元测试 wal_ut_single + ut_mc_init + bio_mc_create wal_ut_many_acts wal_ut_checkpoint ... -wal_ut_teardown +wal_ut_teardown -> 后置函数 @@ -5847,3 +5863,61 @@ test_args_init -> 测试前置函数 vts_ctx_init + + +(gdb) p * (struct vos_io_context *) 0x555555db32e0 +$2 = {ic_ent_array_alloc = {ea_data = {ea_ents = 0x0, ea_ent_nr = 0, ea_size = 0, ea_max = 0, ea_inob = 0, ea_first_delete = 0, ea_delete_nr = 0, ea_embedded_ents = 0x555555db3300}, ea_embedded = {{le_prev = 0x0, le_link = {next = 0x0, + prev = 0x0}, le_ent = {en_ext = {ex_lo = 0, ex_hi = 0}, en_sel_ext = {ex_lo = 0, ex_hi = 0}, en_csum = {cs_csum = 0x0, cs_nr = 0, cs_type = 0, cs_len = 0, cs_buf_len = 0, cs_chunksize = 0}, en_ver = 0, en_visibility = 0, + en_minor_epc = 0, en_addr = {ba_off = 0, ba_type = 0 '\000', ba_pad1 = 0 '\000', ba_flags = 0, ba_pad2 = 0}, en_epoch = 0, en_avail_rc = 0}} }}, ic_ent_array = 0x0, ic_bound = 1, ic_epr = {epr_lo = 0, epr_hi = 1}, + ic_oid = {id_pub = {lo = 0, hi = 0}, id_shard = 0, id_layout_ver = 0, Segmentation fault + + +Breakpoint 1, vos_fetch_begin (coh=..., oid=..., epoch=1, dkey=0x7fffffffcc30, iod_nr=iod_nr@entry=1, iods=0x7fffffffcc48, vos_flags=0, shadows=0x0, ioh=0x7fffffffcb90, dth=0x0) at src/vos/vos_io.c:1472 +1472 { +Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64 json-c-0.11-4.el7_0.x86_64 libaio-0.3.109-13.el7.x86_64 libcmocka-1.1.5-1.el7.x86_64 libgcc-4.8.5-44.el7.x86_64 libibverbs-22.4-6.el7_9.x86_64 libnl3-3.2.28-4.el7.x86_64 librdmacm-22.4-6.el7_9.x86_64 libunwind-1.2-2.el7.x86_64 libuuid-2.23.2-65.el7_9.1.x86_64 libyaml-0.1.4-11.el7_0.x86_64 lz4-1.8.3-1.el7.x86_64 numactl-libs-2.0.12-5.el7.x86_64 openssl11-libs-1.1.1k-5.el7.x86_64 zlib-1.2.7-21.el7_9.x86_64 +(gdb) bt +#0 vos_fetch_begin (coh=..., oid=..., epoch=1, dkey=0x7fffffffcc30, iod_nr=iod_nr@entry=1, iods=0x7fffffffcc48, vos_flags=0, shadows=0x0, ioh=0x7fffffffcb90, dth=0x0) at src/vos/vos_io.c:1472 +#1 0x00007ffff77a7672 in vos_obj_fetch_ex (coh=..., oid=..., epoch=epoch@entry=1, flags=flags@entry=0, dkey=dkey@entry=0x7fffffffcc30, iod_nr=iod_nr@entry=1, iods=iods@entry=0x7fffffffcc48, sgls=0x7fffffffcc88, dth=0x0) at src/vos/vos_io.c:2837 +#2 0x00007ffff77a7c0a in vos_obj_fetch (coh=..., oid=..., epoch=epoch@entry=1, flags=flags@entry=0, dkey=dkey@entry=0x7fffffffcc30, iod_nr=iod_nr@entry=1, iods=iods@entry=0x7fffffffcc48, sgls=0x7fffffffcc88) at src/vos/vos_io.c:2875 +#3 0x00007ffff784885d in db_fetch (db=, table=0x7ffff7feba00 "pool", key=0x7fffffffccd0, val=0x7fffffffccf0) at src/vos/sys_db.c:223 +#4 0x00007ffff7fcbc85 in smd_db_fetch (table=table@entry=0x7ffff7feba00 "pool", key=key@entry=0x7fffffffcd20, key_size=key_size@entry=16, val=val@entry=0x7fffffffcd30, val_size=val_size@entry=784) at src/bio/smd/smd_store.c:29 +#5 0x00007ffff7fc98dc in pool_get_blob (pool_id=pool_id@entry=0x5555555612f0 "\217\020\336\271\250\033C\346\256\302Ǡ\264\215\"[Q\336\370d", tgt_id=4294967295, table_name=table_name@entry=0x7ffff7feba00 "pool", + blob_id=blob_id@entry=0x7fffffffd0a0) at src/bio/smd/smd_pool.c:279 +#6 0x00007ffff7fca640 in smd_pool_get_blob (pool_id=pool_id@entry=0x5555555612f0 "\217\020\336\271\250\033C\346\256\302Ǡ\264\215\"[Q\336\370d", tgt_id=, st=st@entry=SMD_DEV_TYPE_DATA, + blob_id=blob_id@entry=0x7fffffffd0a0) at src/bio/smd/smd_pool.c:304 +#7 0x00007ffff7f78a95 in bio_mc_open (xs_ctxt=0x555555d9a280, pool_id=pool_id@entry=0x5555555612f0 "\217\020\336\271\250\033C\346\256\302Ǡ\264\215\"[Q\336\370d", flags=flags@entry=(unknown: 0), mc=mc@entry=0x5555555612e8 ) + at src/bio/bio_context.c:903 +#8 0x000055555555731c in ut_mc_init (args=args@entry=0x5555555612e0 , meta_sz=meta_sz@entry=134217728, wal_sz=wal_sz@entry=134217728, data_sz=data_sz@entry=134217728) at src/vos/tests/wal_ut.c:38 +#9 0x000055555555bd08 in wal_ut_single (state=) at src/vos/tests/wal_ut.c:307 +#10 0x00007ffff79cfda2 in cmocka_run_one_test_or_fixture () from /lib64/libcmocka.so.0 +#11 0x00007ffff79d07a5 in _cmocka_run_group_tests () from /lib64/libcmocka.so.0 +#12 0x000055555555d197 in run_wal_tests () at src/vos/tests/wal_ut.c:912 +#13 0x0000555555556584 in main (argc=1, argv=0x7fffffffdbb8) at src/vos/tests/bio_ut.c:90 + + + + + +---------- vea ---------- +vea_flush: 刷新老化缓冲区中的空闲碎片 + +vea_reserve: 在块设备上保留一个范围,如果块设备碎片太多而无法满足连续的保留,则可以保留一个范围向量 + +vea_load: 从 SCM 加载空间跟踪信息以初始化内存中复合索引 + + + + + +write_header + +alloc_prep_block: 分配准备的块, 内部, 准备一个用于分配的内存块一旦该块被完全保留并且保证没有其他人能够写入该内存区域,就可以安全地写入分配标头并调用对象构造函数。 由于此阶段的内存块仅以瞬态保留,因此无需担心此方法的故障安全性,因为如果发生崩溃,内存将返回到空闲块集合中 + + +palloc_reservation_create: 创建内存块的易失性保留。 分配新块的第一步是将其保留在临时堆中 - 这由存储桶抽象表示。 为了为多线程应用程序提供最佳扩展并减少碎片,根据当前线程上下文以及请求的大小属于哪个分配类来选择适当的存储桶。 一旦选择了存储桶,就会为请求的大小保留足够的内存。 底层块分配算法(best-fit、next-fit...)根据桶容器的不同而变化 + + +palloc_reserve: +palloc_operation: palloc_operation——持久内存操作。 获取 NULL 指针或现有内存块并将其修改为至少占用“size”个字节。 malloc、free 和 realloc 例程是在该通用操作的上下文中实现的,该操作包含通常在这些方法中单独完成的所有功能。 需要做的第一件事是确定哪些内存块将受到操作的影响 - 这取决于操作是否需要修改或释放现有块和/或分配新块。 简化的分配过程流程如下: 在临时堆中保留一个新块 准备新块 创建所需修改的重做日志 新对象的块元数据偏移量 提交并处理重做日志 类似地,释放过程: 创建所需修改的重做日志 所需的修改将块元数据反转回“空闲”状态将对象偏移的目标设置为零提交并处理重做日志有一个重要的区别 释放过程 - 它不会将内存块返回到临时容器。 一旦没有更多内存可用,就会完成此操作。 重新分配是上述内容的组合,并增加了复制旧内容的步骤 + + diff --git a/stop.sh b/stop.sh new file mode 100755 index 00000000000..05fc6dc1c84 --- /dev/null +++ b/stop.sh @@ -0,0 +1,37 @@ +echo -e "stop" + +# source /root/.bashrc +# run_all "pkill daos_agent;pkill daos_server" + +source /root/.bashrc +umount /mnt/daos +df -h|grep '/mnt/daos' + +pkill daos_agent +pkill daos_server + +rm -f /tmp/daos*.log +rm -f /tmp/.daos_engine.0.log.swp +rm -f /tmp/daos_engine* + +#export FI_LOG_LEVEL=debug +#export FI_LOG_LEVEL=warn + +#export HG_LOG_LEVEL=debug +#export HG_LOG_LEVEL=warn + +# echo -e "dmg storage format" + +# count=0 +# while true;do +# joined_num=`dmg sys query -v|grep Joined|wc -l` +# if [[ $joined_num -eq 3 ]];then +# break +# fi +# echo -e "wait all rank join, $count times" +# count=$((count+1)) +# sleep 1 +# done + +# centos7 +# cp -r /home/xb/project/stor/daos/main/daos/daosCA/certs /etc/daos/