github.com/sdboyer/gps@v0.16.3/source_cache.go (about) 1 package gps 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/sdboyer/gps/pkgtree" 8 ) 9 10 // singleSourceCache provides a method set for storing and retrieving data about 11 // a single source. 12 type singleSourceCache interface { 13 // Store the manifest and lock information for a given revision, as defined by 14 // a particular ProjectAnalyzer. 15 setManifestAndLock(Revision, ProjectAnalyzer, Manifest, Lock) 16 17 // Get the manifest and lock information for a given revision, as defined by 18 // a particular ProjectAnalyzer. 19 getManifestAndLock(Revision, ProjectAnalyzer) (Manifest, Lock, bool) 20 21 // Store a PackageTree for a given revision. 22 setPackageTree(Revision, pkgtree.PackageTree) 23 24 // Get the PackageTree for a given revision. 25 getPackageTree(Revision) (pkgtree.PackageTree, bool) 26 27 // Indicate to the cache that an individual revision is known to exist. 28 markRevisionExists(r Revision) 29 30 // Store the mappings between a set of PairedVersions' surface versions 31 // their corresponding revisions. 32 // 33 // If flush is true, the existing list of versions will be purged before 34 // writing. Revisions will have their pairings purged, but record of the 35 // revision existing will be kept, on the assumption that revisions are 36 // immutable and permanent. 37 storeVersionMap(versionList []PairedVersion, flush bool) 38 39 // Get the list of unpaired versions corresponding to the given revision. 40 getVersionsFor(Revision) ([]UnpairedVersion, bool) 41 42 // Gets all the version pairs currently known to the cache. 43 getAllVersions() []PairedVersion 44 45 // Get the revision corresponding to the given unpaired version. 46 getRevisionFor(UnpairedVersion) (Revision, bool) 47 48 // Attempt to convert the given Version to a Revision, given information 49 // currently present in the cache, and in the Version itself. 50 toRevision(v Version) (Revision, bool) 51 52 // Attempt to convert the given Version to an UnpairedVersion, given 53 // information currently present in the cache, or in the Version itself. 54 // 55 // If the input is a revision and multiple UnpairedVersions are associated 56 // with it, whatever happens to be the first is returned. 57 toUnpaired(v Version) (UnpairedVersion, bool) 58 } 59 60 type singleSourceCacheMemory struct { 61 mut sync.RWMutex // protects all maps 62 infos map[ProjectAnalyzer]map[Revision]projectInfo 63 ptrees map[Revision]pkgtree.PackageTree 64 vMap map[UnpairedVersion]Revision 65 rMap map[Revision][]UnpairedVersion 66 } 67 68 func newMemoryCache() singleSourceCache { 69 return &singleSourceCacheMemory{ 70 infos: make(map[ProjectAnalyzer]map[Revision]projectInfo), 71 ptrees: make(map[Revision]pkgtree.PackageTree), 72 vMap: make(map[UnpairedVersion]Revision), 73 rMap: make(map[Revision][]UnpairedVersion), 74 } 75 } 76 77 type projectInfo struct { 78 Manifest 79 Lock 80 } 81 82 func (c *singleSourceCacheMemory) setManifestAndLock(r Revision, an ProjectAnalyzer, m Manifest, l Lock) { 83 c.mut.Lock() 84 inner, has := c.infos[an] 85 if !has { 86 inner = make(map[Revision]projectInfo) 87 c.infos[an] = inner 88 } 89 inner[r] = projectInfo{Manifest: m, Lock: l} 90 91 // Ensure there's at least an entry in the rMap so that the rMap always has 92 // a complete picture of the revisions we know to exist 93 if _, has = c.rMap[r]; !has { 94 c.rMap[r] = nil 95 } 96 c.mut.Unlock() 97 } 98 99 func (c *singleSourceCacheMemory) getManifestAndLock(r Revision, an ProjectAnalyzer) (Manifest, Lock, bool) { 100 c.mut.Lock() 101 defer c.mut.Unlock() 102 103 inner, has := c.infos[an] 104 if !has { 105 return nil, nil, false 106 } 107 108 pi, has := inner[r] 109 if has { 110 return pi.Manifest, pi.Lock, true 111 } 112 return nil, nil, false 113 } 114 115 func (c *singleSourceCacheMemory) setPackageTree(r Revision, ptree pkgtree.PackageTree) { 116 c.mut.Lock() 117 c.ptrees[r] = ptree 118 119 // Ensure there's at least an entry in the rMap so that the rMap always has 120 // a complete picture of the revisions we know to exist 121 if _, has := c.rMap[r]; !has { 122 c.rMap[r] = nil 123 } 124 c.mut.Unlock() 125 } 126 127 func (c *singleSourceCacheMemory) getPackageTree(r Revision) (pkgtree.PackageTree, bool) { 128 c.mut.Lock() 129 ptree, has := c.ptrees[r] 130 c.mut.Unlock() 131 return ptree, has 132 } 133 134 func (c *singleSourceCacheMemory) storeVersionMap(versionList []PairedVersion, flush bool) { 135 c.mut.Lock() 136 if flush { 137 // TODO(sdboyer) how do we handle cache consistency here - revs that may 138 // be out of date vis-a-vis the ptrees or infos maps? 139 for r := range c.rMap { 140 c.rMap[r] = nil 141 } 142 143 c.vMap = make(map[UnpairedVersion]Revision) 144 } 145 146 for _, v := range versionList { 147 pv := v.(PairedVersion) 148 u, r := pv.Unpair(), pv.Underlying() 149 c.vMap[u] = r 150 c.rMap[r] = append(c.rMap[r], u) 151 } 152 c.mut.Unlock() 153 } 154 155 func (c *singleSourceCacheMemory) markRevisionExists(r Revision) { 156 c.mut.Lock() 157 if _, has := c.rMap[r]; !has { 158 c.rMap[r] = nil 159 } 160 c.mut.Unlock() 161 } 162 163 func (c *singleSourceCacheMemory) getVersionsFor(r Revision) ([]UnpairedVersion, bool) { 164 c.mut.Lock() 165 versionList, has := c.rMap[r] 166 c.mut.Unlock() 167 return versionList, has 168 } 169 170 func (c *singleSourceCacheMemory) getAllVersions() []PairedVersion { 171 vlist := make([]PairedVersion, 0, len(c.vMap)) 172 for v, r := range c.vMap { 173 vlist = append(vlist, v.Is(r)) 174 } 175 return vlist 176 } 177 178 func (c *singleSourceCacheMemory) getRevisionFor(uv UnpairedVersion) (Revision, bool) { 179 c.mut.Lock() 180 r, has := c.vMap[uv] 181 c.mut.Unlock() 182 return r, has 183 } 184 185 func (c *singleSourceCacheMemory) toRevision(v Version) (Revision, bool) { 186 switch t := v.(type) { 187 case Revision: 188 return t, true 189 case PairedVersion: 190 return t.Underlying(), true 191 case UnpairedVersion: 192 c.mut.Lock() 193 r, has := c.vMap[t] 194 c.mut.Unlock() 195 return r, has 196 default: 197 panic(fmt.Sprintf("Unknown version type %T", v)) 198 } 199 } 200 201 func (c *singleSourceCacheMemory) toUnpaired(v Version) (UnpairedVersion, bool) { 202 switch t := v.(type) { 203 case UnpairedVersion: 204 return t, true 205 case PairedVersion: 206 return t.Unpair(), true 207 case Revision: 208 c.mut.Lock() 209 upv, has := c.rMap[t] 210 c.mut.Unlock() 211 212 if has && len(upv) > 0 { 213 return upv[0], true 214 } 215 return nil, false 216 default: 217 panic(fmt.Sprintf("unknown version type %T", v)) 218 } 219 }