Beispiel #1
0
def test_peer_rejects_append_entries_on_term_mismatch_setup():
    event_queues = common.create_event_queues()
    peers = None
    startup_state = "follower"
    initial_term = 3
    election_timeout = range(1000, 3000)
    commit_index = 0

    log = MemoryLog()
    log.append(LogEntry(log_index=1, term=2, command=None, data=None))
    log.append(LogEntry(log_index=2, term=2, command=None, data=None))
    log.append(LogEntry(log_index=3, term=2, command=None, data=None))
    log.append(LogEntry(log_index=4, term=2, command=None, data=None))

    key_store = None
    initialize_next_index = False

    event_queues.state_machine.put_nowait(
        AppendEntries(
            event_id=str(uuid.uuid4()),
            source_server="leader_server",
            destination_server="peer_server",
            term=4,
            leader_id="leader_server",
            prev_log_index=4,
            prev_log_term=4,
            entries=[LogEntry(log_index=5, term=4, command=None, data=None)],
            leader_commit=1,
        ))

    proc = mp.Process(
        target=common.start_state_machine,
        args=(
            event_queues,
            startup_state,
            peers,
            initial_term,
            election_timeout,
            commit_index,
            log,
            key_store,
            initialize_next_index,
            "peer_server",
        ),
    )
    proc.start()

    time.sleep(0.1)

    yield event_queues

    proc.kill()
Beispiel #2
0
def test_peer_grants_vote_setup():
    event_queues = common.create_event_queues()
    peers = None
    startup_state = "follower"
    initial_term = 3
    election_timeout = range(1000, 3000)
    commit_index = 0

    log = MemoryLog()
    log.append(LogEntry(log_index=1, term=3, command=None, data=None))
    log.append(LogEntry(log_index=2, term=3, command=None, data=None))

    key_store = None
    initialize_next_index = False

    event_queues.state_machine.put_nowait(
        RequestVote(
            event_id=str(uuid.uuid4()),
            source_server="candidate_server",
            destination_server="peer_server",
            term=4,
            candidate_id="candidate_server",
            last_log_index=6,
            last_log_term=3,
        ))

    event_queues.state_machine.put_nowait(
        LocalStateSnapshotRequestForTesting())

    proc = mp.Process(
        target=common.start_state_machine,
        args=(
            event_queues,
            startup_state,
            peers,
            initial_term,
            election_timeout,
            commit_index,
            log,
            key_store,
            initialize_next_index,
            "peer_server",
        ),
    )
    proc.start()

    time.sleep(0.1)

    yield event_queues

    proc.kill()
Beispiel #3
0
def test_peer_deletes_conflicting_log_entries_and_appends_new(
        conflicting_entries):
    event_queues = conflicting_entries
    event = event_queues.dispatcher.get_nowait()
    state = event_queues.testing.get_nowait()

    assert event.success == True
    assert event.term == 4
    assert event.last_log_index == 5

    assert state.state["log"] == [
        LogEntry(log_index=1,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": "foo"
                 }),
        LogEntry(log_index=2,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": "foo"
                 }),
        LogEntry(log_index=3,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": "foo"
                 }),
        LogEntry(log_index=4,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": "foo"
                 }),
        LogEntry(log_index=5,
                 term=4,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }),
    ]
Beispiel #4
0
 def _handle_client_request(self, event):
     log_entry = LogEntry(log_index=self._log.next_index(),
                          term=self._term,
                          command=event.command,
                          data=event.data)
     self._log.append(log_entry)
     self._event_queues.log_writer.put_nowait(log_entry)
     self._pending_client_requests.append(
         PendingClientRequest(
             request_id=event.event_id,
             request_commit_index=log_entry.log_index,
             request_receive_time=time.monotonic(),
         ))
Beispiel #5
0
def test_peer_commits_entries_and_advances_commit_index_setup():
    event_queues = common.create_event_queues()
    peers = None
    startup_state = "follower"
    initial_term = 2
    election_timeout = range(1000, 3000)
    commit_index = 0

    log = MemoryLog()

    log.append(
        LogEntry(log_index=1,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }))
    log.append(
        LogEntry(log_index=2,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }))
    log.append(
        LogEntry(log_index=3,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }))
    log.append(
        LogEntry(log_index=4,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }))
    log.append(
        LogEntry(log_index=5,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }))
    log.append(
        LogEntry(log_index=6,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }))
    log.append(
        LogEntry(log_index=7,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 1
                 }))

    key_store = None
    initialize_next_index = False

    event_queues.state_machine.put_nowait(
        AppendEntries(
            event_id=str(uuid.uuid4()),
            source_server="leader_server",
            destination_server="peer_server",
            term=3,
            leader_id="leader_server",
            prev_log_index=7,
            prev_log_term=2,
            entries=[
                LogEntry(log_index=8,
                         term=2,
                         command="_set",
                         data={
                             "key": "b",
                             "value": 2
                         })
            ],
            leader_commit=8,
        ))

    event_queues.state_machine.put_nowait(
        LocalStateSnapshotRequestForTesting())

    proc = mp.Process(
        target=common.start_state_machine,
        args=(
            event_queues,
            startup_state,
            peers,
            initial_term,
            election_timeout,
            commit_index,
            log,
            key_store,
            initialize_next_index,
            "peer_server",
        ),
    )
    proc.start()

    time.sleep(0.1)

    yield event_queues

    proc.kill()
Beispiel #6
0
def test_peer_appends_new_entries(new_entries):
    event_queues = new_entries
    event = event_queues.dispatcher.get_nowait()
    state = event_queues.testing.get_nowait()

    assert event.success == True
    assert event.term == 3
    assert event.last_log_index == 8

    assert state.state["log"] == [
        LogEntry(log_index=1,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
        LogEntry(log_index=2,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
        LogEntry(log_index=3,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
        LogEntry(log_index=4,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
        LogEntry(log_index=5,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
        LogEntry(log_index=6,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
        LogEntry(log_index=7,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
        LogEntry(log_index=8,
                 term=2,
                 command="_set",
                 data={
                     "key": "a",
                     "value": 11
                 }),
    ]
Beispiel #7
0
from raft.structures.log_entry import LogEntry

_DEFAULT_LOG_INDEX = 0
_DEFAULT_LOG_TERM = 0
_DEFAULT_LOG_ENTRY = LogEntry(
    log_index=_DEFAULT_LOG_INDEX,
    term=_DEFAULT_LOG_TERM,
    command=None,
    data=None,
)


class MemoryLog:
    def __init__(self):
        self._log = []

    def append(self, entry):
        self._log.append(entry)

    def at(self, index):
        try:
            return self._log[index] if index < 0 else self._log[index - 1]
        except IndexError:
            return None

    def last_index(self):
        if self._log:
            return self._log[-1].log_index
        else:
            return _DEFAULT_LOG_INDEX