diff --git a/src/tests/suite/daos_base_tx.c b/src/tests/suite/daos_base_tx.c index 5752ade4fb87..765c0677ebfb 100644 --- a/src/tests/suite/daos_base_tx.c +++ b/src/tests/suite/daos_base_tx.c @@ -884,6 +884,108 @@ dtx_21(void **state) ioreq_fini(&req); } +static void +dtx_22(void **state) +{ + test_arg_t *arg = *state; + daos_obj_id_t oid; + daos_handle_t oh; + daos_iod_t iod = { 0 }; + d_sg_list_t sgl = { 0 }; + daos_recx_t recx[2]; + d_iov_t val_iov[2]; + d_iov_t dkey; + d_iov_t akey; + uint64_t dkey_val = 100; + uint64_t akey_val = 200; + uint32_t update_var0 = 0x1234; + uint32_t update_var1 = 0x6789; + uint32_t update_var2 = 0xbcdf; + uint32_t flags = DAOS_GET_DKEY | DAOS_GET_AKEY | DAOS_GET_RECX | DAOS_GET_MAX; + int rc; + + FAULT_INJECTION_REQUIRED(); + + print_message("iteration does not return aborted DTX\n"); + + if (!test_runable(arg, dts_dtx_replica_cnt)) + return; + + oid = daos_test_oid_gen(arg->coh, dts_dtx_class, DAOS_OT_MULTI_UINT64, 0, arg->myrank); + rc = daos_obj_open(arg->coh, oid, DAOS_OO_RW, &oh, NULL); + assert_rc_equal(rc, 0); + + d_iov_set(&dkey, &dkey_val, sizeof(uint64_t)); + d_iov_set(&akey, &akey_val, sizeof(uint64_t)); + iod.iod_name = akey; + iod.iod_type = DAOS_IOD_ARRAY; + iod.iod_size = sizeof(update_var0); + + d_iov_set(&val_iov[0], &update_var0, sizeof(update_var0)); + d_iov_set(&val_iov[1], &update_var1, sizeof(update_var1)); + sgl.sg_nr = 2; + sgl.sg_iovs = val_iov; + recx[0].rx_idx = 30; + recx[0].rx_nr = 1; + recx[1].rx_idx = 50; + recx[1].rx_nr = 1; + iod.iod_nr = 2; + iod.iod_recxs = recx; + + rc = daos_obj_update(oh, DAOS_TX_NONE, 0, &dkey, 1, &iod, &sgl, NULL); + assert_rc_equal(rc, 0); + + dkey_val = 0; + akey_val = 0; + rc = daos_obj_query_key(oh, DAOS_TX_NONE, flags, &dkey, &akey, &recx[0], NULL); + assert_rc_equal(rc, 0); + + assert_int_equal(*(uint64_t *)dkey.iov_buf, 100); + assert_int_equal(*(uint64_t *)akey.iov_buf, 200); + assert_int_equal(recx[0].rx_idx, 50); + assert_int_equal(recx[0].rx_nr, 1); + + par_barrier(PAR_COMM_WORLD); + if (arg->myrank == 0) + /* Simulate the case of TX IO error on the shard_1. */ + daos_debug_set_params(arg->group, -1, DMG_KEY_FAIL_LOC, + DAOS_DTX_FAIL_IO | DAOS_FAIL_ALWAYS, 0, NULL); + par_barrier(PAR_COMM_WORLD); + + d_iov_set(&val_iov[0], &update_var2, sizeof(update_var2)); + sgl.sg_nr = 1; + sgl.sg_iovs = &val_iov[0]; + recx[0].rx_idx = 70; + recx[0].rx_nr = 1; + iod.iod_nr = 1; + iod.iod_recxs = &recx[0]; + + /* Update the same dkey & akey with higher index. */ + dkey_val = 100; + akey_val = 200; + rc = daos_obj_update(oh, DAOS_TX_NONE, 0, &dkey, 1, &iod, &sgl, NULL); + assert_rc_equal(rc, -DER_IO); + + dkey_val = 0; + akey_val = 0; + rc = daos_obj_query_key(oh, DAOS_TX_NONE, flags, &dkey, &akey, &recx[0], NULL); + assert_rc_equal(rc, 0); + + /* Since the 2nd update failed, query should return old value. */ + assert_int_equal(*(uint64_t *)dkey.iov_buf, 100); + assert_int_equal(*(uint64_t *)akey.iov_buf, 200); + assert_int_equal(recx[0].rx_idx, 50); + assert_int_equal(recx[0].rx_nr, 1); + + rc = daos_obj_close(oh, NULL); + assert_rc_equal(rc, 0); + + par_barrier(PAR_COMM_WORLD); + if (arg->myrank == 0) + daos_debug_set_params(arg->group, -1, DMG_KEY_FAIL_LOC, 0, 0, NULL); + par_barrier(PAR_COMM_WORLD); +} + static int dtx_base_rf0_setup(void **state) { @@ -947,6 +1049,8 @@ static const struct CMUnitTest dtx_tests[] = { dtx_20, dtx_base_rf1_setup, rebuild_sub_teardown}, {"DTX21: do not abort partially committed DTX", dtx_21, dtx_base_rf0_setup, rebuild_sub_teardown}, + {"DTX22: iteration does not return aborted DTX", + dtx_22, NULL, test_case_teardown}, }; static int diff --git a/src/vos/evt_iter.c b/src/vos/evt_iter.c index ef9e3efa2965..afcfe0ac93cc 100644 --- a/src/vos/evt_iter.c +++ b/src/vos/evt_iter.c @@ -306,22 +306,6 @@ evt_iter_move(struct evt_context *tcx, struct evt_iterator *iter) return rc; } -static int -evt_iter_skip(struct evt_context *tcx, struct evt_iterator *iter) -{ - struct evt_entry_array *enta; - struct evt_entry *entry; - - if (iter->it_options & (EVT_ITER_SKIP_HOLES | EVT_ITER_SKIP_DATA)) { - enta = iter->it_entries; - entry = evt_ent_array_get(enta, iter->it_index); - - if (should_skip(entry, iter)) - return evt_iter_move(tcx, iter); - } - return 0; -} - static int evt_iter_probe_sorted(struct evt_context *tcx, struct evt_iterator *iter, int opc, const struct evt_rect *rect, @@ -369,31 +353,35 @@ evt_iter_probe_sorted(struct evt_context *tcx, struct evt_iterator *iter, if (opc == EVT_ITER_FIRST) { index = iter->it_forward ? 0 : enta->ea_ent_nr - 1; - iter->it_index = index; /* Mark the last entry */ entry = evt_ent_array_get(enta, enta->ea_ent_nr - 1 - index); entry->en_visibility |= EVT_LAST; - goto out; - } - - if (opc != EVT_ITER_FIND) { + } else if (opc != EVT_ITER_FIND) { D_ERROR("Unknown op code for evt iterator: %d\n", opc); return -DER_NOSYS; + } else { + /** If entry doesn't exist, it will return next entry */ + index = evt_iter_probe_find(iter, rect); + if (index == -1) + return -DER_NONEXIST; } - /** If entry doesn't exist, it will return next entry */ - index = evt_iter_probe_find(iter, rect); - if (index == -1) - return -DER_NONEXIST; - iter->it_index = index; - entry = evt_ent_array_get(iter->it_entries, index); + entry = evt_ent_array_get(enta, index); + + if (rect != NULL) + D_DEBUG(DB_TRACE, "probe ent "DF_EXT" Update ent "DF_EXT"\n", + DP_EXT(&rect->rc_ex), DP_EXT(&entry->en_sel_ext)); + + if (entry->en_avail_rc < 0) + return entry->en_avail_rc; - D_DEBUG(DB_TRACE, "probe ent "DF_EXT" Update ent "DF_EXT"\n", - DP_EXT(&rect->rc_ex), DP_EXT(&entry->en_sel_ext)); -out: iter->it_state = EVT_ITER_READY; - return evt_iter_skip(tcx, iter); + + if (entry->en_avail_rc == ALB_UNAVAILABLE || should_skip(entry, iter)) + return evt_iter_move(tcx, iter); + + return 0; } static void @@ -470,8 +458,27 @@ evt_iter_probe(daos_handle_t ih, enum evt_iter_opc opc, iter->it_state = EVT_ITER_FINI; rc = -DER_NONEXIST; } else { + struct evt_trace *trace; + struct evt_node *nd; + struct evt_node_entry *ne; + struct evt_desc *desc; + + trace = &tcx->tc_trace[tcx->tc_depth - 1]; + nd = evt_off2node(tcx, trace->tr_node); + ne = evt_node_entry_at(tcx, nd, trace->tr_at); + desc = evt_off2desc(tcx, ne->ne_child); + + rc = evt_desc_log_status(tcx, ne->ne_rect.rd_epc, desc, evt_iter_intent(iter)); + if (rc < 0) + goto out; + iter->it_state = EVT_ITER_READY; iter->it_skip_move = 0; + + if (rc == ALB_UNAVAILABLE) + return evt_iter_move(tcx, iter); + + rc = 0; } out: return rc;