Part A

Part A implements the basic functionality of the Two Phase Commit protocol.

Unit Testing

Test Driven Development (TDD) is a crucial part of designing large systems and software in general. Golang has built-in testing features that we will take advantage of for unit testing. In the skeleton code, the FileJournal actually has a bug in its Empty function. The FileJournal is built on top of a file where each line is a journal entry. If a crash were to happen, the journal is read and its entries are replayed. The Empty function is periodically called at the end of the transaction of prevent the journal from growing unnecessarily large.

  1. Write a test to test the functionality of Empty in the file pkg/journal/journal_test.go. You may want to look at the other test in same file and those in pkg/kvstore/kvstore_test.go to get a sense of how testing works in Go. This test should make sure that the log is actually emptied when Empty is called.

    Hint: You may want to use an EntryIterator to verify.

  2. Now that this new test fails on the current code, use the output of your test to find and fix the bug in the FileJournal.

The Journal itself is not used in Part A, but fixing this bug and writing the test is worth points for this Part A. You can read more about the Journal interface in Important Existing Code. If you plan on completing Part B, you will need to implement this before you start.

Follower 2PC Handling

You should implement the 2PC follower to correctly handle normal GET and two-phase commit messages. Refer to Two Phase Commit for details on the implementation of two-phase commit logic. Refer to Testing for how to bypass the leader to communicate with followers directly.

Start by looking at the function HandleMessage in pkg/tpc/tpcfollower.go. This function is called every time the follower receives a message from the leader.

Based on what the message is, it will call either vote or global. You are responsible for filling in these two functions to update the follower state machine and return the appropriate response.

For Part A, there is not a need to implement any journaling or the replayJournal function.

Leader 2PC Handling

You should implement the 2PC leader to correctly handle normal GET and PUT requests. Refer to Two Phase Commit for details on the implementation of two-phase commit logic. The leader needs to send Leader messages to all of its followers as well as process the results from the followers. Refer to Testing for how to mock a follower for the Leader to communicate with.

Start by looking at the function Put . This is the function where all Two Phase Commit transactions begin. The purpose of this function is to update the leader state machine and send the correct messages to the followers. This function will call voteRequest and globalRequest.

voteRequest and globalRequest are responsible for sending the correct messages to the followers and parsing the response. Both functions call SendMessage, which returns a channel where the responses will be placed. You can expect there will eventually be numFollowers responses.

For voteRequest, if any of the responses are an ABORT then the function should return an ABORT. For globalRequest, it doesn't matter what each follower returns since the only thing that can be returned is an ACK. Rather, you should block until you receive numFollower ACKs.

One point of confusion here is what the SendMessage function does. SendMessage takes a LeaderMsg and sends it to every follower the leader is connected to. It returns a Go channel of the responses and you can expect that there will eventually be numFollowers items in that channel.

Channels are a Go feature that can be considered a built-in bounded queue. If the retry argument is set to True, then SendMessage will resend the same message to a follower that fails to respond within a timeout or responds with an error. If it is set to False, then such a follower will be considered to have responded with an ABORT by default. This may be useful in implementing the behavior of the Vote phases versus a Global phase.

For Part A, there is not need to implement any journaling or the replayJournal function.

Last updated