@@ -1181,18 +1181,14 @@ handle_follower(#append_entries_rpc{term = Term,
1181
1181
State0 = update_term (Term , State00 #{leader_id => LeaderId }),
1182
1182
case has_log_entry_or_snapshot (PLIdx , PLTerm , Log00 ) of
1183
1183
{entry_ok , Log0 } ->
1184
- {LocalLastIdx , _ } = ra_log :last_index_term (Log0 ),
1185
1184
% filter entries already seen
1186
1185
{Log1 , Entries , LastValidIdx } =
1187
1186
drop_existing (Log0 , Entries0 , PLIdx ),
1188
- ? DEBUG_IF (length (Entries ) < length (Entries0 ),
1189
- " ~ts DUPES last index ~b incoming last ~b ~b ~b " ,
1190
- [log_id (State0 ), LocalLastIdx , PLIdx ,
1191
- length (Entries0 ), length (Entries )]),
1192
1187
case Entries of
1193
1188
[] ->
1194
1189
% % all entries have already been written
1195
1190
ok = incr_counter (Cfg , ? C_RA_SRV_AER_RECEIVED_FOLLOWER_EMPTY , 1 ),
1191
+ {LocalLastIdx , _ } = ra_log :last_index_term (Log1 ),
1196
1192
{LogIsValidated , Log2 } =
1197
1193
case Entries0 of
1198
1194
[] when LocalLastIdx > PLIdx ->
@@ -1229,18 +1225,22 @@ handle_follower(#append_entries_rpc{term = Term,
1229
1225
{NextState , State ,
1230
1226
[cast_reply (Id , LeaderId , Reply ) | Effects ]};
1231
1227
false ->
1232
- % % We need to ensure we make progress in case
1233
- % % the last applied index is lower than the last
1234
- % % valid index
1228
+ % % We need to ensure we make progress in case the
1229
+ % % leader is having to resend already received
1230
+ % % entries in order to validate, e.g. after a
1231
+ % % term_mismatch, hence we reply with success but
1232
+ % % only up to the last index we already had
1235
1233
LastValidatedIdx = max (LastApplied , LastValidIdx ),
1236
1234
? DEBUG (" ~ts : append_entries_rpc with last index ~b "
1237
1235
" including ~b entries did not validate local log. "
1238
- " Requesting resend from index ~b , last index ~b " ,
1239
- [LogId , PLIdx , length (Entries0 ),
1240
- LastValidatedIdx + 1 , LocalLastIdx ]),
1241
- {Reply , State } =
1242
- mismatch_append_entries_reply (Term , LastValidatedIdx ,
1243
- State0 #{log => Log2 }),
1236
+ " Local last index ~b " ,
1237
+ [LogId , PLIdx , length (Entries0 ), LocalLastIdx ]),
1238
+ {LVTerm , State } = fetch_term (LastValidatedIdx , State0 ),
1239
+ Reply = # append_entries_reply {term = CurTerm ,
1240
+ success = true ,
1241
+ next_index = LastValidatedIdx + 1 ,
1242
+ last_index = LastValidatedIdx ,
1243
+ last_term = LVTerm },
1244
1244
{follower , State ,
1245
1245
[cast_reply (Id , LeaderId , Reply )]}
1246
1246
end ;
@@ -1250,14 +1250,12 @@ handle_follower(#append_entries_rpc{term = Term,
1250
1250
LeaderCommit ),
1251
1251
% % assert we're not writing below the last applied index
1252
1252
? assertNot (FstIdx < LastApplied ),
1253
- State2 = lists :foldl (fun pre_append_log_follower /2 ,
1254
- State1 , Entries ),
1253
+ State = lists :foldl (fun pre_append_log_follower /2 ,
1254
+ State1 , Entries ),
1255
1255
case ra_log :write (Entries , Log1 ) of
1256
1256
{ok , Log2 } ->
1257
- {NextState , State , Effects } =
1258
- evaluate_commit_index_follower (State2 #{log => Log2 },
1259
- Effects0 ),
1260
- {NextState , State , Effects };
1257
+ evaluate_commit_index_follower (State #{log => Log2 },
1258
+ Effects0 );
1261
1259
{error , wal_down } ->
1262
1260
% % at this point we know the wal process exited
1263
1261
% % but we dont know exactly which in flight messages
@@ -1269,9 +1267,9 @@ handle_follower(#append_entries_rpc{term = Term,
1269
1267
% % it wrote for each UID into an ETS table and query
1270
1268
% % this.
1271
1269
{await_condition ,
1272
- State2 #{log => Log1 ,
1273
- condition =>
1274
- #{predicate_fun => fun wal_down_condition /2 }},
1270
+ State #{log => Log1 ,
1271
+ condition =>
1272
+ #{predicate_fun => fun wal_down_condition /2 }},
1275
1273
Effects0 };
1276
1274
{error , _ } = Err ->
1277
1275
exit (Err )
@@ -1346,23 +1344,23 @@ handle_follower(#heartbeat_rpc{leader_id = LeaderId,
1346
1344
cfg := # cfg {id = Id }} = State ) ->
1347
1345
Reply = heartbeat_reply (CurTerm , QueryIndex ),
1348
1346
{follower , State , [cast_reply (Id , LeaderId , Reply )]};
1349
- handle_follower ({ra_log_event , {written , TERM , _ } = Evt },
1350
- State0 = #{log := Log0 ,
1351
- cfg := # cfg {id = Id },
1352
- leader_id := LeaderId ,
1353
- current_term := TERM = Term })
1354
- when LeaderId =/= undefined ->
1347
+ handle_follower ({ra_log_event , Evt }, #{log := Log0 ,
1348
+ cfg := # cfg {id = Id },
1349
+ leader_id := LeaderId ,
1350
+ current_term := Term } = State0 ) ->
1351
+ % forward events to ra_log
1352
+ % if the last written changes then send an append entries reply
1353
+ LW = ra_log :last_written (Log0 ),
1355
1354
{Log , Effects } = ra_log :handle_event (Evt , Log0 ),
1356
1355
State = State0 #{log => Log },
1357
- % % only reply with success if the written event relates to the current
1358
- % % term. this avoids accidentally confirming overwritten indexes too
1359
- % % early
1360
- Reply = append_entries_reply (Term , true , State ),
1361
- {follower , State , [cast_reply (Id , LeaderId , Reply ) | Effects ]};
1362
- handle_follower ({ra_log_event , Evt }, State = #{log := Log0 }) ->
1363
- % simply forward all other events to ra_log
1364
- {Log , Effects } = ra_log :handle_event (Evt , Log0 ),
1365
- {follower , State #{log => Log }, Effects };
1356
+ case LW =/= ra_log :last_written (Log ) of
1357
+ true when LeaderId =/= undefined ->
1358
+ % % last written has changed so we need to send an AER reply
1359
+ Reply = append_entries_reply (Term , true , State ),
1360
+ {follower , State , [cast_reply (Id , LeaderId , Reply ) | Effects ]};
1361
+ _ ->
1362
+ {follower , State , Effects }
1363
+ end ;
1366
1364
handle_follower (# pre_vote_rpc {},
1367
1365
#{cfg := # cfg {log_id = LogId },
1368
1366
membership := Membership } = State ) when Membership =/= voter ->
0 commit comments