/* * rpmemd_common_fip_init -- initialize fabric provider */ static int rpmemd_common_fip_init(struct rpmemd *rpmemd, const struct rpmem_req_attr *req, struct rpmem_resp_attr *resp, int *status) { /* register the whole pool with header in RDMA */ void *addr = (void *)((uintptr_t)rpmemd->pool->pool_addr); struct rpmemd_fip_attr fip_attr = { .addr = addr, .size = req->pool_size, .nlanes = req->nlanes, .nthreads = rpmemd->nthreads, .provider = req->provider, .persist_method = rpmemd->persist_method, .deep_persist = rpmemd_deep_persist, .ctx = rpmemd }; const int is_pmem = rpmemd_db_pool_is_pmem(rpmemd->pool); if (rpmemd_apply_pm_policy(&fip_attr.persist_method, &fip_attr.persist, is_pmem)) { *status = RPMEM_ERR_FATAL; goto err_fip_init; } const char *node = rpmem_get_ssh_conn_addr(); enum rpmem_err err; rpmemd->fip = rpmemd_fip_init(node, NULL, &fip_attr, resp, &err); if (!rpmemd->fip) { *status = (int)err; goto err_fip_init; } return 0; err_fip_init: return -1; } /* * rpmemd_print_req_attr -- print request attributes */ static void rpmemd_print_req_attr(const struct rpmem_req_attr *req) { RPMEMD_LOG(NOTICE, RPMEMD_LOG_INDENT "pool descriptor: '%s'", _str(req->pool_desc)); RPMEMD_LOG(NOTICE, RPMEMD_LOG_INDENT "pool size: %lu", req->pool_size); RPMEMD_LOG(NOTICE, RPMEMD_LOG_INDENT "nlanes: %u", req->nlanes); RPMEMD_LOG(NOTICE, RPMEMD_LOG_INDENT "provider: %s", rpmem_provider_to_str(req->provider)); }
/* * rpmemd_common_fip_init -- initialize fabric provider */ static int rpmemd_common_fip_init(struct rpmemd *rpmemd, const struct rpmem_req_attr *req, struct rpmem_resp_attr *resp, int *status) { void *addr = (void *)((uintptr_t)rpmemd->pool->pool_addr + POOL_HDR_SIZE); struct rpmemd_fip_attr fip_attr = { .addr = addr, .size = req->pool_size, .nlanes = req->nlanes, .nthreads = rpmemd->nthreads, .provider = req->provider, .persist_method = rpmemd->persist_method, .persist = rpmemd->persist, }; const char *node = rpmem_get_ssh_conn_addr(); enum rpmem_err err; rpmemd->fip = rpmemd_fip_init(node, NULL, &fip_attr, resp, &err); if (!rpmemd->fip) { *status = (int)err; goto err_fip_init; } return 0; err_fip_init: return -1; } /* * rpmemd_print_req_attr -- print request attributes */ static void rpmemd_print_req_attr(const struct rpmem_req_attr *req) { RPMEMD_LOG(NOTICE, "\tpool descriptor: '%s'", _str(req->pool_desc)); RPMEMD_LOG(NOTICE, "\tpool size: %lu", req->pool_size); RPMEMD_LOG(NOTICE, "\tnlanes: %u", req->nlanes); RPMEMD_LOG(NOTICE, "\tprovider: %s", rpmem_provider_to_str(req->provider)); }
/* * rpmemd_common_fip_init -- initialize fabric provider */ static int rpmemd_common_fip_init(struct rpmemd *rpmemd, const struct rpmem_req_attr *req, struct rpmem_resp_attr *resp, int *status) { void *addr = (void *)((uintptr_t)rpmemd->pool->pool_addr + POOL_HDR_SIZE); struct rpmemd_fip_attr fip_attr = { .addr = addr, .size = req->pool_size, .nlanes = req->nlanes, .nthreads = rpmemd->nthreads, .provider = req->provider, .persist_method = rpmemd->persist_method, .persist = rpmemd->persist, }; const char *node = rpmemd_get_ssh_addr(); enum rpmem_err err; rpmemd->fip = rpmemd_fip_init(node, NULL, &fip_attr, resp, &err); if (!rpmemd->fip) { *status = (int)err; goto err_fip_init; } return 0; err_fip_init: return -1; } /* * rpmemd_req_create -- handle create request */ static int rpmemd_req_create(struct rpmemd_obc *obc, void *arg, const struct rpmem_req_attr *req, const struct rpmem_pool_attr *pool_attr) { RPMEMD_ASSERT(arg != NULL); struct rpmemd *rpmemd = (struct rpmemd *)arg; int ret; int status = 0; int err_send = 1; struct rpmem_resp_attr resp; memset(&resp, 0, sizeof(resp)); if (rpmemd->pool) { RPMEMD_LOG(ERR, "pool already opened"); status = RPMEM_ERR_FATAL; goto err_pool_opened; } rpmemd->pool = rpmemd_db_pool_create(rpmemd->db, req->pool_desc, 0, (struct rpmem_pool_attr *)pool_attr); if (!rpmemd->pool) { status = rpmemd_db_get_status(errno); goto err_pool_create; } ret = rpmemd_check_pool(rpmemd, req, &status); if (ret) goto err_pool_check; ret = rpmemd_common_fip_init(rpmemd, req, &resp, &status); if (ret) goto err_fip_init; ret = rpmemd_obc_create_resp(rpmemd->obc, status, &resp); if (ret) { err_send = 0; goto err_create_resp; } ret = rpmemd_fip_accept(rpmemd->fip); if (ret) { status = RPMEM_ERR_FATAL_CONN; goto err_accept; } ret = rpmemd_fip_process_start(rpmemd->fip); if (ret) { status = RPMEM_ERR_FATAL_CONN; goto err_process_start; } return 0; err_process_start: rpmemd_fip_close(rpmemd->fip); err_accept: err_send = 0; err_create_resp: rpmemd_fip_fini(rpmemd->fip); err_fip_init: err_pool_check: rpmemd_db_pool_close(rpmemd->db, rpmemd->pool); rpmemd_db_pool_remove(rpmemd->db, req->pool_desc); err_pool_create: err_pool_opened: if (err_send) ret = rpmemd_obc_create_resp(rpmemd->obc, status, &resp); rpmemd->closing = 1; return ret; }
/* * client_init -- test case for client initialization */ int client_init(const struct test_case *tc, int argc, char *argv[]) { if (argc < 3) UT_FATAL("usage: %s <target> <provider> <persist method>", tc->name); char *target = argv[0]; char *prov_name = argv[1]; char *persist_method = argv[2]; set_rpmem_cmd("server_init %s", persist_method); char fip_service[NI_MAXSERV]; struct rpmem_target_info *info; info = rpmem_target_parse(target); UT_ASSERTne(info, NULL); unsigned nlanes; enum rpmem_provider provider = get_provider(info->node, prov_name, &nlanes); client_t *client; struct rpmem_resp_attr resp; client = client_exchange(info, NLANES, provider, &resp); struct rpmem_fip_attr attr = { .provider = provider, .persist_method = resp.persist_method, .laddr = lpool, .size = POOL_SIZE, .nlanes = resp.nlanes, .raddr = (void *)resp.raddr, .rkey = resp.rkey, }; ssize_t sret = snprintf(fip_service, NI_MAXSERV, "%u", resp.port); UT_ASSERT(sret > 0); struct rpmem_fip *fip; fip = rpmem_fip_init(info->node, fip_service, &attr, &nlanes); UT_ASSERTne(fip, NULL); client_close_begin(client); client_close_end(client); rpmem_fip_fini(fip); rpmem_target_free(info); return 3; } /* * server_init -- test case for server initialization */ int server_init(const struct test_case *tc, int argc, char *argv[]) { if (argc < 1) UT_FATAL("usage: %s <persist method>", tc->name); enum rpmem_persist_method persist_method = get_persist_method(argv[0]); unsigned nlanes; enum rpmem_provider provider; char *addr = NULL; server_exchange_begin(&nlanes, &provider, &addr); UT_ASSERTne(addr, NULL); struct rpmemd_fip_attr attr = { .addr = rpool, .size = POOL_SIZE, .nlanes = nlanes, .provider = provider, .persist_method = persist_method, .persist = pmem_persist, .nthreads = NTHREADS, }; struct rpmem_resp_attr resp; struct rpmemd_fip *fip; enum rpmem_err err; fip = rpmemd_fip_init(addr, NULL, &attr, &resp, &err); UT_ASSERTne(fip, NULL); server_exchange_end(resp); server_close_begin(); server_close_end(); rpmemd_fip_fini(fip); FREE(addr); return 1; } /* * client_connect -- test case for establishing connection - client side */ int client_connect(const struct test_case *tc, int argc, char *argv[]) { if (argc < 3) UT_FATAL("usage: %s <target> <provider> <persist method>", tc->name); char *target = argv[0]; char *prov_name = argv[1]; char *persist_method = argv[2]; set_rpmem_cmd("server_connect %s", persist_method); char fip_service[NI_MAXSERV]; struct rpmem_target_info *info; int ret; info = rpmem_target_parse(target); UT_ASSERTne(info, NULL); unsigned nlanes; enum rpmem_provider provider = get_provider(info->node, prov_name, &nlanes); client_t *client; struct rpmem_resp_attr resp; client = client_exchange(info, NLANES, provider, &resp); struct rpmem_fip_attr attr = { .provider = provider, .persist_method = resp.persist_method, .laddr = lpool, .size = POOL_SIZE, .nlanes = resp.nlanes, .raddr = (void *)resp.raddr, .rkey = resp.rkey, }; ssize_t sret = snprintf(fip_service, NI_MAXSERV, "%u", resp.port); UT_ASSERT(sret > 0); struct rpmem_fip *fip; fip = rpmem_fip_init(info->node, fip_service, &attr, &nlanes); UT_ASSERTne(fip, NULL); ret = rpmem_fip_connect(fip); UT_ASSERTeq(ret, 0); client_close_begin(client); ret = rpmem_fip_close(fip); UT_ASSERTeq(ret, 0); client_close_end(client); rpmem_fip_fini(fip); rpmem_target_free(info); return 3; } /* * server_connect -- test case for establishing connection - server side */ int server_connect(const struct test_case *tc, int argc, char *argv[]) { if (argc < 1) UT_FATAL("usage: %s <persist method>", tc->name); enum rpmem_persist_method persist_method = get_persist_method(argv[0]); unsigned nlanes; enum rpmem_provider provider; char *addr = NULL; server_exchange_begin(&nlanes, &provider, &addr); UT_ASSERTne(addr, NULL); struct rpmemd_fip_attr attr = { .addr = rpool, .size = POOL_SIZE, .nlanes = nlanes, .provider = provider, .persist_method = persist_method, .persist = pmem_persist, .nthreads = NTHREADS, }; int ret; struct rpmem_resp_attr resp; struct rpmemd_fip *fip; enum rpmem_err err; fip = rpmemd_fip_init(addr, NULL, &attr, &resp, &err); UT_ASSERTne(fip, NULL); server_exchange_end(resp); ret = rpmemd_fip_accept(fip, -1); UT_ASSERTeq(ret, 0); server_close_begin(); server_close_end(); ret = rpmemd_fip_wait_close(fip, -1); UT_ASSERTeq(ret, 0); ret = rpmemd_fip_close(fip); UT_ASSERTeq(ret, 0); rpmemd_fip_fini(fip); FREE(addr); return 1; } /* * server_process -- test case for processing data on server side */ int server_process(const struct test_case *tc, int argc, char *argv[]) { if (argc < 1) UT_FATAL("usage: %s <persist method>", tc->name); enum rpmem_persist_method persist_method = get_persist_method(argv[0]); set_pool_data(rpool, 1); unsigned nlanes; enum rpmem_provider provider; char *addr = NULL; server_exchange_begin(&nlanes, &provider, &addr); UT_ASSERTne(addr, NULL); struct rpmemd_fip_attr attr = { .addr = rpool, .size = POOL_SIZE, .nlanes = nlanes, .provider = provider, .persist_method = persist_method, .persist = pmem_persist, .nthreads = NTHREADS, }; int ret; struct rpmem_resp_attr resp; struct rpmemd_fip *fip; enum rpmem_err err; fip = rpmemd_fip_init(addr, NULL, &attr, &resp, &err); UT_ASSERTne(fip, NULL); server_exchange_end(resp); ret = rpmemd_fip_accept(fip, -1); UT_ASSERTeq(ret, 0); ret = rpmemd_fip_process_start(fip); server_close_begin(); ret = rpmemd_fip_process_stop(fip); UT_ASSERTeq(ret, 0); server_close_end(); ret = rpmemd_fip_wait_close(fip, -1); UT_ASSERTeq(ret, 0); ret = rpmemd_fip_close(fip); UT_ASSERTeq(ret, 0); rpmemd_fip_fini(fip); FREE(addr); return 1; } /* * client_persist -- test case for single-threaded persist operation */ int client_persist(const struct test_case *tc, int argc, char *argv[]) { if (argc < 3) UT_FATAL("usage: %s <target> <provider> <persist method>", tc->name); char *target = argv[0]; char *prov_name = argv[1]; char *persist_method = argv[2]; set_rpmem_cmd("server_process %s", persist_method); char fip_service[NI_MAXSERV]; struct rpmem_target_info *info; info = rpmem_target_parse(target); UT_ASSERTne(info, NULL); int ret; set_pool_data(lpool, 1); set_pool_data(rpool, 1); unsigned nlanes; enum rpmem_provider provider = get_provider(info->node, prov_name, &nlanes); client_t *client; struct rpmem_resp_attr resp; client = client_exchange(info, NLANES, provider, &resp); struct rpmem_fip_attr attr = { .provider = provider, .persist_method = resp.persist_method, .laddr = lpool, .size = POOL_SIZE, .nlanes = resp.nlanes, .raddr = (void *)resp.raddr, .rkey = resp.rkey, }; ssize_t sret = snprintf(fip_service, NI_MAXSERV, "%u", resp.port); UT_ASSERT(sret > 0); struct rpmem_fip *fip; fip = rpmem_fip_init(info->node, fip_service, &attr, &nlanes); UT_ASSERTne(fip, NULL); ret = rpmem_fip_connect(fip); UT_ASSERTeq(ret, 0); ret = rpmem_fip_process_start(fip); UT_ASSERTeq(ret, 0); struct persist_arg arg = { .fip = fip, .lane = 0, }; client_persist_thread(&arg); ret = rpmem_fip_read(fip, rpool, POOL_SIZE, 0); UT_ASSERTeq(ret, 0); ret = rpmem_fip_process_stop(fip); UT_ASSERTeq(ret, 0); client_close_begin(client); ret = rpmem_fip_close(fip); UT_ASSERTeq(ret, 0); client_close_end(client); rpmem_fip_fini(fip); ret = memcmp(rpool, lpool, POOL_SIZE); UT_ASSERTeq(ret, 0); rpmem_target_free(info); return 3; } /* * client_persist_mt -- test case for multi-threaded persist operation */ int client_persist_mt(const struct test_case *tc, int argc, char *argv[]) { if (argc < 3) UT_FATAL("usage: %s <target> <provider> <persist method>", tc->name); char *target = argv[0]; char *prov_name = argv[1]; char *persist_method = argv[2]; set_rpmem_cmd("server_process %s", persist_method); char fip_service[NI_MAXSERV]; struct rpmem_target_info *info; int ret; info = rpmem_target_parse(target); UT_ASSERTne(info, NULL); set_pool_data(lpool, 1); set_pool_data(rpool, 1); unsigned nlanes; enum rpmem_provider provider = get_provider(info->node, prov_name, &nlanes); client_t *client; struct rpmem_resp_attr resp; client = client_exchange(info, NLANES, provider, &resp); struct rpmem_fip_attr attr = { .provider = provider, .persist_method = resp.persist_method, .laddr = lpool, .size = POOL_SIZE, .nlanes = resp.nlanes, .raddr = (void *)resp.raddr, .rkey = resp.rkey, }; ssize_t sret = snprintf(fip_service, NI_MAXSERV, "%u", resp.port); UT_ASSERT(sret > 0); struct rpmem_fip *fip; fip = rpmem_fip_init(info->node, fip_service, &attr, &nlanes); UT_ASSERTne(fip, NULL); ret = rpmem_fip_connect(fip); UT_ASSERTeq(ret, 0); ret = rpmem_fip_process_start(fip); UT_ASSERTeq(ret, 0); pthread_t *persist_thread = MALLOC(resp.nlanes * sizeof(pthread_t)); struct persist_arg *args = MALLOC(resp.nlanes * sizeof(struct persist_arg)); for (unsigned i = 0; i < nlanes; i++) { args[i].fip = fip; args[i].lane = i; PTHREAD_CREATE(&persist_thread[i], NULL, client_persist_thread, &args[i]); } for (unsigned i = 0; i < nlanes; i++) PTHREAD_JOIN(persist_thread[i], NULL); ret = rpmem_fip_read(fip, rpool, POOL_SIZE, 0); UT_ASSERTeq(ret, 0); ret = rpmem_fip_process_stop(fip); UT_ASSERTeq(ret, 0); client_close_begin(client); ret = rpmem_fip_close(fip); UT_ASSERTeq(ret, 0); client_close_end(client); rpmem_fip_fini(fip); FREE(persist_thread); FREE(args); ret = memcmp(rpool, lpool, POOL_SIZE); UT_ASSERTeq(ret, 0); rpmem_target_free(info); return 3; } /* * client_read -- test case for read operation */ int client_read(const struct test_case *tc, int argc, char *argv[]) { if (argc < 3) UT_FATAL("usage: %s <target> <provider> <persist method>", tc->name); char *target = argv[0]; char *prov_name = argv[1]; char *persist_method = argv[2]; set_rpmem_cmd("server_process %s", persist_method); char fip_service[NI_MAXSERV]; struct rpmem_target_info *info; int ret; info = rpmem_target_parse(target); UT_ASSERTne(info, NULL); set_pool_data(lpool, 0); set_pool_data(rpool, 1); unsigned nlanes; enum rpmem_provider provider = get_provider(info->node, prov_name, &nlanes); client_t *client; struct rpmem_resp_attr resp; client = client_exchange(info, NLANES, provider, &resp); struct rpmem_fip_attr attr = { .provider = provider, .persist_method = resp.persist_method, .laddr = lpool, .size = POOL_SIZE, .nlanes = resp.nlanes, .raddr = (void *)resp.raddr, .rkey = resp.rkey, }; ssize_t sret = snprintf(fip_service, NI_MAXSERV, "%u", resp.port); UT_ASSERT(sret > 0); struct rpmem_fip *fip; fip = rpmem_fip_init(info->node, fip_service, &attr, &nlanes); UT_ASSERTne(fip, NULL); ret = rpmem_fip_connect(fip); UT_ASSERTeq(ret, 0); ret = rpmem_fip_process_start(fip); UT_ASSERTeq(ret, 0); ret = rpmem_fip_read(fip, lpool, POOL_SIZE, 0); UT_ASSERTeq(ret, 0); ret = rpmem_fip_process_stop(fip); UT_ASSERTeq(ret, 0); client_close_begin(client); ret = rpmem_fip_close(fip); UT_ASSERTeq(ret, 0); client_close_end(client); rpmem_fip_fini(fip); ret = memcmp(rpool, lpool, POOL_SIZE); UT_ASSERTeq(ret, 0); rpmem_target_free(info); return 3; } /* * test_cases -- available test cases */ static struct test_case test_cases[] = { TEST_CASE(client_init), TEST_CASE(server_init), TEST_CASE(client_connect), TEST_CASE(server_connect), TEST_CASE(client_persist), TEST_CASE(client_persist_mt), TEST_CASE(server_process), TEST_CASE(client_read), }; #define NTESTS (sizeof(test_cases) / sizeof(test_cases[0])) int main(int argc, char *argv[]) { /* workaround for left-opened files by libfabric */ rpmem_fip_probe_get("localhost", NULL); START(argc, argv, "rpmem_obc"); common_init("rpmem_fip", "RPMEM_LOG_LEVEL", "RPMEM_LOG_FILE", 0, 0); rpmem_util_cmds_init(); rpmemd_log_init("rpmemd", getenv("RPMEMD_LOG_FILE"), 0); rpmemd_log_level = rpmemd_log_level_from_str( getenv("RPMEMD_LOG_LEVEL")); TEST_CASE_PROCESS(argc, argv, test_cases, NTESTS); common_fini(); rpmemd_log_close(); rpmem_util_cmds_fini(); DONE(NULL); }