Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

Commit 1d632a4

Browse files
committed
gps: source cache: drop timestamps from immutable cache values
1 parent 235cdec commit 1d632a4

File tree

2 files changed

+92
-34
lines changed

2 files changed

+92
-34
lines changed

internal/gps/source_cache_bolt.go

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
)
2020

2121
// singleSourceCacheBolt implements a singleSourceCache backed by a persistent BoltDB file.
22-
// Stored values are timestamped, and the `epoch` field limits the age of returned values.
22+
// Version mappings are timestamped, and the `epoch` field limits the age of returned values.
2323
// Database access methods are safe for concurrent use with each other (excluding close).
2424
//
2525
// Implementation:
@@ -37,15 +37,14 @@ import (
3737
//
3838
// Bucket: "rev:<revision>"
3939
//
40-
// a) Manifest and Lock info are stored in a bucket derived from ProjectAnalyzer.Info:
40+
// a) Manifest and Lock info are stored in buckets derived from ProjectAnalyzer.Info:
4141
//
42-
// Sub-Bucket: "info:<name>.<version>:<timestamp>"
43-
// Sub-Bucket: "manifest", "lock"
42+
// Sub-Bucket: "info:<name>.<version>:manifest", "info:<name>.<version>:lock"
4443
// Keys/Values: Manifest or Lock fields
4544
//
4645
// b) Package tree buckets contain package import path keys and package-or-error buckets:
4746
//
48-
// Sub-Bucket: "ptree:<timestamp>"
47+
// Sub-Bucket: "ptree"
4948
// Sub-Bucket: "<import_path>"
5049
// Key/Values: PackageOrErr fields
5150
//
@@ -94,17 +93,20 @@ func (s *singleSourceCacheBolt) close() error {
9493

9594
func (s *singleSourceCacheBolt) setManifestAndLock(rev Revision, ai ProjectAnalyzerInfo, m Manifest, l Lock) {
9695
err := s.updateRevBucket(rev, func(b *bolt.Bucket) error {
97-
pre := "info:" + ai.String() + ":"
98-
if err := cachePrefixDelete(b, pre); err != nil {
99-
return err
96+
mName, lName := cacheInfoNames(ai)
97+
if b.Bucket(mName) != nil {
98+
if err := b.DeleteBucket(mName); err != nil {
99+
return err
100+
}
100101
}
101-
info, err := b.CreateBucket(cacheTimestampedKey(pre, time.Now()))
102-
if err != nil {
103-
return err
102+
if b.Bucket(lName) != nil {
103+
if err := b.DeleteBucket(lName); err != nil {
104+
return err
105+
}
104106
}
105107

106108
// Manifest
107-
mb, err := info.CreateBucket([]byte("manifest"))
109+
mb, err := b.CreateBucket(mName)
108110
if err != nil {
109111
return err
110112
}
@@ -116,7 +118,7 @@ func (s *singleSourceCacheBolt) setManifestAndLock(rev Revision, ai ProjectAnaly
116118
}
117119

118120
// Lock
119-
lb, err := info.CreateBucket([]byte("lock"))
121+
lb, err := b.CreateBucket(lName)
120122
if err != nil {
121123
return err
122124
}
@@ -127,15 +129,37 @@ func (s *singleSourceCacheBolt) setManifestAndLock(rev Revision, ai ProjectAnaly
127129
}
128130
}
129131

132+
// cache info bucket prefixes and suffixes.
133+
var (
134+
cacheInfo = []byte("info:")
135+
cacheManifest = []byte(":manifest")
136+
cacheLock = []byte(":lock")
137+
)
138+
139+
// cacheInfoNames returns the manifest and lock bucket names for ai.
140+
func cacheInfoNames(ai ProjectAnalyzerInfo) (manifest, lock []byte) {
141+
info := ai.String()
142+
l := len(cacheInfo) + len(info)
143+
manifest = make([]byte, l+len(cacheManifest))
144+
lock = make([]byte, l+len(cacheLock))
145+
146+
copy(manifest, cacheInfo)
147+
copy(manifest[len(cacheInfo):], info)
148+
copy(manifest[l:], cacheManifest)
149+
150+
copy(lock, cacheInfo)
151+
copy(lock[len(cacheInfo):], info)
152+
copy(lock[l:], cacheLock)
153+
154+
return
155+
}
156+
130157
func (s *singleSourceCacheBolt) getManifestAndLock(rev Revision, ai ProjectAnalyzerInfo) (m Manifest, l Lock, ok bool) {
131158
err := s.viewRevBucket(rev, func(b *bolt.Bucket) error {
132-
info := cacheFindLatestValid(b, "info:"+ai.String()+":", s.epoch)
133-
if info == nil {
134-
return nil
135-
}
159+
mName, lName := cacheInfoNames(ai)
136160

137161
// Manifest
138-
mb := info.Bucket([]byte("manifest"))
162+
mb := b.Bucket(mName)
139163
if mb == nil {
140164
return nil
141165
}
@@ -146,7 +170,7 @@ func (s *singleSourceCacheBolt) getManifestAndLock(rev Revision, ai ProjectAnaly
146170
}
147171

148172
// Lock
149-
lb := info.Bucket([]byte("lock"))
173+
lb := b.Bucket(lName)
150174
if lb == nil {
151175
ok = true
152176
return nil
@@ -165,12 +189,16 @@ func (s *singleSourceCacheBolt) getManifestAndLock(rev Revision, ai ProjectAnaly
165189
return
166190
}
167191

192+
var cachePTree = []byte("ptree")
193+
168194
func (s *singleSourceCacheBolt) setPackageTree(rev Revision, ptree pkgtree.PackageTree) {
169195
err := s.updateRevBucket(rev, func(b *bolt.Bucket) error {
170-
if err := cachePrefixDelete(b, "ptree:"); err != nil {
171-
return err
196+
if b.Bucket(cachePTree) != nil {
197+
if err := b.DeleteBucket(cachePTree); err != nil {
198+
return err
199+
}
172200
}
173-
ptrees, err := b.CreateBucket(cacheTimestampedKey("ptree:", time.Now()))
201+
ptrees, err := b.CreateBucket(cachePTree)
174202
if err != nil {
175203
return err
176204
}
@@ -194,7 +222,7 @@ func (s *singleSourceCacheBolt) setPackageTree(rev Revision, ptree pkgtree.Packa
194222

195223
func (s *singleSourceCacheBolt) getPackageTree(rev Revision) (ptree pkgtree.PackageTree, ok bool) {
196224
err := s.viewRevBucket(rev, func(b *bolt.Bucket) error {
197-
ptrees := cacheFindLatestValid(b, "ptree:", s.epoch)
225+
ptrees := b.Bucket(cachePTree)
198226
if ptrees == nil {
199227
return nil
200228
}

internal/gps/source_cache_bolt_test.go

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,13 @@ func TestBoltCacheTimeout(t *testing.T) {
9595
NewVersion("originalver").Pair("rev2"),
9696
}
9797

98-
// Write values timestamped > start.
98+
// Write values timestamped > `start`.
9999
{
100100
c.setManifestAndLock(rev, ai, manifest, lock)
101101
c.setPackageTree(rev, ptree)
102102
c.setVersionMap(pvs)
103103
}
104-
// Read back values timestamped > start.
104+
// Read back values timestamped > `start`.
105105
{
106106
gotM, gotL, ok := c.getManifestAndLock(rev, ai)
107107
if !ok {
@@ -136,7 +136,7 @@ func TestBoltCacheTimeout(t *testing.T) {
136136
t.Fatal("failed to close cache:", err)
137137
}
138138

139-
// Read with a later epoch. Expect no values, since all timestamped < after.
139+
// Read with a later epoch. Expect no *timestamped* values, since all were < `after`.
140140
{
141141
after := time.Now()
142142
if after.Unix() <= start.Unix() {
@@ -148,15 +148,20 @@ func TestBoltCacheTimeout(t *testing.T) {
148148
t.Fatal(err)
149149
}
150150

151-
m, l, ok := c.getManifestAndLock(rev, ai)
152-
if ok {
153-
t.Errorf("expected no cached info, but got:\n\tManifest: %#v\n\tLock: %#v\n", m, l)
151+
gotM, gotL, ok := c.getManifestAndLock(rev, ai)
152+
if !ok {
153+
t.Error("no manifest and lock found for revision")
154+
}
155+
compareManifests(t, manifest, gotM)
156+
if dl := DiffLocks(lock, gotL); dl != nil {
157+
t.Errorf("lock differences:\n\t %#v", dl)
154158
}
155159

156-
ptree, ok := c.getPackageTree(rev)
157-
if ok {
158-
t.Errorf("expected no cached package tree, but got:\n\t%#v", ptree)
160+
gotPtree, ok := c.getPackageTree(rev)
161+
if !ok {
162+
t.Errorf("no package tree found:\n\t(WNT): %#v", ptree)
159163
}
164+
comparePackageTree(t, ptree, gotPtree)
160165

161166
pvs := c.getAllVersions()
162167
if len(pvs) > 0 {
@@ -173,7 +178,7 @@ func TestBoltCacheTimeout(t *testing.T) {
173178
if err != nil {
174179
t.Fatal(err)
175180
}
176-
// Read values timestamped > start.
181+
// Read values timestamped > `start`.
177182
{
178183
gotM, gotL, ok := c.getManifestAndLock(rev, ai)
179184
if !ok {
@@ -255,7 +260,7 @@ func TestBoltCacheTimeout(t *testing.T) {
255260
NewBranch("newbranch").Pair("revA"),
256261
NewVersion("newver").Pair("revB"),
257262
}
258-
// Overwrite with new values with newer timestamps.
263+
// Overwrite with new values, and with timestamps > `after`.
259264
{
260265
c.setManifestAndLock(rev, ai, newManifest, newLock)
261266
c.setPackageTree(rev, newPtree)
@@ -292,3 +297,28 @@ func TestBoltCacheTimeout(t *testing.T) {
292297
}
293298
}
294299
}
300+
301+
func TestBoltCacheRevisionName(t *testing.T) {
302+
const (
303+
rev = Revision("test")
304+
want = "rev:test"
305+
)
306+
if got := string(cacheRevisionName(rev)); got != want {
307+
t.Errorf("unexpected cache revision name: (GOT):%q (WNT):%q", got, want)
308+
}
309+
}
310+
311+
func TestBoltCacheInfoName(t *testing.T) {
312+
ai := ProjectAnalyzerInfo{
313+
Name: "name",
314+
Version: 42,
315+
}
316+
const (
317+
wantM = "info:name.42:manifest"
318+
wantL = "info:name.42:lock"
319+
)
320+
gotM, gotL := cacheInfoNames(ai)
321+
if string(gotM) != wantM || string(gotL) != wantL {
322+
t.Errorf("unexpected info revision names: (GOT):%q,%q (WNT):%q,%q", gotM, gotL, wantM, wantL)
323+
}
324+
}

0 commit comments

Comments
 (0)