Commit e4c4029e authored by Willem Thiart's avatar Willem Thiart
Browse files

Prevent dupe entries

Thanks to @ar104 for help with this fix!
parent 591973e3
......@@ -283,18 +283,27 @@ int raft_recv_appendentries(
/* 3. If an existing entry conflicts with a new one (same index
but different terms), delete the existing entry and all that
follow it (§5.3) */
int has_mismatch = 0, i;
int i;
for (i = 0; i < ae->n_entries; i++)
{
msg_entry_t* cmd = &ae->entries[i];
int index = ae->prev_log_idx + 1 + i;
raft_entry_t* e2 = raft_get_entry_from_idx(me_, index);
if (!e2)
break; /* reached end of log */
if (e2 && e2->term != cmd->term)
has_mismatch = 1;
if (has_mismatch)
log_delete(me->log, index);
msg_entry_t* ety = &ae->entries[i];
int ety_index = ae->prev_log_idx + 1 + i;
raft_entry_t* existing_ety = raft_get_entry_from_idx(me_, ety_index);
if (existing_ety && existing_ety->term != ety->term)
{
log_delete(me->log, ety_index);
break;
}
else if (!existing_ety)
break;
}
/* Pick up remainder in case of mismatch or missing existing entry */
for (; i < ae->n_entries; i++)
{
int e = raft_append_entry(me_, &ae->entries[i]);
if (-1 == e)
goto fail;
}
/* 4. If leaderCommit > commitIndex, set commitIndex =
......@@ -309,31 +318,19 @@ int raft_recv_appendentries(
raft_become_follower(me_);
raft_set_current_term(me_, ae->term);
/* update current leader because we accepted appendentries from it */
me->current_leader = node;
/* append all entries to log */
for (i = 0; i < ae->n_entries; i++)
{
msg_entry_t* cmd = &ae->entries[i];
raft_entry_t ety;
ety.term = cmd->term;
ety.id = cmd->id;
memcpy(&ety.data, &cmd->data, sizeof(raft_entry_data_t));
int e = raft_append_entry(me_, &ety);
if (-1 == e)
{
__log(me_, "AE failure; couldn't append entry");
r->success = 0;
return -1;
}
}
r->success = 1;
r->current_idx = raft_get_current_idx(me_);
r->first_idx = ae->prev_log_idx + 1;
return 0;
fail:
__log(me_, "AE failure; couldn't append entry");
r->success = 0;
return -1;
}
static int __should_grant_vote(raft_server_private_t* me, msg_requestvote_t* vr)
......
......@@ -801,6 +801,44 @@ void TestRaft_follower_recv_appendentries_add_new_entries_not_already_in_log(
CuAssertTrue(tc, 2 == raft_get_log_count(r));
}
void TestRaft_follower_recv_appendentries_does_not_add_dupe_entries_already_in_log(
CuTest * tc)
{
void *r = raft_new();
raft_add_node(r, (void*)1, 1);
raft_add_node(r, (void*)2, 0);
raft_set_current_term(r, 1);
msg_appendentries_t ae;
msg_appendentries_response_t aer;
memset(&ae, 0, sizeof(msg_appendentries_t));
ae.term = 1;
ae.prev_log_idx = 0;
ae.prev_log_term = 1;
/* include 1 entry */
msg_entry_t e[2];
memset(&e, 0, sizeof(msg_entry_t) * 2);
e[0].id = 1;
ae.entries = e;
ae.n_entries = 1;
memset(&aer, 0, sizeof(aer));
raft_recv_appendentries(r, 1, &ae, &aer);
memset(&aer, 0, sizeof(aer));
raft_recv_appendentries(r, 1, &ae, &aer);
/* still successful even when no raft_append_entry() happened! */
CuAssertTrue(tc, 1 == aer.success);
CuAssertIntEquals(tc, 1, raft_get_log_count(r));
/* lets get the server to append 2 now! */
e[1].id = 2;
ae.n_entries = 2;
memset(&aer, 0, sizeof(aer));
raft_recv_appendentries(r, 1, &ae, &aer);
CuAssertTrue(tc, 1 == aer.success);
CuAssertIntEquals(tc, 2, raft_get_log_count(r));
}
/* If leaderCommit > commitidx, set commitidx =
* min(leaderCommit, last log idx) */
void TestRaft_follower_recv_appendentries_set_commitidx_to_prevLogIdx(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment