Commit 0d06714a92
Verified · cmc
Layout: unified · split
internal/render/render.go +8
| @@ -8,6 +8,7 @@ import ( | ||
| 8 | 8 | "path/filepath" |
| 9 | 9 | "slices" |
| 10 | 10 | "strconv" |
| 11 | "time" | |
| 11 | 12 | |
| 12 | 13 | "golang.org/x/sync/singleflight" |
| 13 | 14 | |
| @@ -84,6 +85,10 @@ func (r *Renderer) generate(it *library.Item, w int, dst string) error { | ||
| 84 | 85 | return os.Rename(tmp.Name(), dst) |
| 85 | 86 | } |
| 86 | 87 | |
| 88 | // pruneGrace keeps stale directories modified this recently, since a request | |
| 89 | // holding an older library snapshot may still be writing into them. | |
| 90 | const pruneGrace = 5 * time.Minute | |
| 91 | ||
| 87 | 92 | // Prune removes derivative directories for items no longer in lib or whose source changed. |
| 88 | 93 | func (r *Renderer) Prune(lib *library.Library) error { |
| 89 | 94 | keep := map[string]bool{} |
| @@ -99,6 +104,9 @@ func (r *Renderer) Prune(lib *library.Library) error { | ||
| 99 | 104 | var firstErr error |
| 100 | 105 | for _, v := range versions { |
| 101 | 106 | if !keep[v] { |
| 107 | if fi, err := os.Stat(v); err == nil && time.Since(fi.ModTime()) < pruneGrace { | |
| 108 | continue | |
| 109 | } | |
| 102 | 110 | if err := os.RemoveAll(v); err != nil { |
| 103 | 111 | log.Printf("prune %s: %v", v, err) |
| 104 | 112 | if firstErr == nil { |
internal/render/render_test.go +19
| @@ -151,6 +151,10 @@ func TestPrune(t *testing.T) { | ||
| 151 | 151 | t.Fatal(err) |
| 152 | 152 | } |
| 153 | 153 | } |
| 154 | past := time.Now().Add(-2 * pruneGrace) | |
| 155 | for _, it := range []*library.Item{cur, old, gone} { | |
| 156 | os.Chtimes(filepath.Dir(r.Path(it, 480)), past, past) | |
| 157 | } | |
| 154 | 158 | lib := &library.Library{Albums: []*library.Album{{Slug: "tokyo", Items: []*library.Item{cur}}}} |
| 155 | 159 | if err := r.Prune(lib); err != nil { |
| 156 | 160 | t.Fatal(err) |
| @@ -164,3 +168,18 @@ func TestPrune(t *testing.T) { | ||
| 164 | 168 | } |
| 165 | 169 | } |
| 166 | 170 | } |
| 171 | ||
| 172 | func TestPruneKeepsRecentlyModifiedStaleDir(t *testing.T) { | |
| 173 | f := &fakeFormat{} | |
| 174 | r := New(t.TempDir(), 1) | |
| 175 | old := item(f) | |
| 176 | if _, err := r.Get(old, 480); err != nil { | |
| 177 | t.Fatal(err) | |
| 178 | } | |
| 179 | if err := r.Prune(&library.Library{}); err != nil { | |
| 180 | t.Fatal(err) | |
| 181 | } | |
| 182 | if _, err := os.Stat(r.Path(old, 480)); err != nil { | |
| 183 | t.Fatalf("recently written stale dir removed: %v", err) | |
| 184 | } | |
| 185 | } | |