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  }