/
client.go
138 lines (114 loc) · 2.7 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package phaul
import (
"fmt"
"github.com/checkpoint-restore/go-criu/v7"
"github.com/checkpoint-restore/go-criu/v7/crit"
"github.com/checkpoint-restore/go-criu/v7/crit/images/stats"
"github.com/checkpoint-restore/go-criu/v7/rpc"
"google.golang.org/protobuf/proto"
)
const (
minPagesWritten uint64 = 64
maxIters int = 8
maxGrowDelta int64 = 32
)
// Client struct
type Client struct {
local Local
remote Remote
cfg Config
}
// MakePhaulClient function
// Main entry point. Caller should create the client object by
// passing here local, remote and comm. See comment in corresponding
// interfaces/structs for explanation.
//
// Then call client.Migrate() and enjoy :)
func MakePhaulClient(l Local, r Remote, c Config) (*Client, error) {
return &Client{local: l, remote: r, cfg: c}, nil
}
func isLastIter(iter int, stats *stats.DumpStatsEntry, prevStats *stats.DumpStatsEntry) bool {
if iter >= maxIters {
fmt.Printf("`- max iters reached\n")
return true
}
pagesWritten := stats.GetPagesWritten()
if pagesWritten < minPagesWritten {
fmt.Printf("`- tiny pre-dump (%d) reached\n", int(pagesWritten))
return true
}
pagesDelta := int64(pagesWritten) - int64(prevStats.GetPagesWritten())
if pagesDelta >= maxGrowDelta {
fmt.Printf("`- grow iter (%d) reached\n", int(pagesDelta))
return true
}
return false
}
// Migrate function
func (pc *Client) Migrate() error {
criu := criu.MakeCriu()
psi := rpc.CriuPageServerInfo{
Fd: proto.Int32(int32(pc.cfg.Memfd)),
}
opts := &rpc.CriuOpts{
Pid: proto.Int32(int32(pc.cfg.Pid)),
LogLevel: proto.Int32(4),
LogFile: proto.String("pre-dump.log"),
Ps: &psi,
}
err := criu.Prepare()
if err != nil {
return err
}
defer criu.Cleanup()
imgs, err := preparePhaulImages(pc.cfg.Wdir)
if err != nil {
return err
}
prevStats := &stats.DumpStatsEntry{}
iter := 0
for {
err = pc.remote.StartIter()
if err != nil {
return err
}
prevP := imgs.lastImagesDir()
imgDir, err := imgs.openNextDir()
if err != nil {
return err
}
opts.ImagesDirFd = proto.Int32(int32(imgDir.Fd()))
if prevP != "" {
opts.ParentImg = proto.String(prevP)
}
err = criu.PreDump(opts, nil)
imgDir.Close()
if err != nil {
return err
}
iter++
err = pc.remote.StopIter()
if err != nil {
return err
}
// Get dump statistics with crit
stats, err := crit.GetDumpStats(imgDir.Name())
if err != nil {
return err
}
if isLastIter(iter, stats, prevStats) {
break
}
prevStats = stats
}
err = pc.remote.StartIter()
if err == nil {
prevP := imgs.lastImagesDir()
err = pc.local.DumpCopyRestore(criu, pc.cfg, prevP)
err2 := pc.remote.StopIter()
if err == nil {
err = err2
}
}
return err
}