Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ mochawesome-report/
go.work
go.work.sum
*.pem
.rjs

51 changes: 51 additions & 0 deletions delivery/raft-enabled-api/dragonboat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package raftenabledapi

import (
"encoding/json"
"io"
"net/http"

"github.com/julienschmidt/httprouter"
"github.com/lni/dragonboat/v4"
"github.com/lni/dragonboat/v4/config"
)

type dragonboatImpl struct {
nh *dragonboat.NodeHost
}

func NewDragonboatReplica(nh *dragonboat.NodeHost) *dragonboatImpl {
return nil
}

type initializeRequest struct {
Password string `json:"password"`
GSIClientID string `json:"gsi_client_id"`
GSIAdminEmails string `json:"gsi_admin_emails"`
JWTSigningKey string `json:"jwt_signing_key"`

InitialMember map[uint64]dragonboat.Target `json:"initial_member"`
}

func (d *dragonboatImpl) StartReplica(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
payload, err := io.ReadAll(r.Body)
if err != nil {
return
}

var req initializeRequest
err = json.Unmarshal(payload, &req)
if err != nil {
return
}

rc := config.Config{
ReplicaID: 0,
ShardID: 0,
}

err = d.nh.StartOnDiskReplica(req.InitialMember, false, NewDiskKV, rc)
if err != nil {
return
}
}
83 changes: 83 additions & 0 deletions delivery/raft-enabled-api/fsm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package raftenabledapi

import (
"encoding/binary"
"fmt"
"io"
"io/ioutil"

sm "github.com/lni/dragonboat/v4/statemachine"
)

// ExampleStateMachine is the IStateMachine implementation used in the
// helloworld example.
// See https://github.com/lni/dragonboat/blob/master/statemachine/rsm.go for
// more details of the IStateMachine interface.
type ExampleStateMachine struct {
ShardID uint64
ReplicaID uint64
Count uint64
}

// NewExampleStateMachine creates and return a new ExampleStateMachine object.
func NewExampleStateMachine(shardID uint64,
replicaID uint64) sm.IStateMachine {
return &ExampleStateMachine{
ShardID: shardID,
ReplicaID: replicaID,
Count: 0,
}
}

// Lookup performs local lookup on the ExampleStateMachine instance. In this example,
// we always return the Count value as a little endian binary encoded byte
// slice.
func (s *ExampleStateMachine) Lookup(query interface{}) (interface{}, error) {
result := make([]byte, 8)
binary.LittleEndian.PutUint64(result, s.Count)
return result, nil
}

// Update updates the object using the specified committed raft entry.
func (s *ExampleStateMachine) Update(e sm.Entry) (sm.Result, error) {
// in this example, we print out the following hello world message for each
// incoming update request. we also increase the counter by one to remember
// how many updates we have applied
s.Count++
fmt.Printf("from ExampleStateMachine.Update(), msg: %s, count:%d\n",
string(e.Cmd), s.Count)
return sm.Result{Value: uint64(len(e.Cmd))}, nil
}

// SaveSnapshot saves the current IStateMachine state into a snapshot using the
// specified io.Writer object.
func (s *ExampleStateMachine) SaveSnapshot(w io.Writer,
fc sm.ISnapshotFileCollection, done <-chan struct{}) error {
// as shown above, the only state that can be saved is the Count variable
// there is no external file in this IStateMachine example, we thus leave
// the fc untouched
data := make([]byte, 8)
binary.LittleEndian.PutUint64(data, s.Count)
_, err := w.Write(data)
return err
}

// RecoverFromSnapshot recovers the state using the provided snapshot.
func (s *ExampleStateMachine) RecoverFromSnapshot(r io.Reader,
files []sm.SnapshotFile,
done <-chan struct{}) error {
// restore the Count variable, that is the only state we maintain in this
// example, the input files is expected to be empty
data, err := ioutil.ReadAll(r)
if err != nil {
return err
}
v := binary.LittleEndian.Uint64(data)
s.Count = v
return nil
}

// Close closes the IStateMachine instance. There is nothing for us to cleanup
// or release as this is a pure in memory data store. Note that the Close
// method is not guaranteed to be called as node can crash at any time.
func (s *ExampleStateMachine) Close() error { return nil }
Loading