Skip to content

Commit 0421f14

Browse files
committed
Merge branch '317-missing-snapshots' into 'master'
fix: do a snapshot state reset atomically (#317) Closes #317 See merge request postgres-ai/database-lab!406
2 parents 4c7b92f + 0b7eed1 commit 0421f14

File tree

3 files changed

+89
-19
lines changed

3 files changed

+89
-19
lines changed

Diff for: internal/cloning/base.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -142,16 +142,16 @@ func (c *Base) CreateClone(cloneRequest *types.CloneCreateRequest) (*models.Clon
142142
return nil, errors.Wrap(err, "failed to fetch snapshots")
143143
}
144144

145-
var snapshot *models.Snapshot
145+
snapshot, err := c.getLatestSnapshot()
146+
if err != nil {
147+
return nil, errors.Wrap(err, "failed to find the latest snapshot")
148+
}
146149

147150
if cloneRequest.Snapshot != nil {
148151
snapshot, err = c.getSnapshotByID(cloneRequest.Snapshot.ID)
149-
} else {
150-
snapshot, err = c.getLatestSnapshot()
151-
}
152-
153-
if err != nil {
154-
return nil, errors.Wrap(err, "failed to get snapshot")
152+
if err != nil {
153+
return nil, errors.Wrap(err, "failed to find the requested snapshot")
154+
}
155155
}
156156

157157
clone := &models.Clone{
@@ -498,7 +498,9 @@ func (c *Base) GetClones() []*models.Clone {
498498
log.Err("Snapshot not found: ", cloneWrapper.Clone.Snapshot.ID)
499499
}
500500

501-
cloneWrapper.Clone.Snapshot = snapshot
501+
if snapshot != nil {
502+
cloneWrapper.Clone.Snapshot = snapshot
503+
}
502504
}
503505

504506
c.refreshCloneMetadata(cloneWrapper)

Diff for: internal/cloning/snapshots.go

+18-8
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ func (c *Base) fetchSnapshots() error {
2828
return errors.Wrap(err, "failed to get snapshots")
2929
}
3030

31-
c.resetSnapshots(make(map[string]*models.Snapshot, len(entries)))
31+
var latestSnapshot *models.Snapshot
32+
33+
snapshots := make(map[string]*models.Snapshot, len(entries))
3234

3335
for _, entry := range entries {
3436
numClones := 0
@@ -50,17 +52,20 @@ func (c *Base) fetchSnapshots() error {
5052
NumClones: numClones,
5153
}
5254

53-
c.addSnapshot(currentSnapshot)
55+
snapshots[entry.ID] = currentSnapshot
56+
latestSnapshot = defineLatestSnapshot(latestSnapshot, currentSnapshot)
5457

5558
log.Dbg("snapshot:", *currentSnapshot)
5659
}
5760

61+
c.resetSnapshots(snapshots, latestSnapshot)
62+
5863
return nil
5964
}
60-
func (c *Base) resetSnapshots(snapshotMap map[string]*models.Snapshot) {
65+
func (c *Base) resetSnapshots(snapshotMap map[string]*models.Snapshot, latestSnapshot *models.Snapshot) {
6166
c.snapshotBox.snapshotMutex.Lock()
6267

63-
c.snapshotBox.latestSnapshot = nil
68+
c.snapshotBox.latestSnapshot = latestSnapshot
6469
c.snapshotBox.items = snapshotMap
6570

6671
c.snapshotBox.snapshotMutex.Unlock()
@@ -70,13 +75,18 @@ func (c *Base) addSnapshot(snapshot *models.Snapshot) {
7075
c.snapshotBox.snapshotMutex.Lock()
7176

7277
c.snapshotBox.items[snapshot.ID] = snapshot
78+
c.snapshotBox.latestSnapshot = defineLatestSnapshot(c.snapshotBox.latestSnapshot, snapshot)
79+
80+
c.snapshotBox.snapshotMutex.Unlock()
81+
}
7382

74-
if c.snapshotBox.latestSnapshot == nil ||
75-
c.snapshotBox.latestSnapshot.DataStateAt == "" || c.snapshotBox.latestSnapshot.DataStateAt < snapshot.DataStateAt {
76-
c.snapshotBox.latestSnapshot = snapshot
83+
// defineLatestSnapshot compares two snapshots and defines the latest one.
84+
func defineLatestSnapshot(latest, challenger *models.Snapshot) *models.Snapshot {
85+
if latest == nil || latest.DataStateAt == "" || latest.DataStateAt < challenger.DataStateAt {
86+
return challenger
7787
}
7888

79-
c.snapshotBox.snapshotMutex.Unlock()
89+
return latest
8090
}
8191

8292
// getLatestSnapshot returns the latest snapshot.

Diff for: internal/cloning/snapshots_test.go

+61-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
)
1414

1515
func (s *BaseCloningSuite) TestLatestSnapshot() {
16-
s.cloning.resetSnapshots(make(map[string]*models.Snapshot))
16+
s.cloning.resetSnapshots(make(map[string]*models.Snapshot), nil)
1717

1818
snapshot1 := &models.Snapshot{
1919
ID: "TestSnapshotID1",
@@ -38,10 +38,27 @@ func (s *BaseCloningSuite) TestLatestSnapshot() {
3838
latestSnapshot, err = s.cloning.getLatestSnapshot()
3939
require.NoError(s.T(), err)
4040
require.Equal(s.T(), latestSnapshot, snapshot2)
41+
42+
snapshot3 := &models.Snapshot{
43+
ID: "TestSnapshotID3",
44+
CreatedAt: "2020-02-21 05:43:21",
45+
DataStateAt: "2020-02-21 00:00:00",
46+
}
47+
48+
snapshotMap := make(map[string]*models.Snapshot)
49+
snapshotMap[snapshot1.ID] = snapshot1
50+
snapshotMap[snapshot2.ID] = snapshot2
51+
snapshotMap[snapshot3.ID] = snapshot3
52+
s.cloning.resetSnapshots(snapshotMap, snapshot3)
53+
54+
require.Equal(s.T(), 3, len(s.cloning.snapshotBox.items))
55+
latestSnapshot, err = s.cloning.getLatestSnapshot()
56+
require.NoError(s.T(), err)
57+
require.Equal(s.T(), latestSnapshot, snapshot3)
4158
}
4259

4360
func (s *BaseCloningSuite) TestSnapshotByID() {
44-
s.cloning.resetSnapshots(make(map[string]*models.Snapshot))
61+
s.cloning.resetSnapshots(make(map[string]*models.Snapshot), nil)
4562

4663
snapshot1 := &models.Snapshot{
4764
ID: "TestSnapshotID1",
@@ -72,7 +89,7 @@ func (s *BaseCloningSuite) TestSnapshotByID() {
7289
require.NoError(s.T(), err)
7390
require.Equal(s.T(), latestSnapshot, snapshot2)
7491

75-
s.cloning.resetSnapshots(make(map[string]*models.Snapshot))
92+
s.cloning.resetSnapshots(make(map[string]*models.Snapshot), nil)
7693
require.Equal(s.T(), 0, len(s.cloning.snapshotBox.items))
7794
latestSnapshot, err = s.cloning.getLatestSnapshot()
7895
require.Nil(s.T(), latestSnapshot)
@@ -102,3 +119,44 @@ func TestCloneCounter(t *testing.T) {
102119
require.Nil(t, err)
103120
require.Equal(t, 0, snapshot.NumClones)
104121
}
122+
123+
func TestLatestSnapshots(t *testing.T) {
124+
baseSnapshot := &models.Snapshot{
125+
DataStateAt: "2020-02-19 00:00:00",
126+
}
127+
newSnapshot := &models.Snapshot{
128+
DataStateAt: "2020-02-21 00:00:00",
129+
}
130+
oldSnapshot := &models.Snapshot{
131+
DataStateAt: "2020-02-01 00:00:00",
132+
}
133+
134+
testCases := []struct {
135+
latest, challenger, result *models.Snapshot
136+
}{
137+
{
138+
latest: baseSnapshot,
139+
challenger: newSnapshot,
140+
result: newSnapshot,
141+
},
142+
{
143+
latest: baseSnapshot,
144+
challenger: oldSnapshot,
145+
result: baseSnapshot,
146+
},
147+
{
148+
latest: nil,
149+
challenger: oldSnapshot,
150+
result: oldSnapshot,
151+
},
152+
{
153+
latest: &models.Snapshot{},
154+
challenger: oldSnapshot,
155+
result: oldSnapshot,
156+
},
157+
}
158+
159+
for _, tc := range testCases {
160+
require.Equal(t, tc.result, defineLatestSnapshot(tc.latest, tc.challenger))
161+
}
162+
}

0 commit comments

Comments
 (0)