@@ -25,25 +25,30 @@ package firecracker
2525import (
2626 "context"
2727 "fmt"
28+ "github.com/ease-lab/vhive/ctriface"
2829 "github.com/ease-lab/vhive/metrics"
2930 "github.com/ease-lab/vhive/snapshotting"
31+ "github.com/ease-lab/vhive/snapshotting/deduplicated"
32+ "github.com/ease-lab/vhive/snapshotting/regular"
3033 "github.com/pkg/errors"
3134 "strconv"
3235 "sync"
3336 "sync/atomic"
3437 "time"
3538
36- "github.com/ease-lab/vhive/ctriface"
3739 log "github.com/sirupsen/logrus"
3840)
3941
4042const snapshotsDir = "/fccd/snapshots"
4143
44+ // TODO: interface for orchestrator
45+
4246type coordinator struct {
4347 sync.Mutex
4448 orch * ctriface.Orchestrator
4549 nextID uint64
4650 isSparseSnaps bool
51+ isDeduplicatedSnaps bool
4752
4853 activeInstances map [string ]* FuncInstance
4954 snapshotManager * snapshotting.SnapshotManager
@@ -59,12 +64,18 @@ func withoutOrchestrator() coordinatorOption {
5964 }
6065}
6166
62- func newFirecrackerCoordinator (orch * ctriface.Orchestrator , snapsCapacityMiB int64 , isSparseSnaps bool , opts ... coordinatorOption ) * coordinator {
67+ func newFirecrackerCoordinator (orch * ctriface.Orchestrator , snapsCapacityMiB int64 , isSparseSnaps bool , isDeduplicatedSnaps bool , opts ... coordinatorOption ) * coordinator {
6368 c := & coordinator {
6469 activeInstances : make (map [string ]* FuncInstance ),
6570 orch : orch ,
66- snapshotManager : snapshotting .NewSnapshotManager (snapshotsDir , snapsCapacityMiB ),
67- isSparseSnaps : isSparseSnaps ,
71+ isSparseSnaps : isSparseSnaps ,
72+ isDeduplicatedSnaps : isDeduplicatedSnaps ,
73+ }
74+
75+ if isDeduplicatedSnaps {
76+ c .snapshotManager = snapshotting .NewSnapshotManager (deduplicated .NewSnapshotManager (snapshotsDir , snapsCapacityMiB ))
77+ } else {
78+ c .snapshotManager = snapshotting .NewSnapshotManager (regular .NewRegularSnapshotManager (snapshotsDir ))
6879 }
6980
7081 for _ , opt := range opts {
@@ -76,12 +87,24 @@ func newFirecrackerCoordinator(orch *ctriface.Orchestrator, snapsCapacityMiB int
7687
7788func (c * coordinator ) startVM (ctx context.Context , image string , revision string , memSizeMib , vCPUCount uint32 ) (* FuncInstance , error ) {
7889 if c .orch != nil && c .orch .GetSnapshotsEnabled () {
90+ id := image
91+ if c .isDeduplicatedSnaps {
92+ id = revision
93+ }
94+
7995 // Check if snapshot is available
80- if snap , err := c .snapshotManager .AcquireSnapshot (revision ); err == nil {
96+ if snap , err := c .snapshotManager .AcquireSnapshot (id ); err == nil {
8197 if snap .MemSizeMib != memSizeMib || snap .VCPUCount != vCPUCount {
8298 return nil , errors .New ("Please create a new revision when updating uVM memory size or vCPU count" )
8399 } else {
84- return c .orchStartVMSnapshot (ctx , snap , memSizeMib , vCPUCount )
100+ vmID := ""
101+ if c .isDeduplicatedSnaps {
102+ vmID = strconv .Itoa (int (atomic .AddUint64 (& c .nextID , 1 )))
103+ } else {
104+ vmID = snap .GetId ()
105+ }
106+
107+ return c .orchStartVMSnapshot (ctx , snap , memSizeMib , vCPUCount , vmID )
85108 }
86109 } else {
87110 return c .orchStartVM (ctx , image , revision , memSizeMib , vCPUCount )
@@ -106,17 +129,30 @@ func (c *coordinator) stopVM(ctx context.Context, containerID string) error {
106129 return nil
107130 }
108131
132+ if c .orch == nil || ! c .orch .GetSnapshotsEnabled () {
133+ return c .orchStopVM (ctx , fi )
134+ }
135+
136+ id := fi .vmID
137+ if c .isDeduplicatedSnaps {
138+ id = fi .revisionId
139+ }
140+
109141 if fi .snapBooted {
110- defer c .snapshotManager .ReleaseSnapshot (fi . revisionId )
111- } else if c . orch != nil && c . orch . GetSnapshotsEnabled () {
142+ defer c .snapshotManager .ReleaseSnapshot (id )
143+ } else {
112144 // Create snapshot
113145 err := c .orchCreateSnapshot (ctx , fi )
114146 if err != nil {
115147 log .Printf ("Err creating snapshot %s\n " , err )
116148 }
117149 }
118150
119- return c .orchStopVM (ctx , fi )
151+ if c .isDeduplicatedSnaps {
152+ return c .orchStopVM (ctx , fi )
153+ } else {
154+ return c .orchOffloadVM (ctx , fi )
155+ }
120156}
121157
122158// for testing
@@ -178,9 +214,8 @@ func (c *coordinator) orchStartVM(ctx context.Context, image, revision string, m
178214 return fi , err
179215}
180216
181- func (c * coordinator ) orchStartVMSnapshot (ctx context.Context , snap * snapshotting.Snapshot , memSizeMib , vCPUCount uint32 ) (* FuncInstance , error ) {
217+ func (c * coordinator ) orchStartVMSnapshot (ctx context.Context , snap * snapshotting.Snapshot , memSizeMib , vCPUCount uint32 , vmID string ) (* FuncInstance , error ) {
182218 tStartCold := time .Now ()
183- vmID := strconv .Itoa (int (atomic .AddUint64 (& c .nextID , 1 )))
184219 logger := log .WithFields (
185220 log.Fields {
186221 "vmID" : vmID ,
@@ -210,7 +245,7 @@ func (c *coordinator) orchStartVMSnapshot(ctx context.Context, snap *snapshottin
210245 }
211246
212247 coldStartTimeMs := metrics .ToMs (time .Since (tStartCold ))
213- fi := NewFuncInstance (vmID , snap .GetImage (), snap .GetRevisionId (), resp , true , memSizeMib , vCPUCount , coldStartTimeMs )
248+ fi := NewFuncInstance (vmID , snap .GetImage (), snap .GetId (), resp , true , memSizeMib , vCPUCount , coldStartTimeMs )
214249 logger .Debug ("successfully loaded instance from snapshot" )
215250
216251 return fi , err
@@ -224,17 +259,23 @@ func (c *coordinator) orchCreateSnapshot(ctx context.Context, fi *FuncInstance)
224259 },
225260 )
226261
227- removeContainerSnaps , snap , err := c .snapshotManager .InitSnapshot (fi .revisionId , fi .image , fi .coldStartTimeMs , fi .memSizeMib , fi .vCPUCount , c .isSparseSnaps )
262+ id := fi .vmID
263+ if c .isDeduplicatedSnaps {
264+ id = fi .revisionId
265+ }
266+
267+ removeContainerSnaps , snap , err := c .snapshotManager .InitSnapshot (id , fi .image , fi .coldStartTimeMs , fi .memSizeMib , fi .vCPUCount , c .isSparseSnaps )
268+
228269 if err != nil {
229270 if fmt .Sprint (err ) == "There is not enough free space available" {
230271 fi .logger .Info (fmt .Sprintf ("There is not enough space available for snapshots of %s" , fi .revisionId ))
231272 }
232273 return nil
233274 }
234275
235- if removeContainerSnaps != nil {
276+ if c . isDeduplicatedSnaps && removeContainerSnaps != nil {
236277 for _ , cleanupSnapId := range * removeContainerSnaps {
237- if err := c .orch .CleanupRevisionSnapshot (ctx , cleanupSnapId ); err != nil {
278+ if err := c .orch .CleanupSnapshot (ctx , cleanupSnapId ); err != nil {
238279 return errors .Wrap (err , "removing devmapper revision snapshot" )
239280 }
240281 }
@@ -257,7 +298,7 @@ func (c *coordinator) orchCreateSnapshot(ctx context.Context, fi *FuncInstance)
257298 return nil
258299 }
259300
260- if err := c .snapshotManager .CommitSnapshot (fi . revisionId ); err != nil {
301+ if err := c .snapshotManager .CommitSnapshot (id ); err != nil {
261302 fi .logger .WithError (err ).Error ("failed to commit snapshot" )
262303 return err
263304 }
@@ -277,3 +318,16 @@ func (c *coordinator) orchStopVM(ctx context.Context, fi *FuncInstance) error {
277318
278319 return nil
279320}
321+
322+ func (c * coordinator ) orchOffloadVM (ctx context.Context , fi * FuncInstance ) error {
323+ if c .withoutOrchestrator {
324+ return nil
325+ }
326+
327+ if err := c .orch .OffloadVM (ctx , fi .vmID ); err != nil {
328+ fi .logger .WithError (err ).Error ("failed to offload VM" )
329+ return err
330+ }
331+
332+ return nil
333+ }
0 commit comments