// scan scans the directory tree for files. func (cache *Cache) scan() { cache.cachedFiles = cmap.New() cache.totalSize = 0 if !core.PathExists(cache.rootPath) { if err := os.MkdirAll(cache.rootPath, core.DirPermissions); err != nil { log.Fatalf("Failed to create cache directory %s: %s", cache.rootPath, err) } return } log.Info("Scanning cache directory %s...", cache.rootPath) filepath.Walk(cache.rootPath, func(name string, info os.FileInfo, err error) error { if err != nil { log.Fatalf("%s", err) } else if !info.IsDir() { // We don't have directory entries. name = name[len(cache.rootPath)+1:] log.Debug("Found file %s", name) size := info.Size() cache.cachedFiles.Set(name, &cachedFile{ lastReadTime: time.Unix(tools.AccessTime(info), 0), readCount: 0, size: size, }) cache.totalSize += size } return nil }) log.Info("Scan complete, found %d entries", cache.cachedFiles.Count()) }
func start(directory string, highWaterMark, lowWaterMark int64) { entries := CacheEntries{} var totalSize int64 = 0 if err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error { if err != nil { return err } else if (len(info.Name()) == 28 || len(info.Name()) == 29) && info.Name()[27] == '=' { // Directory has the right length. We do this in an attempt to clean only entire // entries in the cache, not just individual files from them. // 28 == length of 20-byte sha1 hash, encoded to base64, which always gets a trailing = // as padding so we can check that to be "sure". // Also 29 in case we appended an extra = (see below) if size, err := findSize(path); err != nil { return err } else { entries = append(entries, CacheEntry{path, size, tools.AccessTime(info)}) totalSize += size return filepath.SkipDir } } else { return nil // nothing particularly to do for other entries } }); err != nil { log.Fatalf("error walking cache directory: %s\n", err) } log.Notice("Total cache size: %s", humanize.Bytes(uint64(totalSize))) if totalSize < highWaterMark { return // Nothing to do, cache is small enough. } // OK, we need to slim it down a bit. We implement a simple LRU algorithm. sort.Sort(entries) for _, entry := range entries { log.Notice("Cleaning %s, accessed %s, saves %s", entry.Path, humanize.Time(time.Unix(entry.Atime, 0)), humanize.Bytes(uint64(entry.Size))) // Try to rename the directory first so we don't delete bits while someone might access them. newPath := entry.Path + "=" if err := os.Rename(entry.Path, newPath); err != nil { log.Errorf("Couldn't rename %s: %s", entry.Path, err) continue } if err := os.RemoveAll(newPath); err != nil { log.Errorf("Couldn't remove %s: %s", newPath, err) continue } totalSize -= entry.Size if totalSize < lowWaterMark { break } } }