diff options
author | Ben Burwell <ben@benburwell.com> | 2020-06-06 22:13:59 -0400 |
---|---|---|
committer | Ben Burwell <ben@benburwell.com> | 2020-06-06 22:13:59 -0400 |
commit | 38db545ba808c69dd911a6bf45c2a340d3ae3487 (patch) | |
tree | 4c4bf2b2c15c48736c245a371cf75f0abe7e0b20 /cache.go | |
parent | b242fa87a86ee27ed0fccf925d49e13b9fe607ef (diff) |
Diffstat (limited to 'cache.go')
-rw-r--r-- | cache.go | 129 |
1 files changed, 0 insertions, 129 deletions
diff --git a/cache.go b/cache.go deleted file mode 100644 index d43fa77..0000000 --- a/cache.go +++ /dev/null @@ -1,129 +0,0 @@ -package main - -import ( - "context" - "log" - "path" - "sync" - "time" -) - -// A PackageCache holds information about Go packages and their upstream -// repositories. -// -// Given a package name, it looks for a similarly named repository in one of -// the upstream hosts and holds on to the result for quicker subsequent access. -type PackageCache struct { - // ExpireAfter is how long to consider a found repository valid for. As - // repositories do not frequently move around, this could be rather long, - // though it also determines how long a user might have to wait for a new - // repository to become available if they previously got a 404. - ExpireAfter time.Duration - - // UpstreamTimeout is how long we should allow HTTP requests to upstream - // hosts to carry on before they are canceled. - UpstreamTimeout time.Duration - - // Hosts are the RepoHosts which should be checked for a repository matching - // the package name. Hosts are checked in order; if two hosts both have a - // repo with the desired name, the repo host which is listed first will - // "win". - Hosts []RepoHost - - // Logger is a logger for diagnostics - Logger *log.Logger - - // CanonicalPrefix is the package prefix to use when naming packages. E.g., - // when looking for a package named "conf", we'll treat the package name as - // CanonicalPrefix + "/conf", e.g. burwell.io/conf. - CanonicalPrefix string - - entries sync.Map // concurrency-safe map[string]entry -} - -type entry struct { - t time.Time - pkg *Package -} - -// A Package represents a Go package's canonical name and its source git -// repository. -type Package struct { - Name string - Repo string -} - -// Get loads package name from the cache, consulting upstream repositories to -// find a matching repo if not present. As this method is meant to be called in -// the critical path of an incoming HTTP request, it can also be cancelled with -// the supplied context. -func (c *PackageCache) Get(ctx context.Context, name string) (Package, bool) { - val, ok := c.entries.Load(name) - if !ok { - return c.load(ctx, name) - } - ent := val.(entry) - - if time.Now().After(ent.t.Add(c.ExpireAfter)) { - return c.load(ctx, name) - } - - if ent.pkg == nil { - return Package{}, false - } - - return *ent.pkg, true -} - -// load looks for a package in the upstream repos, and if found, stores it in -// the cache. If no matching repo is found, a nil entry is stored in the map so -// we don't immediately re-check the upstreams for subsequent requests. -func (c *PackageCache) load(ctx context.Context, name string) (Package, bool) { - pkg, ok := c.find(ctx, name) - if !ok { - c.entries.Store(name, entry{t: time.Now()}) - return Package{}, false - } - c.entries.Store(name, entry{t: time.Now(), pkg: &pkg}) - return pkg, true -} - -// requestContext creates a context for making HTTP requests to upstream hosts. -func (c *PackageCache) requestContext(ctx context.Context) (context.Context, context.CancelFunc) { - if c.UpstreamTimeout == 0 { - return ctx, func() {} - } - return context.WithTimeout(ctx, c.UpstreamTimeout) -} - -// logf logs a message using the configured logger, if any. -func (c *PackageCache) logf(msg string, args ...interface{}) { - if c.Logger == nil { - return - } - c.Logger.Printf(msg, args...) -} - -// find consults the configured upstream hosts to try to find a matching repo -// for package name. -func (c *PackageCache) find(ctx context.Context, name string) (Package, bool) { - c.logf("loading %s", name) - for _, h := range c.Hosts { - reqCtx, cancel := c.requestContext(ctx) - defer cancel() - repo, ok, err := h.HostsRepo(reqCtx, name) - if err != nil { - c.logf("error checking upstream for repo %s: %v", name, err) - return Package{}, false - } - if ok { - c.logf("found repo %s: %s", name, repo) - return Package{ - Name: path.Join(c.CanonicalPrefix, name), - Repo: repo, - }, true - } - } - c.logf("could not find repo %s on any host", name) - return Package{}, false -} |