@@ -209,11 +209,14 @@ M0_INTERNAL int m0_dix_req_wait(struct m0_dix_req *req, uint64_t states,
209209static void dix_req_init (struct m0_dix_req * req ,
210210 struct m0_dix_cli * cli ,
211211 struct m0_sm_group * grp ,
212+ uint32_t min_success ,
212213 bool meta )
213214{
215+ M0_PRE (min_success > 0 );
214216 M0_SET0 (req );
215217 req -> dr_cli = cli ;
216218 req -> dr_is_meta = meta ;
219+ req -> dr_min_success = min_success ;
217220 m0_sm_init (& req -> dr_sm , & dix_req_sm_conf , DIXREQ_INIT , grp );
218221 m0_sm_addb2_counter_init (& req -> dr_sm );
219222}
@@ -222,14 +225,15 @@ M0_INTERNAL void m0_dix_mreq_init(struct m0_dix_req *req,
222225 struct m0_dix_cli * cli ,
223226 struct m0_sm_group * grp )
224227{
225- dix_req_init (req , cli , grp , true);
228+ dix_req_init (req , cli , grp , 1 , true);
226229}
227230
228231M0_INTERNAL void m0_dix_req_init (struct m0_dix_req * req ,
229232 struct m0_dix_cli * cli ,
230- struct m0_sm_group * grp )
233+ struct m0_sm_group * grp ,
234+ uint32_t min_success )
231235{
232- dix_req_init (req , cli , grp , false);
236+ dix_req_init (req , cli , grp , min_success , false);
233237}
234238
235239static enum m0_dix_req_state dix_req_state (const struct m0_dix_req * req )
@@ -1402,6 +1406,20 @@ static void dix_rop(struct m0_dix_req *req)
14021406 M0_LEAVE ();
14031407}
14041408
1409+ /** Checks if the given cas get reply has a newer version of the value */
1410+ static bool dix_item_version_cmp (struct m0_dix_item * ditem ,
1411+ struct m0_cas_get_reply * get_rep ) {
1412+ /*
1413+ * TODO: once cas versions are propagated, check if the get reply
1414+ * has a newer version than seen previously. Will need to add
1415+ * version info to struct m0_dix_item. This function should return
1416+ * true if no previous value is set, or if the previous value has
1417+ * an older version. For now, always return true so the last
1418+ * reply in the array wins.
1419+ */
1420+ return true;
1421+ }
1422+
14051423static void dix_item_rc_update (struct m0_dix_req * req ,
14061424 struct m0_cas_req * creq ,
14071425 uint64_t key_idx ,
@@ -1418,7 +1436,8 @@ static void dix_item_rc_update(struct m0_dix_req *req,
14181436 case DIX_GET :
14191437 m0_cas_get_rep (creq , key_idx , & get_rep );
14201438 rc = get_rep .cge_rc ;
1421- if (rc == 0 ) {
1439+ if (rc == 0 && dix_item_version_cmp (ditem , & get_rep )) {
1440+ m0_buf_free (& ditem -> dxi_val );
14221441 ditem -> dxi_val = get_rep .cge_val ;
14231442 /* Value will be freed at m0_dix_req_fini(). */
14241443 m0_cas_rep_mlock (creq , key_idx );
@@ -1625,24 +1644,28 @@ static void dix_rop_completed(struct m0_sm_group *grp, struct m0_sm_ast *ast)
16251644 struct m0_dix_rop_ctx * rop_del_phase2 = NULL ;
16261645 bool del_phase2 = false;
16271646 struct m0_dix_cas_rop * cas_rop ;
1647+ uint32_t successful_ops = 0 ;
16281648
16291649 (void )grp ;
16301650 if (req -> dr_type == DIX_NEXT )
16311651 m0_dix_next_result_prepare (req );
16321652 else {
1653+ successful_ops = m0_tl_reduce (cas_rop , scan , & rop -> dg_cas_reqs , 0 ,
1654+ + !!(scan -> crp_creq .ccr_sm .sm_rc == 0 ));
1655+
16331656 /*
1634- * Consider DIX request to be successful if there is at least
1635- * one successful CAS request.
1657+ * If enough operations succeeded to satisfy min_success,
1658+ * ignore any operations that failed. If we don't have enough,
1659+ * count all operations when deciding overall success (ensures the
1660+ * overall operation is considered a failure).
16361661 */
1637- if (m0_tl_forall (cas_rop , cas_rop ,
1638- & rop -> dg_cas_reqs ,
1639- cas_rop -> crp_creq .ccr_sm .sm_rc != 0 ))
1640- dix_cas_rop_rc_update (cas_rop_tlist_tail (
1641- & rop -> dg_cas_reqs ), 0 );
16421662
1663+ M0_ASSERT (req -> dr_min_success > 0 );
16431664 m0_tl_for (cas_rop , & rop -> dg_cas_reqs , cas_rop ) {
1644- if (cas_rop -> crp_creq .ccr_sm .sm_rc == 0 )
1665+ if (successful_ops < req -> dr_min_success ||
1666+ cas_rop -> crp_creq .ccr_sm .sm_rc == 0 ) {
16451667 dix_cas_rop_rc_update (cas_rop , 0 );
1668+ }
16461669 m0_cas_req_fini (& cas_rop -> crp_creq );
16471670 } m0_tl_endfor ;
16481671 }
@@ -1956,29 +1979,6 @@ static int dix_spare_target_with_data(struct m0_dix_rec_op *rec_op,
19561979 true);
19571980}
19581981
1959- static void dix_online_unit_choose (struct m0_dix_req * req ,
1960- struct m0_dix_rec_op * rec_op )
1961- {
1962- struct m0_dix_pg_unit * pgu ;
1963- uint64_t start_unit ;
1964- uint64_t i ;
1965- uint64_t j ;
1966-
1967- M0_ENTRY ();
1968- M0_PRE (req -> dr_type == DIX_GET );
1969- start_unit = req -> dr_items [rec_op -> dgp_item ].dxi_pg_unit ;
1970- M0_ASSERT (start_unit < dix_rec_op_spare_offset (rec_op ));
1971- for (i = 0 ; i < start_unit ; i ++ )
1972- rec_op -> dgp_units [i ].dpu_unavail = true;
1973- for (i = start_unit ; i < rec_op -> dgp_units_nr ; i ++ ) {
1974- pgu = & rec_op -> dgp_units [i ];
1975- if (!pgu -> dpu_is_spare && !pgu -> dpu_unavail )
1976- break ;
1977- }
1978- for (j = i + 1 ; j < rec_op -> dgp_units_nr ; j ++ )
1979- rec_op -> dgp_units [j ].dpu_unavail = true;
1980- }
1981-
19821982static void dix_pg_unit_pd_assign (struct m0_dix_pg_unit * pgu ,
19831983 struct m0_pooldev * pd )
19841984{
@@ -2135,15 +2135,6 @@ static void dix_rop_units_set(struct m0_dix_req *req)
21352135 }
21362136
21372137 m0_rwlock_read_unlock (& pm -> pm_lock );
2138-
2139- /*
2140- * Only one CAS GET request should be sent for every record.
2141- * Choose the best destination for every record.
2142- */
2143- if (req -> dr_type == DIX_GET ) {
2144- for (i = 0 ; i < rop -> dg_rec_ops_nr ; i ++ )
2145- dix_online_unit_choose (req , & rop -> dg_rec_ops [i ]);
2146- }
21472138}
21482139
21492140static bool dix_pg_unit_skip (struct m0_dix_req * req ,
0 commit comments