Skip to content

Commit

Permalink
Fix issues in README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
LVala authored Jul 26, 2024
1 parent b6674ee commit b2473fc
Showing 1 changed file with 15 additions and 17 deletions.
32 changes: 15 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@
This repository houses `zaft` - [Raft Consensus Algorithm](https://raft.github.io/) library implemented in Zig. It provides the building blocks
for creating distributed systems requiring consensus among replicated state machines, like databases.


![tang demo](tang.gif)
</div>

## Installation

This package can be installed using the Zig package manager. In your `build.zig.zon` add `zaft` to dependency list:
This package can be installed using the Zig package manager. In your `build.zig.zon` add `zaft` to the dependency list:

```zig
// in build.zig.zon
Expand Down Expand Up @@ -51,14 +49,14 @@ const zaft = @import("zaft");

## Usage

This section will show you how to integrate `zaft` with your program step-by-step. If you want to take look at a fully working example,
This section will show you how to integrate `zaft` with your program step-by-step. If you want to take a look at a fully working example,
check out the [kv_store](./examples/kv_store) - in-memory, replicated key-value store based on `zaft`.

> [!IMPORTANT]
> This tutorial assumes some familiarity with the Raft Consensus Algorithm. If not, I highly advise you to at least skim through
> the [Raft paper](https://raft.github.io/raft.pdf). Don't worry, it's a short and very well written paper!
> the [Raft paper](https://raft.github.io/raft.pdf). Don't worry, it's a short and very well-written paper!
Firstly, initialise the `Raft` struct:
Firstly, initialize the `Raft` struct:

```zig
// we'll get to UserData and Entry in a second
Expand Down Expand Up @@ -128,7 +126,7 @@ fn persistVotedFor(ud: *UserData, voted_for: ?u32) !void {
```

> [!WARNING]
> Notice that all of the callbacks can return an error (mostly for the sake of convinience).
> Notice that all of the callbacks can return an error (mostly for the sake of convenience).
>
> Error returned from `makeRPC` will be ignored, the RPC will be simply retried after
> an appropriate timeout. Errors returned from other function, as of now, will result in a panic.
Expand Down Expand Up @@ -157,7 +155,7 @@ const callbacks = Raft.Callbacks {
```

* `initial_state` - the persisted state of this Raft node. On each reboot, you need to read the persisted Raft state, that
is the `current_term`, `voted_for` and `log` and use it as the `InitialState`:
is the `current_term`, `voted_for`, and `log` and use it as the `InitialState`:

```zig
const initial_state = Raft.InitialState {
Expand All @@ -168,25 +166,25 @@ const initial_state = Raft.InitialState {
};
```

and lastly, an `std.mem.Allocator` to provide memory for the Raft log.
Lastly, an `std.mem.Allocator` will be used to provide memory for the Raft log.

---

The `Raft` struct needs to be periodically ticked in order to trigger timeouts and other necessary actions. You can use a separate thread to do that, or
The `Raft` struct needs to be periodically ticked to trigger timeouts and other necessary actions. You can use a separate thread to do that, or
built your program based on an event loop like [libexev](https://github.com/mitchellh/libxev) with its `xev.Timer`.

```zig
const tick_after = raft.tick();
// tick_after is a number of milliseconds after which raft should be ticked again
// tick_after is the number of milliseconds after which raft should be ticked again
```

For instance, [kv_store](./examples/kv_store/src/ticker.zig) uses a separate thread exclusively to tick the `Raft` struct.

> [!WARNING]
> The `Raft` struct is *not* thread-safe. Use appropriate synchronization means to makes sure it is not accessed simultaneously by many threads
> The `Raft` struct is *not* thread-safe. Use appropriate synchronization means to make sure it is not accessed simultaneously by many threads
> (e.g. a simple `std.Thread.Mutex` will do).
Next, messages from other Raft nodes need to be feed to local `Raft` struct by calling:
Next, messages from other Raft nodes need to be fed to the local `Raft` struct by calling:

```zig
// you will need to receive and deserialize the messages from other peers
Expand All @@ -201,12 +199,12 @@ const entry = Entry { ... };
const idx = try raft.appendEntry(entry);
```

It will return an index of the new entry. According to the Raft algorithm, you program should block on client request
until the entry has been applied. You can use `std.Thread.Condition` and call its `notify` function in the `applyEntry` callback in order to notify
the program that the entry was applied. You can check whether entry was applied by using `raft.checkIfApplied(idx)`.
It will return an index of the new entry. According to the Raft algorithm, your program should block on client requests
until the entry has been applied. You can use `std.Thread.Condition` and call its `notify` function in the `applyEntry` callback to notify
the program that the entry was applied. You can check whether the entry was applied by using `raft.checkIfApplied(idx)`.
Take a look at how [kv_store](./examples/kv_store/src/main.zig) does this.

`appendEntry` function will return error if the node is not a leader. In such case, you should redirect the client request to the leader node.
`appendEntry` function will return an error if the node is not a leader. In such a case, you should redirect the client request to the leader node.
You can check which node is the leader by using `raft.getCurrentLeader()`. You can also check if the node is a leader proactively by calling
`raft.checkifLeader()`.

Expand Down

0 comments on commit b2473fc

Please sign in to comment.