feat: add debug commands for folder counts and files (#10206)

This adds two debugging commands that print information directly from
the database; one for folder counts, and one for file metadata for files
matching a pattern in a folder. E.g.,

```
% syncthing debug database-counts p3jms-73gps
DEVICE   TYPE       FLAGS    DELETED  COUNT  SIZE
-local-  FILE       -------  ---      0      0
-local-  FILE       --G----  ---      2473   70094796496
-local-  DIRECTORY  -------  ---      0      0
-local-  DIRECTORY  --G----  ---      19     2432
PSEUDOP  FILE       -------  ---      2473   70094796496
PSEUDOP  FILE       -nG----  ---      0      0
PSEUDOP  DIRECTORY  -------  ---      19     2432
PSEUDOP  DIRECTORY  -nG----  ---      0      0
```

```
% syncthing debug database-file p3jms-73gps 20240929-DSCF1387
DSCF1387
DEVICE   TYPE  NAME                          SEQUENCE  DELETED  MODIFIED                        SIZE      FLAGS    VERSION             BLOCKLIST
-local-  FILE  Austin/20240929-DSCF1387.raf  1204      ---      2024-09-29T01:10:54Z            48911888  --G----  HX2ELNU:1744213700  fsQdMvUL
PSEUDOP  FILE  Austin/20240929-DSCF1387.raf  22279     ---      2024-09-29T01:10:54Z            48911888  -------  HX2ELNU:1744213700  fsQdMvUL
-local-  FILE  Austin/20240929-DSCF1387.xmp  1196      ---      2024-10-16T08:08:35.137501751Z  5579      --G----  HX2ELNU:1744213700  xDGMnepi
PSEUDOP  FILE  Austin/20240929-DSCF1387.xmp  19910     ---      2024-10-16T08:08:35.137501751Z  5579      -------  HX2ELNU:1744213700  xDGMnepi
```

The local flag bits get a string representation for the bitmask,

```
	FlagLocalUnsupported:   "u",
	FlagLocalIgnored:       "i",
	FlagLocalMustRescan:    "r",
	FlagLocalReceiveOnly:   "e",
	FlagLocalGlobal:        "G",
	FlagLocalNeeded:        "n",
	FlagLocalRemoteInvalid: "v",
```
This commit is contained in:
Jakob Borg
2025-07-04 15:46:24 +02:00
committed by GitHub
parent 06dd8ee6d7
commit ff88430efb
7 changed files with 189 additions and 3 deletions
+31 -2
View File
@@ -920,8 +920,10 @@ func (browserCmd) Run() error {
}
type debugCmd struct {
ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
DatabaseStatistics databaseStatsCmd `cmd:"" help:"Display database size statistics"`
ResetDatabase resetDatabaseCmd `cmd:"" help:"Reset the database, forcing a full rescan and resync"`
DatabaseStatistics databaseStatsCmd `cmd:"" help:"Display database size statistics"`
DatabaseCounts databaseCountsCmd `cmd:"" help:"Display database folder counts"`
DatabaseFile databaseFileCmd `cmd:"" help:"Display database file metadata"`
}
type resetDatabaseCmd struct{}
@@ -956,6 +958,33 @@ func (c databaseStatsCmd) Run() error {
return tw.Flush()
}
type databaseCountsCmd struct {
Folder string `arg:"" required:""`
}
func (c databaseCountsCmd) Run() error {
db, err := sqlite.Open(locations.Get(locations.Database))
if err != nil {
return err
}
return db.DebugCounts(os.Stdout, c.Folder)
}
type databaseFileCmd struct {
Folder string `arg:"" required:""`
File string `arg:"" required:""`
}
func (c databaseFileCmd) Run() error {
db, err := sqlite.Open(locations.Get(locations.Database))
if err != nil {
return err
}
return db.DebugFilePattern(os.Stdout, c.Folder, c.File)
}
func (c databaseStatsCmd) printStat(w io.Writer, s *sqlite.DatabaseStatistics) {
for _, table := range s.Tables {
fmt.Fprintf(w, "%s\t%s\t%s\t%8d KiB\t%5.01f %%\n", s.Name, cmp.Or(s.FolderID, "-"), table.Name, table.Size/1024, float64(table.Size-table.Unused)*100/float64(table.Size))