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
+44
View File
@@ -11,6 +11,8 @@ import (
"crypto/sha256"
"encoding/binary"
"fmt"
"slices"
"strings"
"time"
"github.com/syncthing/syncthing/internal/gen/bep"
@@ -40,10 +42,52 @@ const (
LocalAllFlags = FlagLocalUnsupported | FlagLocalIgnored | FlagLocalMustRescan | FlagLocalReceiveOnly | FlagLocalGlobal | FlagLocalNeeded | FlagLocalRemoteInvalid
)
// localFlagBitNames maps flag values to characters which can be used to
// build a permission-like bit string for easier reading.
var localFlagBitNames = map[FlagLocal]string{
FlagLocalUnsupported: "u",
FlagLocalIgnored: "i",
FlagLocalMustRescan: "r",
FlagLocalReceiveOnly: "e",
FlagLocalGlobal: "G",
FlagLocalNeeded: "n",
FlagLocalRemoteInvalid: "v",
}
func (f FlagLocal) IsInvalid() bool {
return f&LocalInvalidFlags != 0
}
// HumanString returns a permission-like string representation of the flag bits
func (f FlagLocal) HumanString() string {
if f == 0 {
return strings.Repeat("-", len(localFlagBitNames))
}
bit := FlagLocal(1)
var res bytes.Buffer
var extra strings.Builder
for f != 0 {
if f&bit != 0 {
if name, ok := localFlagBitNames[bit]; ok {
res.WriteString(name)
} else {
fmt.Fprintf(&extra, "+0x%x", bit)
}
} else {
res.WriteString("-")
}
f &^= bit
bit <<= 1
}
if res.Len() < len(localFlagBitNames) {
res.WriteString(strings.Repeat("-", len(localFlagBitNames)-res.Len()))
}
base := res.Bytes()
slices.Reverse(base)
return string(base) + extra.String()
}
// BlockSizes is the list of valid block sizes, from min to max
var BlockSizes []int
+11
View File
@@ -38,6 +38,17 @@ func (v *Vector) String() string {
return buf.String()
}
func (v *Vector) HumanString() string {
var buf strings.Builder
for i, c := range v.Counters {
if i > 0 {
buf.WriteRune(',')
}
fmt.Fprintf(&buf, "%s:%d", c.ID, c.Value)
}
return buf.String()
}
func (v *Vector) ToWire() *bep.Vector {
counters := make([]*bep.Counter, len(v.Counters))
for i, c := range v.Counters {