Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Add raft example #153

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open

Commits on Feb 21, 2024

  1. Add a Linux implementation of file locking

    This is taken straight from
    
        github.com/etcd-io/etcd:client/pkg/fileutil/lock_flock.go
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    247f961 View commit details
    Browse the repository at this point in the history
  2. Fix/suppress some linter warnings

    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    e2141f7 View commit details
    Browse the repository at this point in the history
  3. Define SnapshotStorage interface

    This interface defines what `kvstore` needs for saving and loading
    snapshots.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    7b97b3a View commit details
    Browse the repository at this point in the history
  4. Define KVStore interface

    This interface defines what `httpKVAPI` needs as the backing key-value
    store.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    84b03dc View commit details
    Browse the repository at this point in the history
  5. raftNode: initialize snapshotStorage in newRaftNode()

    Initialize the snapshot storage in `newRaftNode()` rather than in
    `startRaft()`. This is a step towards getting rid of the
    `snapshotStorageReady` channel.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    cdd60c2 View commit details
    Browse the repository at this point in the history
  6. newRaftNode(): inline part of the goroutine's work

    This is another step towards getting rid of `snapshotStorageReady`.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    5034ccf View commit details
    Browse the repository at this point in the history
  7. startRaftNode(): replacement for newRaftNode()

    Rename `newRaftNode()` to `startRaftNode()`, and change it to replay
    the WAL synchronously, before returning. This doesn't change anything,
    because the callers were all waiting for `snapshotStorageReady` before
    proceeding anyway.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    c1dd4dc View commit details
    Browse the repository at this point in the history
  8. raftNode.snapdir: remove member

    Use a local variable (in `startRaftNode()`) instead.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    2a547ec View commit details
    Browse the repository at this point in the history
  9. raftNode.id: convert type to uint64

    This is more consistent with the types used elsewhere for IDs.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    0fdf48b View commit details
    Browse the repository at this point in the history
  10. startRaftNode(): take the SnapshotStorage as an argument

    This is the sort of thing that the caller should be able to inject,
    and it's not part of the raft algorithm itself. This change makes it
    clearer what a user of the raft algorithm must supply to it.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    17981fa View commit details
    Browse the repository at this point in the history
  11. kvstore.loadAndApplySnapshot(), applyCommits(): extract methods

    Extract two new methods, for clarity and to reduce code duplication.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    34654f2 View commit details
    Browse the repository at this point in the history
  12. kvstore: separate initialization from startup

    Change `newKVStore()` to set up the initial state, but not start the
    `readCommits()` goroutine anymore. Instead, change the callers to call
    `processCommits()` (a renamed version of `readCommits()`) themselves
    (in a goroutine).
    
    The main benefit of this change is that the `kvstore` can be
    instantiated before calling `startRaftNode()`, meaning that
    `startRaftNode()` can be passed `kvs.getSnapshot` as an argument.
    Previously, it had to be passed an anonymous function that refers to a
    variable (`kvs`) that has not yet been initialized. This asynchrony
    was confusing and unnecessary.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    5be8540 View commit details
    Browse the repository at this point in the history
  13. kvstore.loadSnapshot(): inline method

    It wasn't doing anything useful.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    302d8a5 View commit details
    Browse the repository at this point in the history
  14. FSM: new interface, representing a finite state machine

    Add a new interface, `FSM`, which represents a finite state machine
    that can be driven by raft.
    
    Also add `kvfsm`, which is an `FSM` view of a `kvstore`. Treating
    `kvstore` and `kvfsm` as separate types means that the public
    interface of `kvstore` is not contaminated with internal methods that
    are only there to support raft and should not be invoked by the user.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    78c9106 View commit details
    Browse the repository at this point in the history
  15. Move more functionality from kvstore to kvfsm

    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    9163a7d View commit details
    Browse the repository at this point in the history
  16. TestProposeOnCommit(): add some clarifying comments

    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    2ea3a54 View commit details
    Browse the repository at this point in the history
  17. raftexample_test: introduce peer type

    Make `cluster` hold an array of `peer`s, rather than one array for
    each peer attribute.
    
    Continue storing the names separately, since this `[]string` has to be
    passed to `startRaftNode()`.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    a328306 View commit details
    Browse the repository at this point in the history
  18. raftexample_test: give each peer its own FSM

    The tests can be made cleverer if each `peer` in a `cluster` can be
    instantiated with an arbitrary finite state machine. We'll use this to
    make some tests able to operate more like normal clients of
    `raftNode`s.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    7b9b2cc View commit details
    Browse the repository at this point in the history
  19. kvfsm.applyCommits(): return an error

    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    1de94b9 View commit details
    Browse the repository at this point in the history
  20. FSM.ProcessCommits(): return an error rather than calling log.Fatal()

    Handle such errors at the caller, instead.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    b44de5b View commit details
    Browse the repository at this point in the history
  21. FSM.ApplyCommits(): new method

    This is a step towards moving `ProcessCommits()` out of this interface
    and into `raftNode`.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    58d3994 View commit details
    Browse the repository at this point in the history
  22. newKVStore(): don't call LoadAndApplySnapshot()

    Instead, make `LoadAndApplySnapshot()` part of the `FSM` interface,
    and have the callers of `newKVStore()` invoke that method after
    calling `newKVStore()`. This is a step towards moving this
    functionality entirely out of `FSM`.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    4feda00 View commit details
    Browse the repository at this point in the history
  23. Make ProcessCommits() a method of raftNode

    Now that the `FSM` interface is more capable, there is no reason that
    this method, which has more to do with raft anyway, can't be
    implemented in `raftNode`. This makes it easier to implement new FSMs
    without having to reimplement this method.
    
    This means that `newRaftNode()` has to return a pointer to the
    `raftNode`, so make that change, too. This change will make other
    future changes simpler, too.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    ba8d8ca View commit details
    Browse the repository at this point in the history
  24. newRaftNode(): call LoadAndApplySnapshot() here

    Make this a standard part of starting up a node.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    bb3c651 View commit details
    Browse the repository at this point in the history
  25. LoadAndApplySnapshot(): move method to raftNode and make it private

    This is the last use of `kvstore.snapshotStorage`, so remove that
    field as well.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    73ae94b View commit details
    Browse the repository at this point in the history
  26. raftNode: add a new and better way to tell when the node is done

    The old method, monitoring the `errorC` channel, is not great because
    the error only pops out of that channel once. Which of the pieces of
    code that are waiting on that channel reads the error? Nobody knows!
    
    Instead, provide a `Done()` method and an `Err()` method that
    interested parties can use to determine when the node finishes and
    what error it returned.
    
    The callers haven't been changed yet.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    c0cac21 View commit details
    Browse the repository at this point in the history
  27. serveHTTPKVAPI(): monitor the raft node using its "done" channel

    Use the `done` channel instead of the `errorC` channel for monitoring
    for the completion of the raft node. If the channel is closed, don't
    log the error, since the caller of `ProcessCommits()` is already
    taking care of that.
    
    Since this means that we're not killing the server by aborting the
    program, we now have to call `srv.Close()` explicitly.
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    b19e64f View commit details
    Browse the repository at this point in the history
  28. cluster.Close(): read any error from the node directly

    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    b4c1a55 View commit details
    Browse the repository at this point in the history
  29. TestProposeOnCommit(): read any error from the node directly

    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    d420ab3 View commit details
    Browse the repository at this point in the history
  30. cluster.Cleanup(): new method, extracted from Close()

    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    d181e4a View commit details
    Browse the repository at this point in the history
  31. TestProposeOnCommit(): change test to use ProcessCommits()

    Instead of driving the channels within the test, user a cleverer FSM
    and call `ProcessCommits()` to manage the channels.
    
    The old version of the test only looked at the first data item in each
    `commit`, even though multiple data items can be sent in a single
    `commit`. It also only looked at the first 100 commits, even though
    there is a multiplication factor because each node initiates 100
    proposals. The new version checks all data items, and checks that the
    total number of commits is as expected (namely, 100 for each node, or
    300 total).
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    0ae9c56 View commit details
    Browse the repository at this point in the history
  32. newRaftNode(): don't return commitC and errorC

    Keep `commitC` and `errorC` internal to `raftNode`: don't return them
    from `newRaftNode()`, and don't require them as arguments to
    `(*raftNode).ProcessCommits()`.
    
    (Some tests still need them, but they can access the members directly
    on the `raftNode` instance.)
    
    Signed-off-by: Michael Haggerty <[email protected]>
    mhagger authored and Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    848ee9d View commit details
    Browse the repository at this point in the history
  33. add raft example

    Elbehery committed Feb 21, 2024
    Configuration menu
    Copy the full SHA
    cd6fbb1 View commit details
    Browse the repository at this point in the history