@@ -8,22 +8,72 @@ import (
8
8
"github.com/golang/dep/gps/pkgtree"
9
9
)
10
10
11
- // A multiCache manages two cache levels, ephemeral in-memory and persistent on-disk.
11
+ // multiCache creates singleSourceMultiCaches, and coordinates their async updates.
12
+ type multiCache struct {
13
+ mem , disk sourceCache
14
+ // Asynchronous disk cache updates. Closed by the close method.
15
+ async chan func ()
16
+ // Closed when async has completed processing.
17
+ done chan struct {}
18
+ }
19
+
20
+ // newMultiCache returns a new multiCache backed by mem and disk sourceCaches.
21
+ // Spawns a single background goroutine which lives until close() is called.
22
+ func newMultiCache (mem , disk sourceCache ) * multiCache {
23
+ m := & multiCache {
24
+ mem : mem ,
25
+ disk : disk ,
26
+ async : make (chan func (), 50 ),
27
+ done : make (chan struct {}),
28
+ }
29
+ go m .processAsync ()
30
+ return m
31
+ }
32
+
33
+ func (c * multiCache ) processAsync () {
34
+ for f := range c .async {
35
+ f ()
36
+ }
37
+ close (c .done )
38
+ }
39
+
40
+ // close releases resources after blocking until async writes complete.
41
+ func (c * multiCache ) close () error {
42
+ close (c .async )
43
+ _ = c .mem .close ()
44
+ <- c .done
45
+ return c .disk .close ()
46
+ }
47
+
48
+ // newSingleSourceCache returns a singleSourceMultiCache for id.
49
+ func (c * multiCache ) newSingleSourceCache (id ProjectIdentifier ) singleSourceCache {
50
+ return & singleSourceMultiCache {
51
+ mem : c .mem .newSingleSourceCache (id ),
52
+ disk : c .disk .newSingleSourceCache (id ),
53
+ async : c .async ,
54
+ }
55
+ }
56
+
57
+ // singleSourceMultiCache manages two cache levels, ephemeral in-memory and persistent on-disk.
12
58
//
13
59
// The in-memory cache is always checked first, with the on-disk used as a fallback.
14
60
// Values read from disk are set in-memory when an appropriate method exists.
15
61
//
16
- // Set values are cached both in-memory and on-disk.
17
- type multiCache struct {
62
+ // Set values are cached both in-memory and on-disk. Values are set synchronously
63
+ // in-memory. Writes to the on-disk cache are asynchronous, and executed in order by a
64
+ // background goroutine.
65
+ type singleSourceMultiCache struct {
18
66
mem , disk singleSourceCache
67
+ // Asynchronous disk cache updates.
68
+ async chan <- func ()
19
69
}
20
70
21
- func (c * multiCache ) setManifestAndLock (r Revision , ai ProjectAnalyzerInfo , m Manifest , l Lock ) {
71
+ func (c * singleSourceMultiCache ) setManifestAndLock (r Revision , ai ProjectAnalyzerInfo , m Manifest , l Lock ) {
22
72
c .mem .setManifestAndLock (r , ai , m , l )
23
- c .disk .setManifestAndLock (r , ai , m , l )
73
+ c .async <- func () { c . disk .setManifestAndLock (r , ai , m , l ) }
24
74
}
25
75
26
- func (c * multiCache ) getManifestAndLock (r Revision , ai ProjectAnalyzerInfo ) (Manifest , Lock , bool ) {
76
+ func (c * singleSourceMultiCache ) getManifestAndLock (r Revision , ai ProjectAnalyzerInfo ) (Manifest , Lock , bool ) {
27
77
m , l , ok := c .mem .getManifestAndLock (r , ai )
28
78
if ok {
29
79
return m , l , true
@@ -38,12 +88,12 @@ func (c *multiCache) getManifestAndLock(r Revision, ai ProjectAnalyzerInfo) (Man
38
88
return nil , nil , false
39
89
}
40
90
41
- func (c * multiCache ) setPackageTree (r Revision , ptree pkgtree.PackageTree ) {
91
+ func (c * singleSourceMultiCache ) setPackageTree (r Revision , ptree pkgtree.PackageTree ) {
42
92
c .mem .setPackageTree (r , ptree )
43
- c .disk .setPackageTree (r , ptree )
93
+ c .async <- func () { c . disk .setPackageTree (r , ptree ) }
44
94
}
45
95
46
- func (c * multiCache ) getPackageTree (r Revision , pr ProjectRoot ) (pkgtree.PackageTree , bool ) {
96
+ func (c * singleSourceMultiCache ) getPackageTree (r Revision , pr ProjectRoot ) (pkgtree.PackageTree , bool ) {
47
97
ptree , ok := c .mem .getPackageTree (r , pr )
48
98
if ok {
49
99
return ptree , true
@@ -58,17 +108,17 @@ func (c *multiCache) getPackageTree(r Revision, pr ProjectRoot) (pkgtree.Package
58
108
return pkgtree.PackageTree {}, false
59
109
}
60
110
61
- func (c * multiCache ) markRevisionExists (r Revision ) {
111
+ func (c * singleSourceMultiCache ) markRevisionExists (r Revision ) {
62
112
c .mem .markRevisionExists (r )
63
- c .disk .markRevisionExists (r )
113
+ c .async <- func () { c . disk .markRevisionExists (r ) }
64
114
}
65
115
66
- func (c * multiCache ) setVersionMap (pvs []PairedVersion ) {
116
+ func (c * singleSourceMultiCache ) setVersionMap (pvs []PairedVersion ) {
67
117
c .mem .setVersionMap (pvs )
68
- c .disk .setVersionMap (pvs )
118
+ c .async <- func () { c . disk .setVersionMap (pvs ) }
69
119
}
70
120
71
- func (c * multiCache ) getVersionsFor (rev Revision ) ([]UnpairedVersion , bool ) {
121
+ func (c * singleSourceMultiCache ) getVersionsFor (rev Revision ) ([]UnpairedVersion , bool ) {
72
122
uvs , ok := c .mem .getVersionsFor (rev )
73
123
if ok {
74
124
return uvs , true
@@ -77,7 +127,7 @@ func (c *multiCache) getVersionsFor(rev Revision) ([]UnpairedVersion, bool) {
77
127
return c .disk .getVersionsFor (rev )
78
128
}
79
129
80
- func (c * multiCache ) getAllVersions () ([]PairedVersion , bool ) {
130
+ func (c * singleSourceMultiCache ) getAllVersions () ([]PairedVersion , bool ) {
81
131
pvs , ok := c .mem .getAllVersions ()
82
132
if ok {
83
133
return pvs , true
@@ -92,7 +142,7 @@ func (c *multiCache) getAllVersions() ([]PairedVersion, bool) {
92
142
return nil , false
93
143
}
94
144
95
- func (c * multiCache ) getRevisionFor (uv UnpairedVersion ) (Revision , bool ) {
145
+ func (c * singleSourceMultiCache ) getRevisionFor (uv UnpairedVersion ) (Revision , bool ) {
96
146
rev , ok := c .mem .getRevisionFor (uv )
97
147
if ok {
98
148
return rev , true
@@ -101,7 +151,7 @@ func (c *multiCache) getRevisionFor(uv UnpairedVersion) (Revision, bool) {
101
151
return c .disk .getRevisionFor (uv )
102
152
}
103
153
104
- func (c * multiCache ) toRevision (v Version ) (Revision , bool ) {
154
+ func (c * singleSourceMultiCache ) toRevision (v Version ) (Revision , bool ) {
105
155
rev , ok := c .mem .toRevision (v )
106
156
if ok {
107
157
return rev , true
@@ -110,7 +160,7 @@ func (c *multiCache) toRevision(v Version) (Revision, bool) {
110
160
return c .disk .toRevision (v )
111
161
}
112
162
113
- func (c * multiCache ) toUnpaired (v Version ) (UnpairedVersion , bool ) {
163
+ func (c * singleSourceMultiCache ) toUnpaired (v Version ) (UnpairedVersion , bool ) {
114
164
uv , ok := c .mem .toUnpaired (v )
115
165
if ok {
116
166
return uv , true
0 commit comments