Riak KV may lost recent writes in the presence of heavy handoff activity.
{:type :invoke, :f :write, :value 31, :process 27, :time 205105199455, :index 16232}
{:type :ok, :f :write, :value 31, :process 27, :time 205110025753, ..., :index 16234}
{:type :invoke, :f :write, :value 5, :process 26, :time 205222111586, :index 16245}
{:type :ok, :f :write, :value 5, :process 26, :time 205224722230, ..., :index 16246}
{:type :invoke, :f :read, :value nil, :process 25, :time 205256891475, :index 16250}
{:type :ok, :f :read, :value 5, :process 25, :time 205260160969, ..., :index 16252}
{:type :invoke, :f :read, :value nil, :process 24, :time 206523664708, :index 16343}
{:type :ok, :f :read, :value 5, :process 24, :time 206526735511, ..., :index 16344}
{:type :invoke, :f :write, :value 30, :process 26, :time 206664972077, :index 16356}
{:type :ok, :f :write, :value 30, :process 26, :time 206673674701, ..., :index 16358}
{:type :invoke, :f :write, :value 20, :process 27, :time 206712230895, :index 16361}
{:type :ok, :f :write, :value 20, :process 27, :time 206715122992, ..., :index 16362}
{:type :invoke, :f :read, :value nil, :process 25, :time 207091635937, :index 16394}
{:type :ok, :f :read, :value 20, :process 25, :time 207095405146, ..., :index 16396}
{:type :invoke, :f :read, :value nil, :process 25, :time 207244686086, :index 16407}
{:type :ok, :f :read, :value 31, :process 25, :time 207247072654, ..., :index 16408}
Though it won't hurt to mention that I have successfully reproduced this bug under riak 2.2.3 as well.
Essentially this is caused by the fact that put fsm does not account for the possibility of multiple forwards to another coordinator. I'll try to illustrate:
2020-03-25T19:19:00.386369Z [error] Unrecognized message {15919439,{ok,{r_object,<<"registers">>,<<"jepsen638479067-8">>,[{r_content,{dict,3,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,50,113,86,90,100,101,73,71,104,90,49,76,106,117,113,77,121,106,86,52,98,70]],[[<<"index">>]],[],[[<<"X-Riak-Last-Modified">>|{1585,163940,383362}]],[],[]}}},<<"37">>}],[{<<"...">>,{13,63752383125}},{<<188,169,128,137,39,255,43,155>>,{5,63752383126}},{<<188,169,128,137,39,255,44,215,0,0,0,1>>,{28,63752383133}},{<<91,17,173,142,39,242,0,107>>,{1,63752383139}},{<<187,196,68,144,40,0,3,163>>,{8,63752383140}},{<<188,169,128,137,39,255,44,166>>,{7,63752383140}}],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}}}
2020-03-25T19:19:02.354180Z [error] Unrecognized message {53908694,{ok,{r_object,<<"registers">>,<<"jepsen638479067-8">>,[{r_content,{dict,3,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[[<<"X-Riak-VTag">>,49,85,73,73,113,78,109,51,122,50,116,66,102,119,90,103,55,81,100,57,76,49]],[[<<"index">>]],[],[[<<"X-Riak-Last-Modified">>|{1585,163942,349490}]],[],[]}}},<<"17">>}],[{<<"...">>,{13,63752383125}},{<<188,169,128,137,39,255,43,155>>,{5,63752383126}},{<<188,169,128,137,39,255,44,215,0,0,0,1>>,{28,63752383133}},{<<91,17,173,142,39,242,0,107>>,{1,63752383139}},{<<188,169,128,137,39,255,44,166>>,{7,63752383140}},{<<187,196,68,144,40,0,3,163>>,{11,63752383142}}],{dict,1,16,16,8,80,48,{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},{{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[[clean|true]],[]}}},undefined}}}
Riak KV may lost recent writes in the presence of heavy handoff activity.
I've made a test with the help of Jepsen framework specifically to investigate this kind of buggy behaviour because it hit us several times already in our production environment. This test observes an occurence of this bug almost every run to be honest. An ordinary test run follows roughly these steps:
I have attached a Jepsen report archive of one such test run. Most notable observations are in
results.edn, here's an excerpt, redacted for brewity:Basically this all means that the client 25 while operating on key
jepsen638479067-6read value20and subsequently read value31quite unexpectedly, all in the absence of concurrent writes under this key.Skimming through
history.edn, here's relevant history fragment, again redacted a bit for brewity:It can be seen clearly that an act of writing
31at index 16232 effected read at index 16407, though in the meantime 3 subsequent writes have succeeded (16245, 16356, 16361).Affected version(s)
Though it won't hurt to mention that I have successfully reproduced this bug under riak 2.2.3 as well.
Steps to reproduce
Clone aforementioned repo.
Start a test run with:
Wait for it to finish cleanly.
Note that tearing down node with
riak stopon 2.9.1 may become stuck for some reason at the end of a run, simple ^C would be fine then.Look at the analysis report in
store/latest/results.edn.Suspected cause
Essentially this is caused by the fact that put fsm does not account for the possibility of multiple forwards to another coordinator. I'll try to illustrate:
retry_put_coordinator_failureistruewhich is the default per cuttlefish schema.This is why I believe there are occasional unrecognized messages in logs, which are extraneous responses to original requests retried unwarrantedly:
One more evidence which strengthen my suspicion is that turning off
retry_put_coordinator_failuremakes this buggy behaviuor go away with quite high probability, if not completely, given the number of test runs I've performed so far.Additional observations
Moreover it's not clear for me why acknowledgement is being sent in the execute state of an fsm, but not in the validate state since there's a possibility that execute will be skipped altogether, in the event of parameter violation for example.