Skip to content

[Feature]: Persist imported Mission Control Data across restarts #8898

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

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
8 changes: 7 additions & 1 deletion cmd/lncli/cmd_import_mission_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ var importMissionControlCommand = cli.Command{
Name: "force",
Usage: "whether to force the history entry import",
},
cli.BoolFlag{
Name: "persist_mc",
Usage: "whether to persist the imported mission " +
"control to disk",
},
},
}

Expand Down Expand Up @@ -91,7 +96,8 @@ func importMissionControl(ctx *cli.Context) error {
Pairs: []*routerrpc.PairHistory{
importResult,
},
Force: ctx.IsSet("force"),
Force: ctx.IsSet("force"),
PersistMc: ctx.IsSet("persist_mc"),
}

rpcCtx := context.Background()
Expand Down
12 changes: 11 additions & 1 deletion cmd/lncli/cmd_mission_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,13 @@ var resetMissionControlCommand = cli.Command{
Category: "Mission Control",
Usage: "Reset internal mission control state.",
Action: actionDecorator(resetMissionControl),
Flags: []cli.Flag{
cli.BoolFlag{
Name: "reset_imported_persisted_mc",
Usage: "whether to reset the imported and persisted " +
"mission control state on disk.",
},
},
}

func resetMissionControl(ctx *cli.Context) error {
Expand All @@ -364,7 +371,10 @@ func resetMissionControl(ctx *cli.Context) error {

client := routerrpc.NewRouterClient(conn)

req := &routerrpc.ResetMissionControlRequest{}
resetImportedPersistedMC := ctx.IsSet("reset_imported_persisted_mc")
req := &routerrpc.ResetMissionControlRequest{
ResetImportedPersistedMc: resetImportedPersistedMC,
}
_, err := client.ResetMissionControl(ctxc, req)
return err
}
928 changes: 477 additions & 451 deletions lnrpc/routerrpc/router.pb.go

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion lnrpc/routerrpc/router.proto
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ service Router {

/* lncli: `resetmc`
ResetMissionControl clears all mission control state and starts with a clean
slate.
state. If the reset_imported_persisted_mc flag is set to true, it also
resets the imported and persisted mission control data on disk.
*/
rpc ResetMissionControl (ResetMissionControlRequest)
returns (ResetMissionControlResponse);
Expand Down Expand Up @@ -443,6 +444,9 @@ message SendToRouteResponse {
}

message ResetMissionControlRequest {
// Whether to reset the imported and persisted mission control state on
// disk.
bool reset_imported_persisted_mc = 1;
}

message ResetMissionControlResponse {
Expand All @@ -467,6 +471,9 @@ message XImportMissionControlRequest {
// override the failure pair is imported before the success pair and both
// still clamp existing failure/success amounts.
bool force = 2;

// Whether to persist the imported mission control to disk.
bool persist_mc = 3;
}

message XImportMissionControlResponse {
Expand Down
14 changes: 12 additions & 2 deletions lnrpc/routerrpc/router.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@
},
"/v2/router/mc/reset": {
"post": {
"summary": "lncli: `resetmc`\nResetMissionControl clears all mission control state and starts with a clean\nslate.",
"summary": "lncli: `resetmc`\nResetMissionControl clears all mission control state and starts with a clean\nstate. If the reset_imported_persisted_mc flag is set to true, it also\nresets the imported and persisted mission control data on disk.",
"operationId": "Router_ResetMissionControl",
"responses": {
"200": {
Expand Down Expand Up @@ -1624,7 +1624,13 @@
}
},
"routerrpcResetMissionControlRequest": {
"type": "object"
"type": "object",
"properties": {
"reset_imported_persisted_mc": {
"type": "boolean",
"description": "Whether to reset the imported and persisted mission control state on\ndisk."
}
}
},
"routerrpcResetMissionControlResponse": {
"type": "object"
Expand Down Expand Up @@ -1895,6 +1901,10 @@
"force": {
"type": "boolean",
"description": "Whether to force override MC pair history. Note that even with force\noverride the failure pair is imported before the success pair and both\nstill clamp existing failure/success amounts."
},
"persist_mc": {
"type": "boolean",
"description": "Whether to persist the imported mission control to disk."
}
}
},
Expand Down
14 changes: 9 additions & 5 deletions lnrpc/routerrpc/router_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,21 @@ type MissionControl interface {
amt lnwire.MilliSatoshi, capacity btcutil.Amount) float64

// ResetHistory resets the history of MissionControl returning it to a
// state as if no payment attempts have been made.
ResetHistory() error
// state as if no payment attempts have been made.If the
// resetImportedPersistedMC flag is set to true, it also resets the
// imported and persisted mission control data on disk.
ResetHistory(resetImportedPersistedMC bool) error

// GetHistorySnapshot takes a snapshot from the current mission control
// state and actual probability estimates.
GetHistorySnapshot() *routing.MissionControlSnapshot

// ImportHistory imports the mission control snapshot to our internal
// state. This import will only be applied in-memory, and will not be
// persisted across restarts.
ImportHistory(snapshot *routing.MissionControlSnapshot, force bool) error
// state. This import will be applied both in-memory and persisted to
// disk, ensuring that the mission control data is available across
// restarts (if persistMC flag is set).
ImportHistory(snapshot *routing.MissionControlSnapshot, force bool,
persistMC bool) error

// GetPairHistorySnapshot returns the stored history for a given node
// pair.
Expand Down
2 changes: 1 addition & 1 deletion lnrpc/routerrpc/router_backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ func (m *mockMissionControl) GetProbability(fromNode, toNode route.Vertex,
return testMissionControlProb
}

func (m *mockMissionControl) ResetHistory() error {
func (m *mockMissionControl) ResetHistory(resetImportedPersistedMC bool) error {
return nil
}

Expand Down
6 changes: 4 additions & 2 deletions lnrpc/routerrpc/router_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions lnrpc/routerrpc/router_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -887,11 +887,14 @@ func (s *Server) SendToRouteV2(ctx context.Context,
}

// ResetMissionControl clears all mission control state and starts with a clean
// slate.
// state. If the ResetImportedPersistedMc flag is set to true, it also resets
// the imported and persisted mission control data on disk.
func (s *Server) ResetMissionControl(ctx context.Context,
req *ResetMissionControlRequest) (*ResetMissionControlResponse, error) {

err := s.cfg.RouterBackend.MissionControl.ResetHistory()
err := s.cfg.RouterBackend.MissionControl.ResetHistory(
req.ResetImportedPersistedMc,
)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -1115,7 +1118,7 @@ func (s *Server) XImportMissionControl(_ context.Context,
}

err := s.cfg.RouterBackend.MissionControl.ImportHistory(
snapshot, req.Force,
snapshot, req.Force, req.PersistMc,
)
if err != nil {
return nil, err
Expand Down
45 changes: 38 additions & 7 deletions routing/missioncontrol.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,23 @@ func (m *MissionControl) init() error {
m.applyPaymentResult(result)
}

mcSnapshots, err := m.store.fetchMCData()
if err != nil {
return err
}

mcPairsPersisted := 0
for _, mcSnapshot := range mcSnapshots {
err := m.ImportHistory(mcSnapshot, false, true)
if err != nil {
return err
}
mcPairsPersisted += len(mcSnapshot.Pairs)
}

log.Debugf("Mission control state reconstruction finished: "+
"n=%v, time=%v", len(results), time.Since(start))
"raw_payment_results_count=%v, persisted_mc_pairs_count=%v, "+
"time=%v", len(results), mcPairsPersisted, time.Since(start))

return nil
}
Expand Down Expand Up @@ -312,8 +327,10 @@ func (m *MissionControl) SetConfig(cfg *MissionControlConfig) error {
}

// ResetHistory resets the history of MissionControl returning it to a state as
// if no payment attempts have been made.
func (m *MissionControl) ResetHistory() error {
// if no payment attempts have been made. If the resetImportedPersistedMC
// flag is set to true, it also resets the imported and persisted mission
// control data on disk.
func (m *MissionControl) ResetHistory(resetImportedPersistedMC bool) error {
m.Lock()
defer m.Unlock()

Expand All @@ -323,6 +340,13 @@ func (m *MissionControl) ResetHistory() error {

m.state.resetHistory()

if resetImportedPersistedMC {
err := m.store.resetMCData()
if err != nil {
return err
}
}

log.Debugf("Mission control history cleared")

return nil
Expand Down Expand Up @@ -360,11 +384,11 @@ func (m *MissionControl) GetHistorySnapshot() *MissionControlSnapshot {
return m.state.getSnapshot()
}

// ImportHistory imports the set of mission control results provided to our
// in-memory state. These results are not persisted, so will not survive
// restarts.
// ImportHistory imports the set of mission control results to our in-memory
// state and disk, ensuring that the mission control data is available across
// restarts (if persistMC flag is set).
func (m *MissionControl) ImportHistory(history *MissionControlSnapshot,
force bool) error {
force bool, persistMC bool) error {

if history == nil {
return errors.New("cannot import nil history")
Expand All @@ -378,6 +402,13 @@ func (m *MissionControl) ImportHistory(history *MissionControlSnapshot,

imported := m.state.importSnapshot(history, force)

if persistMC {
err := m.store.persistMCData(history)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it will first import the new data, and then flush the updated set to disk ?

if err != nil {
return err
}
}

log.Infof("Imported %v results to mission control", imported)

return nil
Expand Down
Loading
Loading