.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / internal / cache / cache.go
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 cache implements a build artifact cache.
6 //
7 // This package is a slightly modified fork of Go's
8 // cmd/go/internal/cache package.
9 package cache
10
11 import (
12         "bytes"
13         "crypto/sha256"
14         "encoding/hex"
15         "errors"
16         "fmt"
17         "io"
18         "io/ioutil"
19         "os"
20         "path/filepath"
21         "strconv"
22         "strings"
23         "time"
24
25         "honnef.co/go/tools/internal/renameio"
26 )
27
28 // An ActionID is a cache action key, the hash of a complete description of a
29 // repeatable computation (command line, environment variables,
30 // input file contents, executable contents).
31 type ActionID [HashSize]byte
32
33 // An OutputID is a cache output key, the hash of an output of a computation.
34 type OutputID [HashSize]byte
35
36 // A Cache is a package cache, backed by a file system directory tree.
37 type Cache struct {
38         dir string
39         now func() time.Time
40 }
41
42 // Open opens and returns the cache in the given directory.
43 //
44 // It is safe for multiple processes on a single machine to use the
45 // same cache directory in a local file system simultaneously.
46 // They will coordinate using operating system file locks and may
47 // duplicate effort but will not corrupt the cache.
48 //
49 // However, it is NOT safe for multiple processes on different machines
50 // to share a cache directory (for example, if the directory were stored
51 // in a network file system). File locking is notoriously unreliable in
52 // network file systems and may not suffice to protect the cache.
53 //
54 func Open(dir string) (*Cache, error) {
55         info, err := os.Stat(dir)
56         if err != nil {
57                 return nil, err
58         }
59         if !info.IsDir() {
60                 return nil, &os.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")}
61         }
62         for i := 0; i < 256; i++ {
63                 name := filepath.Join(dir, fmt.Sprintf("%02x", i))
64                 if err := os.MkdirAll(name, 0777); err != nil {
65                         return nil, err
66                 }
67         }
68         c := &Cache{
69                 dir: dir,
70                 now: time.Now,
71         }
72         return c, nil
73 }
74
75 // fileName returns the name of the file corresponding to the given id.
76 func (c *Cache) fileName(id [HashSize]byte, key string) string {
77         return filepath.Join(c.dir, fmt.Sprintf("%02x", id[0]), fmt.Sprintf("%x", id)+"-"+key)
78 }
79
80 // An entryNotFoundError indicates that a cache entry was not found, with an
81 // optional underlying reason.
82 type entryNotFoundError struct {
83         Err error
84 }
85
86 func (e *entryNotFoundError) Error() string {
87         if e.Err == nil {
88                 return "cache entry not found"
89         }
90         return fmt.Sprintf("cache entry not found: %v", e.Err)
91 }
92
93 func (e *entryNotFoundError) Unwrap() error {
94         return e.Err
95 }
96
97 const (
98         // action entry file is "v1 <hex id> <hex out> <decimal size space-padded to 20 bytes> <unixnano space-padded to 20 bytes>\n"
99         hexSize   = HashSize * 2
100         entrySize = 2 + 1 + hexSize + 1 + hexSize + 1 + 20 + 1 + 20 + 1
101 )
102
103 // verify controls whether to run the cache in verify mode.
104 // In verify mode, the cache always returns errMissing from Get
105 // but then double-checks in Put that the data being written
106 // exactly matches any existing entry. This provides an easy
107 // way to detect program behavior that would have been different
108 // had the cache entry been returned from Get.
109 //
110 // verify is enabled by setting the environment variable
111 // GODEBUG=gocacheverify=1.
112 var verify = false
113
114 var errVerifyMode = errors.New("gocacheverify=1")
115
116 // DebugTest is set when GODEBUG=gocachetest=1 is in the environment.
117 var DebugTest = false
118
119 func init() { initEnv() }
120
121 func initEnv() {
122         verify = false
123         debugHash = false
124         debug := strings.Split(os.Getenv("GODEBUG"), ",")
125         for _, f := range debug {
126                 if f == "gocacheverify=1" {
127                         verify = true
128                 }
129                 if f == "gocachehash=1" {
130                         debugHash = true
131                 }
132                 if f == "gocachetest=1" {
133                         DebugTest = true
134                 }
135         }
136 }
137
138 // Get looks up the action ID in the cache,
139 // returning the corresponding output ID and file size, if any.
140 // Note that finding an output ID does not guarantee that the
141 // saved file for that output ID is still available.
142 func (c *Cache) Get(id ActionID) (Entry, error) {
143         if verify {
144                 return Entry{}, &entryNotFoundError{Err: errVerifyMode}
145         }
146         return c.get(id)
147 }
148
149 type Entry struct {
150         OutputID OutputID
151         Size     int64
152         Time     time.Time
153 }
154
155 // get is Get but does not respect verify mode, so that Put can use it.
156 func (c *Cache) get(id ActionID) (Entry, error) {
157         missing := func(reason error) (Entry, error) {
158                 return Entry{}, &entryNotFoundError{Err: reason}
159         }
160         f, err := os.Open(c.fileName(id, "a"))
161         if err != nil {
162                 return missing(err)
163         }
164         defer f.Close()
165         entry := make([]byte, entrySize+1) // +1 to detect whether f is too long
166         if n, err := io.ReadFull(f, entry); n > entrySize {
167                 return missing(errors.New("too long"))
168         } else if err != io.ErrUnexpectedEOF {
169                 if err == io.EOF {
170                         return missing(errors.New("file is empty"))
171                 }
172                 return missing(err)
173         } else if n < entrySize {
174                 return missing(errors.New("entry file incomplete"))
175         }
176         if entry[0] != 'v' || entry[1] != '1' || entry[2] != ' ' || entry[3+hexSize] != ' ' || entry[3+hexSize+1+hexSize] != ' ' || entry[3+hexSize+1+hexSize+1+20] != ' ' || entry[entrySize-1] != '\n' {
177                 return missing(errors.New("invalid header"))
178         }
179         eid, entry := entry[3:3+hexSize], entry[3+hexSize:]
180         eout, entry := entry[1:1+hexSize], entry[1+hexSize:]
181         esize, entry := entry[1:1+20], entry[1+20:]
182         //lint:ignore SA4006 See https://github.com/dominikh/go-tools/issues/465
183         etime, entry := entry[1:1+20], entry[1+20:]
184         var buf [HashSize]byte
185         if _, err := hex.Decode(buf[:], eid); err != nil {
186                 return missing(fmt.Errorf("decoding ID: %v", err))
187         } else if buf != id {
188                 return missing(errors.New("mismatched ID"))
189         }
190         if _, err := hex.Decode(buf[:], eout); err != nil {
191                 return missing(fmt.Errorf("decoding output ID: %v", err))
192         }
193         i := 0
194         for i < len(esize) && esize[i] == ' ' {
195                 i++
196         }
197         size, err := strconv.ParseInt(string(esize[i:]), 10, 64)
198         if err != nil {
199                 return missing(fmt.Errorf("parsing size: %v", err))
200         } else if size < 0 {
201                 return missing(errors.New("negative size"))
202         }
203         i = 0
204         for i < len(etime) && etime[i] == ' ' {
205                 i++
206         }
207         tm, err := strconv.ParseInt(string(etime[i:]), 10, 64)
208         if err != nil {
209                 return missing(fmt.Errorf("parsing timestamp: %v", err))
210         } else if tm < 0 {
211                 return missing(errors.New("negative timestamp"))
212         }
213
214         c.used(c.fileName(id, "a"))
215
216         return Entry{buf, size, time.Unix(0, tm)}, nil
217 }
218
219 // GetFile looks up the action ID in the cache and returns
220 // the name of the corresponding data file.
221 func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) {
222         entry, err = c.Get(id)
223         if err != nil {
224                 return "", Entry{}, err
225         }
226         file = c.OutputFile(entry.OutputID)
227         info, err := os.Stat(file)
228         if err != nil {
229                 return "", Entry{}, &entryNotFoundError{Err: err}
230         }
231         if info.Size() != entry.Size {
232                 return "", Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")}
233         }
234         return file, entry, nil
235 }
236
237 // GetBytes looks up the action ID in the cache and returns
238 // the corresponding output bytes.
239 // GetBytes should only be used for data that can be expected to fit in memory.
240 func (c *Cache) GetBytes(id ActionID) ([]byte, Entry, error) {
241         entry, err := c.Get(id)
242         if err != nil {
243                 return nil, entry, err
244         }
245         data, _ := ioutil.ReadFile(c.OutputFile(entry.OutputID))
246         if sha256.Sum256(data) != entry.OutputID {
247                 return nil, entry, &entryNotFoundError{Err: errors.New("bad checksum")}
248         }
249         return data, entry, nil
250 }
251
252 // OutputFile returns the name of the cache file storing output with the given OutputID.
253 func (c *Cache) OutputFile(out OutputID) string {
254         file := c.fileName(out, "d")
255         c.used(file)
256         return file
257 }
258
259 // Time constants for cache expiration.
260 //
261 // We set the mtime on a cache file on each use, but at most one per mtimeInterval (1 hour),
262 // to avoid causing many unnecessary inode updates. The mtimes therefore
263 // roughly reflect "time of last use" but may in fact be older by at most an hour.
264 //
265 // We scan the cache for entries to delete at most once per trimInterval (1 day).
266 //
267 // When we do scan the cache, we delete entries that have not been used for
268 // at least trimLimit (5 days). Statistics gathered from a month of usage by
269 // Go developers found that essentially all reuse of cached entries happened
270 // within 5 days of the previous reuse. See golang.org/issue/22990.
271 const (
272         mtimeInterval = 1 * time.Hour
273         trimInterval  = 24 * time.Hour
274         trimLimit     = 5 * 24 * time.Hour
275 )
276
277 // used makes a best-effort attempt to update mtime on file,
278 // so that mtime reflects cache access time.
279 //
280 // Because the reflection only needs to be approximate,
281 // and to reduce the amount of disk activity caused by using
282 // cache entries, used only updates the mtime if the current
283 // mtime is more than an hour old. This heuristic eliminates
284 // nearly all of the mtime updates that would otherwise happen,
285 // while still keeping the mtimes useful for cache trimming.
286 func (c *Cache) used(file string) {
287         info, err := os.Stat(file)
288         if err == nil && c.now().Sub(info.ModTime()) < mtimeInterval {
289                 return
290         }
291         os.Chtimes(file, c.now(), c.now())
292 }
293
294 // Trim removes old cache entries that are likely not to be reused.
295 func (c *Cache) Trim() {
296         now := c.now()
297
298         // We maintain in dir/trim.txt the time of the last completed cache trim.
299         // If the cache has been trimmed recently enough, do nothing.
300         // This is the common case.
301         data, _ := renameio.ReadFile(filepath.Join(c.dir, "trim.txt"))
302         t, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64)
303         if err == nil && now.Sub(time.Unix(t, 0)) < trimInterval {
304                 return
305         }
306
307         // Trim each of the 256 subdirectories.
308         // We subtract an additional mtimeInterval
309         // to account for the imprecision of our "last used" mtimes.
310         cutoff := now.Add(-trimLimit - mtimeInterval)
311         for i := 0; i < 256; i++ {
312                 subdir := filepath.Join(c.dir, fmt.Sprintf("%02x", i))
313                 c.trimSubdir(subdir, cutoff)
314         }
315
316         // Ignore errors from here: if we don't write the complete timestamp, the
317         // cache will appear older than it is, and we'll trim it again next time.
318         renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666)
319 }
320
321 // trimSubdir trims a single cache subdirectory.
322 func (c *Cache) trimSubdir(subdir string, cutoff time.Time) {
323         // Read all directory entries from subdir before removing
324         // any files, in case removing files invalidates the file offset
325         // in the directory scan. Also, ignore error from f.Readdirnames,
326         // because we don't care about reporting the error and we still
327         // want to process any entries found before the error.
328         f, err := os.Open(subdir)
329         if err != nil {
330                 return
331         }
332         names, _ := f.Readdirnames(-1)
333         f.Close()
334
335         for _, name := range names {
336                 // Remove only cache entries (xxxx-a and xxxx-d).
337                 if !strings.HasSuffix(name, "-a") && !strings.HasSuffix(name, "-d") {
338                         continue
339                 }
340                 entry := filepath.Join(subdir, name)
341                 info, err := os.Stat(entry)
342                 if err == nil && info.ModTime().Before(cutoff) {
343                         os.Remove(entry)
344                 }
345         }
346 }
347
348 // putIndexEntry adds an entry to the cache recording that executing the action
349 // with the given id produces an output with the given output id (hash) and size.
350 func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify bool) error {
351         // Note: We expect that for one reason or another it may happen
352         // that repeating an action produces a different output hash
353         // (for example, if the output contains a time stamp or temp dir name).
354         // While not ideal, this is also not a correctness problem, so we
355         // don't make a big deal about it. In particular, we leave the action
356         // cache entries writable specifically so that they can be overwritten.
357         //
358         // Setting GODEBUG=gocacheverify=1 does make a big deal:
359         // in verify mode we are double-checking that the cache entries
360         // are entirely reproducible. As just noted, this may be unrealistic
361         // in some cases but the check is also useful for shaking out real bugs.
362         entry := fmt.Sprintf("v1 %x %x %20d %20d\n", id, out, size, time.Now().UnixNano())
363         if verify && allowVerify {
364                 old, err := c.get(id)
365                 if err == nil && (old.OutputID != out || old.Size != size) {
366                         // panic to show stack trace, so we can see what code is generating this cache entry.
367                         msg := fmt.Sprintf("go: internal cache error: cache verify failed: id=%x changed:<<<\n%s\n>>>\nold: %x %d\nnew: %x %d", id, reverseHash(id), out, size, old.OutputID, old.Size)
368                         panic(msg)
369                 }
370         }
371         file := c.fileName(id, "a")
372
373         // Copy file to cache directory.
374         mode := os.O_WRONLY | os.O_CREATE
375         f, err := os.OpenFile(file, mode, 0666)
376         if err != nil {
377                 return err
378         }
379         _, err = f.WriteString(entry)
380         if err == nil {
381                 // Truncate the file only *after* writing it.
382                 // (This should be a no-op, but truncate just in case of previous corruption.)
383                 //
384                 // This differs from ioutil.WriteFile, which truncates to 0 *before* writing
385                 // via os.O_TRUNC. Truncating only after writing ensures that a second write
386                 // of the same content to the same file is idempotent, and does not — even
387                 // temporarily! — undo the effect of the first write.
388                 err = f.Truncate(int64(len(entry)))
389         }
390         if closeErr := f.Close(); err == nil {
391                 err = closeErr
392         }
393         if err != nil {
394                 // TODO(bcmills): This Remove potentially races with another go command writing to file.
395                 // Can we eliminate it?
396                 os.Remove(file)
397                 return err
398         }
399         os.Chtimes(file, c.now(), c.now()) // mainly for tests
400
401         return nil
402 }
403
404 // Put stores the given output in the cache as the output for the action ID.
405 // It may read file twice. The content of file must not change between the two passes.
406 func (c *Cache) Put(id ActionID, file io.ReadSeeker) (OutputID, int64, error) {
407         return c.put(id, file, true)
408 }
409
410 // PutNoVerify is like Put but disables the verify check
411 // when GODEBUG=goverifycache=1 is set.
412 // It is meant for data that is OK to cache but that we expect to vary slightly from run to run,
413 // like test output containing times and the like.
414 func (c *Cache) PutNoVerify(id ActionID, file io.ReadSeeker) (OutputID, int64, error) {
415         return c.put(id, file, false)
416 }
417
418 func (c *Cache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) {
419         // Compute output ID.
420         h := sha256.New()
421         if _, err := file.Seek(0, 0); err != nil {
422                 return OutputID{}, 0, err
423         }
424         size, err := io.Copy(h, file)
425         if err != nil {
426                 return OutputID{}, 0, err
427         }
428         var out OutputID
429         h.Sum(out[:0])
430
431         // Copy to cached output file (if not already present).
432         if err := c.copyFile(file, out, size); err != nil {
433                 return out, size, err
434         }
435
436         // Add to cache index.
437         return out, size, c.putIndexEntry(id, out, size, allowVerify)
438 }
439
440 // PutBytes stores the given bytes in the cache as the output for the action ID.
441 func (c *Cache) PutBytes(id ActionID, data []byte) error {
442         _, _, err := c.Put(id, bytes.NewReader(data))
443         return err
444 }
445
446 // copyFile copies file into the cache, expecting it to have the given
447 // output ID and size, if that file is not present already.
448 func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
449         name := c.fileName(out, "d")
450         info, err := os.Stat(name)
451         if err == nil && info.Size() == size {
452                 // Check hash.
453                 if f, err := os.Open(name); err == nil {
454                         h := sha256.New()
455                         io.Copy(h, f)
456                         f.Close()
457                         var out2 OutputID
458                         h.Sum(out2[:0])
459                         if out == out2 {
460                                 return nil
461                         }
462                 }
463                 // Hash did not match. Fall through and rewrite file.
464         }
465
466         // Copy file to cache directory.
467         mode := os.O_RDWR | os.O_CREATE
468         if err == nil && info.Size() > size { // shouldn't happen but fix in case
469                 mode |= os.O_TRUNC
470         }
471         f, err := os.OpenFile(name, mode, 0666)
472         if err != nil {
473                 return err
474         }
475         defer f.Close()
476         if size == 0 {
477                 // File now exists with correct size.
478                 // Only one possible zero-length file, so contents are OK too.
479                 // Early return here makes sure there's a "last byte" for code below.
480                 return nil
481         }
482
483         // From here on, if any of the I/O writing the file fails,
484         // we make a best-effort attempt to truncate the file f
485         // before returning, to avoid leaving bad bytes in the file.
486
487         // Copy file to f, but also into h to double-check hash.
488         if _, err := file.Seek(0, 0); err != nil {
489                 f.Truncate(0)
490                 return err
491         }
492         h := sha256.New()
493         w := io.MultiWriter(f, h)
494         if _, err := io.CopyN(w, file, size-1); err != nil {
495                 f.Truncate(0)
496                 return err
497         }
498         // Check last byte before writing it; writing it will make the size match
499         // what other processes expect to find and might cause them to start
500         // using the file.
501         buf := make([]byte, 1)
502         if _, err := file.Read(buf); err != nil {
503                 f.Truncate(0)
504                 return err
505         }
506         h.Write(buf)
507         sum := h.Sum(nil)
508         if !bytes.Equal(sum, out[:]) {
509                 f.Truncate(0)
510                 return fmt.Errorf("file content changed underfoot")
511         }
512
513         // Commit cache file entry.
514         if _, err := f.Write(buf); err != nil {
515                 f.Truncate(0)
516                 return err
517         }
518         if err := f.Close(); err != nil {
519                 // Data might not have been written,
520                 // but file may look like it is the right size.
521                 // To be extra careful, remove cached file.
522                 os.Remove(name)
523                 return err
524         }
525         os.Chtimes(name, c.now(), c.now()) // mainly for tests
526
527         return nil
528 }