Skip to content

Commit 29882fb

Browse files
committed
add tests
1 parent 1c27b47 commit 29882fb

File tree

11 files changed

+278
-36
lines changed

11 files changed

+278
-36
lines changed

cri/firecracker/coordinator.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
"github.com/ease-lab/vhive/ctriface"
2929
"github.com/ease-lab/vhive/metrics"
3030
"github.com/ease-lab/vhive/snapshotting"
31-
"github.com/ease-lab/vhive/snapshotting/deduplicated"
31+
"github.com/ease-lab/vhive/snapshotting/fulllocal"
3232
"github.com/ease-lab/vhive/snapshotting/regular"
3333
"github.com/pkg/errors"
3434
"strconv"
@@ -77,9 +77,9 @@ func newFirecrackerCoordinator(
7777
}
7878

7979
if isFullLocal {
80-
c.snapshotManager = snapshotting.NewSnapshotManager(deduplicated.NewSnapshotManager(snapshotsDir, snapsCapacityMiB))
80+
c.snapshotManager = snapshotting.NewSnapshotManager(fulllocal.NewSnapshotManager(snapshotsDir, snapsCapacityMiB))
8181
} else {
82-
c.snapshotManager = snapshotting.NewSnapshotManager(regular.NewRegularSnapshotManager(snapshotsDir))
82+
c.snapshotManager = snapshotting.NewSnapshotManager(regular.NewSnapshotManager(snapshotsDir))
8383
}
8484

8585
for _, opt := range opts {
@@ -142,6 +142,7 @@ func (c *coordinator) stopVM(ctx context.Context, containerID string) error {
142142
}
143143

144144
if funcInst.snapBooted {
145+
// Release snapshot after the VM has been stopped / offloaded
145146
defer c.snapshotManager.ReleaseSnapshot(id)
146147
} else {
147148
// Create snapshot
@@ -273,7 +274,7 @@ func (c *coordinator) orchCreateSnapshot(ctx context.Context, funcInst *FuncInst
273274
id = funcInst.revisionId
274275
}
275276

276-
removeContainerSnaps, snap, err := c.snapshotManager.InitSnapshot(
277+
_, snap, err := c.snapshotManager.InitSnapshot(
277278
id,
278279
funcInst.image,
279280
funcInst.coldStartTimeMs,
@@ -286,13 +287,14 @@ func (c *coordinator) orchCreateSnapshot(ctx context.Context, funcInst *FuncInst
286287
return nil
287288
}
288289

289-
if c.isFullLocal && removeContainerSnaps != nil {
290+
// This call is only necessary if the alternative approach in devicemapper with thin-delta is used.
291+
/*if c.isFullLocal && removeContainerSnaps != nil {
290292
for _, cleanupSnapId := range *removeContainerSnaps {
291293
if err := c.orch.CleanupSnapshot(ctx, cleanupSnapId); err != nil {
292294
return errors.Wrap(err, "removing devmapper revision snapshot")
293295
}
294296
}
295-
}
297+
}*/
296298

297299
ctxTimeout, cancel := context.WithTimeout(ctx, time.Second*60)
298300
defer cancel()

ctriface/iface.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,8 @@ func (o *Orchestrator) OffloadVM(ctx context.Context, vmID string, isFullLocal b
641641
return nil
642642
}
643643

644+
// CleanupSnapshot removes a devicemapper snapshot. This function is only necessary if the alternative approach with
645+
// thin-delta is used. Otherwise, snapshots created from within vHive get already cleaned up during stopVM.
644646
func (o *Orchestrator) CleanupSnapshot(ctx context.Context, revisionID string) error {
645647
if err := o.devMapper.RemoveDeviceSnapshot(ctx, revisionID); err != nil {
646648
return errors.Wrapf(err, "removing revision snapshot")

ctriface/image/manager_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ func TestMain(m *testing.M) {
6060
TimestampFormat: ctrdlog.RFC3339NanoFixed,
6161
FullTimestamp: true,
6262
})
63-
//log.SetReportCaller(true) // FIXME: make sure it's false unless debugging
6463

6564
log.SetOutput(os.Stdout)
6665

devmapper/devicemapper.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ import (
3838
"sync"
3939
)
4040

41+
// Own managed snapshots in snapmanager and in containerd identified by snapkey. Has name deviceName.
42+
// snapshotId used internally by containerd, needed for thin_delta. Once committed, snapshots identified
43+
// by snapName within containerd?
44+
45+
// Only remove snapshots created through createSnapshot. Use key used there to delete them.
46+
4147
// DeviceMapper creates and manages device snapshots used to store container images.
4248
type DeviceMapper struct {
4349
sync.Mutex
@@ -178,6 +184,7 @@ func (dmpr *DeviceMapper) GetDeviceSnapshot(ctx context.Context, snapKey string)
178184
_, present := dmpr.snapDevices[snapKey]
179185

180186
if !present {
187+
// Get snapshot from containerd if not yet stored by vHive devicemapper
181188
info, err := dmpr.snapshotService.Stat(ctx, snapKey)
182189
if err != nil {
183190
return nil, err
@@ -210,7 +217,6 @@ func getDeviceName(poolName, snapshotId string) string {
210217
return fmt.Sprintf("%s-snap-%s", poolName, snapshotId)
211218
}
212219

213-
// CreatePatch creates a patch file storing the difference between an image and the container filesystem
214220
// CreatePatch creates a patch file storing the file differences between and image and the changes applied
215221
// by the container using rsync. Note that this is a different approach than using thin_delta which is able to
216222
// extract blocks directly by leveraging the metadata stored by the device mapper.

snapshotting/Makefile

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# MIT License
2+
#
3+
# Copyright (c) 2020 Dmitrii Ustiugov, Plamen Petrov and EASE lab
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in all
13+
# copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
23+
EXTRAGOARGS:=-v -race -cover
24+
25+
test:
26+
# Need to pass GOROOT because GitHub-hosted runners may have several
27+
# go versions installed so that calling go from root may fail
28+
sudo env "PATH=$(PATH)" "GOROOT=$(GOROOT)" go test ./ $(EXTRAGOARGS)
29+
30+
test-man:
31+
echo "Nothing to test manually"
32+
33+
.PHONY: test test-man

snapshotting/deduplicated/manager.go renamed to snapshotting/fulllocal/manager.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
// SOFTWARE.
2222

23-
package deduplicated
23+
package fulllocal
2424

2525
import (
2626
"container/heap"
@@ -32,24 +32,27 @@ import (
3232
"sync"
3333
)
3434

35-
// ImprovedSnapshotManager manages snapshots stored on the node.
36-
type ImprovedSnapshotManager struct {
35+
// FullLocalSnapshotManager manages snapshots stored on the node.
36+
type FullLocalSnapshotManager struct {
3737
sync.Mutex
38+
baseFolder string
39+
40+
// Stored snapshots
3841
snapshots map[string]*snapshotting.Snapshot
42+
// Eviction metadata for stored snapshots
3943
snapStats map[string]*SnapshotStats
4044

41-
// Heap of snapshots not in use sorted on score
45+
// Heap of snapshots not in use that can be freed to save space. Sorted by score
4246
freeSnaps SnapHeap
43-
baseFolder string
4447

4548
// Eviction
4649
clock int64 // When container last used. Increased to priority terminated container on termination
4750
capacityMib int64
4851
usedMib int64
4952
}
5053

51-
func NewSnapshotManager(baseFolder string, capacityMib int64) *ImprovedSnapshotManager {
52-
manager := new(ImprovedSnapshotManager)
54+
func NewSnapshotManager(baseFolder string, capacityMib int64) *FullLocalSnapshotManager {
55+
manager := new(FullLocalSnapshotManager)
5356
manager.snapshots = make(map[string]*snapshotting.Snapshot)
5457
manager.snapStats = make(map[string]*SnapshotStats)
5558
heap.Init(&manager.freeSnaps)
@@ -67,7 +70,7 @@ func NewSnapshotManager(baseFolder string, capacityMib int64) *ImprovedSnapshotM
6770

6871
// AcquireSnapshot returns a snapshot for the specified revision if it is available and increments the internal counter
6972
// such that the snapshot can't get removed. Similar to how a RW lock works
70-
func (mgr *ImprovedSnapshotManager) AcquireSnapshot(revision string) (*snapshotting.Snapshot, error) {
73+
func (mgr *FullLocalSnapshotManager) AcquireSnapshot(revision string) (*snapshotting.Snapshot, error) {
7174
mgr.Lock()
7275
defer mgr.Unlock()
7376

@@ -105,7 +108,7 @@ func (mgr *ImprovedSnapshotManager) AcquireSnapshot(revision string) (*snapshott
105108

106109
// ReleaseSnapshot releases the snapshot with the given revision so that it can possibly get deleted if it is not in use
107110
// by any other VMs.
108-
func (mgr *ImprovedSnapshotManager) ReleaseSnapshot(revision string) error {
111+
func (mgr *FullLocalSnapshotManager) ReleaseSnapshot(revision string) error {
109112
mgr.Lock()
110113
defer mgr.Unlock()
111114

@@ -114,6 +117,10 @@ func (mgr *ImprovedSnapshotManager) ReleaseSnapshot(revision string) error {
114117
return errors.New(fmt.Sprintf("Get: Snapshot for revision %s does not exist", revision))
115118
}
116119

120+
if snapStat.numUsing == 0 {
121+
return errors.New("Can't release a snapshot that is not in use")
122+
}
123+
117124
snapStat.numUsing -= 1
118125

119126
if snapStat.numUsing == 0 {
@@ -125,9 +132,9 @@ func (mgr *ImprovedSnapshotManager) ReleaseSnapshot(revision string) error {
125132
return nil
126133
}
127134

128-
// InitSnapshot initializes a snapshot by adding its metadata to the ImprovedSnapshotManager. Once the snapshot has been created,
135+
// InitSnapshot initializes a snapshot by adding its metadata to the FullLocalSnapshotManager. Once the snapshot has been created,
129136
// CommitSnapshot must be run to finalize the snapshot creation and make the snapshot available fo ruse
130-
func (mgr *ImprovedSnapshotManager) InitSnapshot(revision, image string, coldStartTimeMs int64, memSizeMib, vCPUCount uint32, sparse bool) (*[]string, *snapshotting.Snapshot, error) {
137+
func (mgr *FullLocalSnapshotManager) InitSnapshot(revision, image string, coldStartTimeMs int64, memSizeMib, vCPUCount uint32, sparse bool) (*[]string, *snapshotting.Snapshot, error) {
131138
mgr.Lock()
132139

133140
if _, present := mgr.snapshots[revision]; present {
@@ -172,13 +179,19 @@ func (mgr *ImprovedSnapshotManager) InitSnapshot(revision, image string, coldSta
172179
}
173180

174181
// CommitSnapshot finalizes the snapshot creation and makes it available for use.
175-
func (mgr *ImprovedSnapshotManager) CommitSnapshot(revision string) error {
182+
func (mgr *FullLocalSnapshotManager) CommitSnapshot(revision string) error {
176183
mgr.Lock()
177184
snapStat, present := mgr.snapStats[revision]
178185
if !present {
179186
mgr.Unlock()
180187
return errors.New(fmt.Sprintf("Snapshot for revision %s to commit does not exist", revision))
181188
}
189+
190+
if snapStat.usable {
191+
mgr.Unlock()
192+
return errors.New(fmt.Sprintf("Snapshot for revision %s has already been committed", revision))
193+
}
194+
182195
snap := mgr.snapshots[revision]
183196
mgr.Unlock()
184197

@@ -201,7 +214,7 @@ func (mgr *ImprovedSnapshotManager) CommitSnapshot(revision string) error {
201214

202215
// freeSpace makes sure neededMib of disk space is available by removing unused snapshots. Make sure to have a lock
203216
// when calling this function.
204-
func (mgr *ImprovedSnapshotManager) freeSpace(neededMib int64) (*[]string, error) {
217+
func (mgr *FullLocalSnapshotManager) freeSpace(neededMib int64) (*[]string, error) {
205218
var toDelete []string
206219
var freedMib int64 = 0
207220
var removeContainerSnaps []string
@@ -213,7 +226,7 @@ func (mgr *ImprovedSnapshotManager) freeSpace(neededMib int64) (*[]string, error
213226
toDelete = append(toDelete, snapStat.revisionId)
214227

215228
snap := mgr.snapshots[snapStat.revisionId]
216-
removeContainerSnaps = append(removeContainerSnaps, snap.ContainerSnapName)
229+
removeContainerSnaps = append(removeContainerSnaps, snap.GetContainerSnapName())
217230
freedMib += snapStat.TotalSizeMiB
218231
}
219232

snapshotting/deduplicated/snapHeap.go renamed to snapshotting/fulllocal/snapHeap.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121
// SOFTWARE.
2222

23-
package deduplicated
23+
package fulllocal
2424

2525
type SnapHeap []*SnapshotStats
2626

snapshotting/deduplicated/snapStats.go renamed to snapshotting/fulllocal/snapStats.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
package deduplicated
1+
package fulllocal
22

3-
// Snapshot identified by revision
4-
// Only capitalized fields are serialised / deserialised
3+
// SnapshotStats contains snapshot data used by the snapshot manager for its keepalive policy.
54
type SnapshotStats struct {
65
revisionId string
76

0 commit comments

Comments
 (0)