github.com/golang/dep@v0.5.4/gps/source_cache_multi.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gps 6 7 import ( 8 "github.com/golang/dep/gps/pkgtree" 9 ) 10 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. 58 // 59 // The in-memory cache is always checked first, with the on-disk used as a fallback. 60 // Values read from disk are set in-memory when an appropriate method exists. 61 // 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 { 66 mem, disk singleSourceCache 67 // Asynchronous disk cache updates. 68 async chan<- func() 69 } 70 71 func (c *singleSourceMultiCache) setManifestAndLock(r Revision, ai ProjectAnalyzerInfo, m Manifest, l Lock) { 72 c.mem.setManifestAndLock(r, ai, m, l) 73 c.async <- func() { c.disk.setManifestAndLock(r, ai, m, l) } 74 } 75 76 func (c *singleSourceMultiCache) getManifestAndLock(r Revision, ai ProjectAnalyzerInfo) (Manifest, Lock, bool) { 77 m, l, ok := c.mem.getManifestAndLock(r, ai) 78 if ok { 79 return m, l, true 80 } 81 82 m, l, ok = c.disk.getManifestAndLock(r, ai) 83 if ok { 84 c.mem.setManifestAndLock(r, ai, m, l) 85 return m, l, true 86 } 87 88 return nil, nil, false 89 } 90 91 func (c *singleSourceMultiCache) setPackageTree(r Revision, ptree pkgtree.PackageTree) { 92 c.mem.setPackageTree(r, ptree) 93 c.async <- func() { c.disk.setPackageTree(r, ptree) } 94 } 95 96 func (c *singleSourceMultiCache) getPackageTree(r Revision, pr ProjectRoot) (pkgtree.PackageTree, bool) { 97 ptree, ok := c.mem.getPackageTree(r, pr) 98 if ok { 99 return ptree, true 100 } 101 102 ptree, ok = c.disk.getPackageTree(r, pr) 103 if ok { 104 c.mem.setPackageTree(r, ptree) 105 return ptree, true 106 } 107 108 return pkgtree.PackageTree{}, false 109 } 110 111 func (c *singleSourceMultiCache) markRevisionExists(r Revision) { 112 c.mem.markRevisionExists(r) 113 c.async <- func() { c.disk.markRevisionExists(r) } 114 } 115 116 func (c *singleSourceMultiCache) setVersionMap(pvs []PairedVersion) { 117 c.mem.setVersionMap(pvs) 118 c.async <- func() { c.disk.setVersionMap(pvs) } 119 } 120 121 func (c *singleSourceMultiCache) getVersionsFor(rev Revision) ([]UnpairedVersion, bool) { 122 uvs, ok := c.mem.getVersionsFor(rev) 123 if ok { 124 return uvs, true 125 } 126 127 return c.disk.getVersionsFor(rev) 128 } 129 130 func (c *singleSourceMultiCache) getAllVersions() ([]PairedVersion, bool) { 131 pvs, ok := c.mem.getAllVersions() 132 if ok { 133 return pvs, true 134 } 135 136 pvs, ok = c.disk.getAllVersions() 137 if ok { 138 c.mem.setVersionMap(pvs) 139 return pvs, true 140 } 141 142 return nil, false 143 } 144 145 func (c *singleSourceMultiCache) getRevisionFor(uv UnpairedVersion) (Revision, bool) { 146 rev, ok := c.mem.getRevisionFor(uv) 147 if ok { 148 return rev, true 149 } 150 151 return c.disk.getRevisionFor(uv) 152 } 153 154 func (c *singleSourceMultiCache) toRevision(v Version) (Revision, bool) { 155 rev, ok := c.mem.toRevision(v) 156 if ok { 157 return rev, true 158 } 159 160 return c.disk.toRevision(v) 161 } 162 163 func (c *singleSourceMultiCache) toUnpaired(v Version) (UnpairedVersion, bool) { 164 uv, ok := c.mem.toUnpaired(v) 165 if ok { 166 return uv, true 167 } 168 169 return c.disk.toUnpaired(v) 170 }