From 4fd614be09572774b33b18aca65ae3becd89b886 Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Fri, 23 Oct 2015 20:02:38 +0100 Subject: [PATCH] Add a different mode to stindex --- cmd/stindex/dump.go | 63 +++++++++++++++++++++++++++++ cmd/stindex/dumpsize.go | 90 +++++++++++++++++++++++++++++++++++++++++ cmd/stindex/main.go | 70 +++++++++----------------------- cmd/stindex/util.go | 52 ++++++++++++++++++++++++ 4 files changed, 223 insertions(+), 52 deletions(-) create mode 100644 cmd/stindex/dump.go create mode 100644 cmd/stindex/dumpsize.go create mode 100644 cmd/stindex/util.go diff --git a/cmd/stindex/dump.go b/cmd/stindex/dump.go new file mode 100644 index 00000000..24b43670 --- /dev/null +++ b/cmd/stindex/dump.go @@ -0,0 +1,63 @@ +// Copyright (C) 2015 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package main + +import ( + "encoding/binary" + "fmt" + "log" + + "github.com/syncthing/protocol" + "github.com/syncthing/syncthing/lib/db" + "github.com/syndtr/goleveldb/leveldb" +) + +func dump(ldb *leveldb.DB) { + it := ldb.NewIterator(nil, nil) + var dev protocol.DeviceID + for it.Next() { + key := it.Key() + switch key[0] { + case db.KeyTypeDevice: + folder := nulString(key[1 : 1+64]) + devBytes := key[1+64 : 1+64+32] + name := nulString(key[1+64+32:]) + copy(dev[:], devBytes) + fmt.Printf("[device] F:%q N:%q D:%v\n", folder, name, dev) + + var f protocol.FileInfo + err := f.UnmarshalXDR(it.Value()) + if err != nil { + log.Fatal(err) + } + fmt.Printf(" N:%q\n F:%#o\n M:%d\n V:%v\n S:%d\n B:%d\n", f.Name, f.Flags, f.Modified, f.Version, f.Size(), len(f.Blocks)) + + case db.KeyTypeGlobal: + folder := nulString(key[1 : 1+64]) + name := nulString(key[1+64:]) + fmt.Printf("[global] F:%q N:%q V:%x\n", folder, name, it.Value()) + + case db.KeyTypeBlock: + folder := nulString(key[1 : 1+64]) + hash := key[1+64 : 1+64+32] + name := nulString(key[1+64+32:]) + fmt.Printf("[block] F:%q H:%x N:%q I:%d\n", folder, hash, name, binary.BigEndian.Uint32(it.Value())) + + case db.KeyTypeDeviceStatistic: + fmt.Printf("[dstat]\n %x\n %x\n", it.Key(), it.Value()) + + case db.KeyTypeFolderStatistic: + fmt.Printf("[fstat]\n %x\n %x\n", it.Key(), it.Value()) + + case db.KeyTypeVirtualMtime: + fmt.Printf("[mtime]\n %x\n %x\n", it.Key(), it.Value()) + + default: + fmt.Printf("[???]\n %x\n %x\n", it.Key(), it.Value()) + } + } +} diff --git a/cmd/stindex/dumpsize.go b/cmd/stindex/dumpsize.go new file mode 100644 index 00000000..272b50f8 --- /dev/null +++ b/cmd/stindex/dumpsize.go @@ -0,0 +1,90 @@ +// Copyright (C) 2015 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package main + +import ( + "container/heap" + "fmt" + + "github.com/syncthing/protocol" + "github.com/syncthing/syncthing/lib/db" + "github.com/syndtr/goleveldb/leveldb" +) + +// An IntHeap is a min-heap of ints. +type SizedElement struct { + key string + size int +} + +type ElementHeap []SizedElement + +func (h ElementHeap) Len() int { return len(h) } +func (h ElementHeap) Less(i, j int) bool { return h[i].size > h[j].size } +func (h ElementHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } + +func (h *ElementHeap) Push(x interface{}) { + *h = append(*h, x.(SizedElement)) +} + +func (h *ElementHeap) Pop() interface{} { + old := *h + n := len(old) + x := old[n-1] + *h = old[0 : n-1] + return x +} + +func dumpsize(ldb *leveldb.DB) { + h := &ElementHeap{} + heap.Init(h) + + it := ldb.NewIterator(nil, nil) + var dev protocol.DeviceID + var ele SizedElement + for it.Next() { + key := it.Key() + switch key[0] { + case db.KeyTypeDevice: + folder := nulString(key[1 : 1+64]) + devBytes := key[1+64 : 1+64+32] + name := nulString(key[1+64+32:]) + copy(dev[:], devBytes) + ele.key = fmt.Sprintf("DEVICE:%s:%s:%s", dev, folder, name) + + case db.KeyTypeGlobal: + folder := nulString(key[1 : 1+64]) + name := nulString(key[1+64:]) + ele.key = fmt.Sprintf("GLOBAL:%s:%s", folder, name) + + case db.KeyTypeBlock: + folder := nulString(key[1 : 1+64]) + hash := key[1+64 : 1+64+32] + name := nulString(key[1+64+32:]) + ele.key = fmt.Sprintf("BLOCK:%s:%x:%s", folder, hash, name) + + case db.KeyTypeDeviceStatistic: + ele.key = fmt.Sprintf("DEVICESTATS:%s", key[1:]) + + case db.KeyTypeFolderStatistic: + ele.key = fmt.Sprintf("FOLDERSTATS:%s", key[1:]) + + case db.KeyTypeVirtualMtime: + ele.key = fmt.Sprintf("MTIME:%s", key[1:]) + + default: + ele.key = fmt.Sprintf("UNKNOWN:%x", key) + } + ele.size = len(it.Value()) + heap.Push(h, ele) + } + + for h.Len() > 0 { + ele = heap.Pop(h).(SizedElement) + fmt.Println(ele.key, ele.size) + } +} diff --git a/cmd/stindex/main.go b/cmd/stindex/main.go index 370aab6b..2a67cc2a 100644 --- a/cmd/stindex/main.go +++ b/cmd/stindex/main.go @@ -7,25 +7,33 @@ package main import ( - "encoding/binary" "flag" "fmt" "log" "os" + "path/filepath" - "github.com/syncthing/syncthing/lib/db" - "github.com/syncthing/syncthing/lib/protocol" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/opt" ) func main() { + var mode string log.SetFlags(0) log.SetOutput(os.Stdout) + flag.StringVar(&mode, "mode", "dump", "Mode of operation: dump, dumpsize") + flag.Parse() - ldb, err := leveldb.OpenFile(flag.Arg(0), &opt.Options{ + path := flag.Arg(0) + if path == "" { + path = filepath.Join(defaultConfigDir(), "index-v0.11.0.db") + } + + fmt.Println("Path:", path) + + ldb, err := leveldb.OpenFile(path, &opt.Options{ ErrorIfMissing: true, Strict: opt.StrictAll, OpenFilesCacheCapacity: 100, @@ -34,53 +42,11 @@ func main() { log.Fatal(err) } - it := ldb.NewIterator(nil, nil) - var dev protocol.DeviceID - for it.Next() { - key := it.Key() - switch key[0] { - case db.KeyTypeDevice: - folder := nulString(key[1 : 1+64]) - devBytes := key[1+64 : 1+64+32] - name := nulString(key[1+64+32:]) - copy(dev[:], devBytes) - fmt.Printf("[device] F:%q N:%q D:%v\n", folder, name, dev) - - var f protocol.FileInfo - err := f.UnmarshalXDR(it.Value()) - if err != nil { - log.Fatal(err) - } - fmt.Printf(" N:%q\n F:%#o\n M:%d\n V:%v\n S:%d\n B:%d\n", f.Name, f.Flags, f.Modified, f.Version, f.Size(), len(f.Blocks)) - - case db.KeyTypeGlobal: - folder := nulString(key[1 : 1+64]) - name := nulString(key[1+64:]) - fmt.Printf("[global] F:%q N:%q V:%x\n", folder, name, it.Value()) - - case db.KeyTypeBlock: - folder := nulString(key[1 : 1+64]) - hash := key[1+64 : 1+64+32] - name := nulString(key[1+64+32:]) - fmt.Printf("[block] F:%q H:%x N:%q I:%d\n", folder, hash, name, binary.BigEndian.Uint32(it.Value())) - - case db.KeyTypeDeviceStatistic: - fmt.Printf("[dstat]\n %x\n %x\n", it.Key(), it.Value()) - - case db.KeyTypeFolderStatistic: - fmt.Printf("[fstat]\n %x\n %x\n", it.Key(), it.Value()) - - default: - fmt.Printf("[???]\n %x\n %x\n", it.Key(), it.Value()) - } + if mode == "dump" { + dump(ldb) + } else if mode == "dumpsize" { + size(ldb) + } else { + fmt.Println("Unknown mode") } } - -func nulString(bs []byte) string { - for i := range bs { - if bs[i] == 0 { - return string(bs[:i]) - } - } - return string(bs) -} diff --git a/cmd/stindex/util.go b/cmd/stindex/util.go new file mode 100644 index 00000000..333cc582 --- /dev/null +++ b/cmd/stindex/util.go @@ -0,0 +1,52 @@ +// Copyright (C) 2015 The Syncthing Authors. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package main + +import ( + "log" + "os" + "path/filepath" + "runtime" + + "github.com/syncthing/syncthing/lib/osutil" +) + +func nulString(bs []byte) string { + for i := range bs { + if bs[i] == 0 { + return string(bs[:i]) + } + } + return string(bs) +} + +func defaultConfigDir() string { + switch runtime.GOOS { + case "windows": + if p := os.Getenv("LocalAppData"); p != "" { + return filepath.Join(p, "Syncthing") + } + return filepath.Join(os.Getenv("AppData"), "Syncthing") + + case "darwin": + dir, err := osutil.ExpandTilde("~/Library/Application Support/Syncthing") + if err != nil { + log.Fatal(err) + } + return dir + + default: + if xdgCfg := os.Getenv("XDG_CONFIG_HOME"); xdgCfg != "" { + return filepath.Join(xdgCfg, "syncthing") + } + dir, err := osutil.ExpandTilde("~/.config/syncthing") + if err != nil { + log.Fatal(err) + } + return dir + } +}