Add a check option to garbage collect DB files
This commit is contained in:
parent
615af97043
commit
e895beadb7
47
main.go
47
main.go
@ -2148,36 +2148,54 @@ func collectFileListing(root string) (paths []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkFiles(root, suffix string, hashes []string) (bool, []string, error) {
|
func checkFiles(gc bool,
|
||||||
|
root, suffix string, hashes []string) (bool, []string, error) {
|
||||||
db := hashesToFileListing(root, suffix, hashes)
|
db := hashesToFileListing(root, suffix, hashes)
|
||||||
fs, err := collectFileListing(root)
|
fs, err := collectFileListing(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
iDB, iFS, ok, intersection := 0, 0, true, []string{}
|
// There are two legitimate cases of FS-only database files:
|
||||||
|
// 1. There is no code to unlink images at all
|
||||||
|
// (although sync should create orphan records for everything).
|
||||||
|
// 2. thumbnail: failures may result in an unreferenced garbage image.
|
||||||
|
ok := true
|
||||||
|
onlyDB := func(path string) {
|
||||||
|
ok = false
|
||||||
|
fmt.Printf("only in DB: %s\n", path)
|
||||||
|
}
|
||||||
|
onlyFS := func(path string) {
|
||||||
|
if !gc {
|
||||||
|
ok = false
|
||||||
|
fmt.Printf("only in FS: %s\n", path)
|
||||||
|
} else if err := os.Remove(path); err != nil {
|
||||||
|
ok = false
|
||||||
|
fmt.Printf("only in FS (removing failed): %s: %s\n", path, err)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("only in FS (removing): %s\n", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iDB, iFS, intersection := 0, 0, []string{}
|
||||||
for iDB < len(db) && iFS < len(fs) {
|
for iDB < len(db) && iFS < len(fs) {
|
||||||
if db[iDB] == fs[iFS] {
|
if db[iDB] == fs[iFS] {
|
||||||
intersection = append(intersection, db[iDB])
|
intersection = append(intersection, db[iDB])
|
||||||
iDB++
|
iDB++
|
||||||
iFS++
|
iFS++
|
||||||
} else if db[iDB] < fs[iFS] {
|
} else if db[iDB] < fs[iFS] {
|
||||||
ok = false
|
onlyDB(db[iDB])
|
||||||
fmt.Printf("only in DB: %s\n", db[iDB])
|
|
||||||
iDB++
|
iDB++
|
||||||
} else {
|
} else {
|
||||||
ok = false
|
onlyFS(fs[iFS])
|
||||||
fmt.Printf("only in FS: %s\n", fs[iFS])
|
|
||||||
iFS++
|
iFS++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, path := range db[iDB:] {
|
for _, path := range db[iDB:] {
|
||||||
ok = false
|
onlyDB(path)
|
||||||
fmt.Printf("only in DB: %s\n", path)
|
|
||||||
}
|
}
|
||||||
for _, path := range fs[iFS:] {
|
for _, path := range fs[iFS:] {
|
||||||
ok = false
|
onlyFS(path)
|
||||||
fmt.Printf("only in FS: %s\n", path)
|
|
||||||
}
|
}
|
||||||
return ok, intersection, nil
|
return ok, intersection, nil
|
||||||
}
|
}
|
||||||
@ -2225,6 +2243,7 @@ func checkHashes(paths []string) (bool, error) {
|
|||||||
// cmdCheck carries out various database consistency checks.
|
// cmdCheck carries out various database consistency checks.
|
||||||
func cmdCheck(fs *flag.FlagSet, args []string) error {
|
func cmdCheck(fs *flag.FlagSet, args []string) error {
|
||||||
full := fs.Bool("full", false, "verify image hashes")
|
full := fs.Bool("full", false, "verify image hashes")
|
||||||
|
gc := fs.Bool("gc", false, "garbage collect database files")
|
||||||
if err := fs.Parse(args); err != nil {
|
if err := fs.Parse(args); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -2261,13 +2280,13 @@ func cmdCheck(fs *flag.FlagSet, args []string) error {
|
|||||||
|
|
||||||
// This somewhat duplicates {image,thumb}Path().
|
// This somewhat duplicates {image,thumb}Path().
|
||||||
log.Println("checking SQL against filesystem")
|
log.Println("checking SQL against filesystem")
|
||||||
okImages, intersection, err := checkFiles(
|
okImages, intersection, err := checkFiles(*gc,
|
||||||
filepath.Join(galleryDirectory, nameOfImageRoot), "", allSHA1)
|
filepath.Join(galleryDirectory, nameOfImageRoot), "", allSHA1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
okThumbs, _, err := checkFiles(
|
okThumbs, _, err := checkFiles(*gc,
|
||||||
filepath.Join(galleryDirectory, nameOfThumbRoot), ".webp", thumbSHA1)
|
filepath.Join(galleryDirectory, nameOfThumbRoot), ".webp", thumbSHA1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -2276,11 +2295,11 @@ func cmdCheck(fs *flag.FlagSet, args []string) error {
|
|||||||
ok = false
|
ok = false
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("checking for dead symlinks")
|
log.Println("checking for dead symlinks (should become orphans on sync)")
|
||||||
for _, path := range intersection {
|
for _, path := range intersection {
|
||||||
if _, err := os.Stat(path); err != nil {
|
if _, err := os.Stat(path); err != nil {
|
||||||
ok = false
|
ok = false
|
||||||
fmt.Printf("%s: %s\n", path, err)
|
fmt.Printf("%s: %s\n", path, err.(*os.PathError).Unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user