forked from TrueCloudLab/restic
Remove Each(), add basic stats
This commit is contained in:
parent
4bb7f2f2ed
commit
b6f25aa690
6 changed files with 82 additions and 71 deletions
|
@ -24,30 +24,6 @@ var (
|
||||||
|
|
||||||
const hashSize = sha256.Size
|
const hashSize = sha256.Size
|
||||||
|
|
||||||
// Each lists all entries of type t in the backend and calls function f() with
|
|
||||||
// the id and data.
|
|
||||||
func Each(be interface {
|
|
||||||
Lister
|
|
||||||
Getter
|
|
||||||
}, t Type, f func(id ID, data []byte, err error)) error {
|
|
||||||
ids, err := be.List(t)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, id := range ids {
|
|
||||||
data, err := be.Get(t, id)
|
|
||||||
if err != nil {
|
|
||||||
f(id, nil, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
f(id, data, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each lists all entries of type t in the backend and calls function f() with
|
// Each lists all entries of type t in the backend and calls function f() with
|
||||||
// the id.
|
// the id.
|
||||||
func EachID(be Lister, t Type, f func(ID)) error {
|
func EachID(be Lister, t Type, f func(ID)) error {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
@ -32,10 +31,10 @@ func list_keys(s restic.Server) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Each(backend.Key, func(id backend.ID, data []byte, err error) {
|
s.EachID(backend.Key, func(id backend.ID) {
|
||||||
k := restic.Key{}
|
k, err := restic.LoadKey(s, id)
|
||||||
err = json.Unmarshal(data, &k)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "LoadKey() failed: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,17 +33,12 @@ func (cmd CmdList) Execute(args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var t backend.Type
|
||||||
t backend.Type
|
|
||||||
each func(backend.Type, func(backend.ID, []byte, error)) error = s.Each
|
|
||||||
)
|
|
||||||
switch args[0] {
|
switch args[0] {
|
||||||
case "data":
|
case "data":
|
||||||
t = backend.Data
|
t = backend.Data
|
||||||
each = s.EachDecrypted
|
|
||||||
case "trees":
|
case "trees":
|
||||||
t = backend.Tree
|
t = backend.Tree
|
||||||
each = s.EachDecrypted
|
|
||||||
case "snapshots":
|
case "snapshots":
|
||||||
t = backend.Snapshot
|
t = backend.Snapshot
|
||||||
case "keys":
|
case "keys":
|
||||||
|
@ -54,11 +49,7 @@ func (cmd CmdList) Execute(args []string) error {
|
||||||
return errors.New("invalid type")
|
return errors.New("invalid type")
|
||||||
}
|
}
|
||||||
|
|
||||||
return each(t, func(id backend.ID, data []byte, err error) {
|
return s.EachID(t, func(id backend.ID) {
|
||||||
if t == backend.Data || t == backend.Tree {
|
|
||||||
fmt.Printf("%s %s\n", id, backend.Hash(data))
|
|
||||||
} else {
|
|
||||||
fmt.Printf("%s\n", id)
|
fmt.Printf("%s\n", id)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
28
key.go
28
key.go
|
@ -84,15 +84,7 @@ func CreateKey(s Server, password string) (*Key, error) {
|
||||||
|
|
||||||
// OpenKey tries do decrypt the key specified by id with the given password.
|
// OpenKey tries do decrypt the key specified by id with the given password.
|
||||||
func OpenKey(s Server, id backend.ID, password string) (*Key, error) {
|
func OpenKey(s Server, id backend.ID, password string) (*Key, error) {
|
||||||
// extract data from repo
|
k, err := LoadKey(s, id)
|
||||||
data, err := s.Get(backend.Key, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore json
|
|
||||||
k := &Key{}
|
|
||||||
err = json.Unmarshal(data, k)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -148,6 +140,24 @@ func SearchKey(s Server, password string) (*Key, error) {
|
||||||
return nil, ErrNoKeyFound
|
return nil, ErrNoKeyFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadKey loads a key from the backend.
|
||||||
|
func LoadKey(s Server, id backend.ID) (*Key, error) {
|
||||||
|
// extract data from repo
|
||||||
|
data, err := s.Get(backend.Key, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore json
|
||||||
|
k := &Key{}
|
||||||
|
err = json.Unmarshal(data, k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return k, err
|
||||||
|
}
|
||||||
|
|
||||||
// AddKey adds a new key to an already existing repository.
|
// AddKey adds a new key to an already existing repository.
|
||||||
func AddKey(s Server, password string, template *Key) (*Key, error) {
|
func AddKey(s Server, password string, template *Key) (*Key, error) {
|
||||||
// fill meta data about key
|
// fill meta data about key
|
||||||
|
|
60
server.go
60
server.go
|
@ -26,12 +26,6 @@ func NewServerWithKey(be backend.Backend, key *Key) Server {
|
||||||
return Server{be: be, key: key}
|
return Server{be: be, key: key}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each lists all entries of type t in the backend and calls function f() with
|
|
||||||
// the id and data.
|
|
||||||
func (s Server) Each(t backend.Type, f func(id backend.ID, data []byte, err error)) error {
|
|
||||||
return backend.Each(s.be, t, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each lists all entries of type t in the backend and calls function f() with
|
// Each lists all entries of type t in the backend and calls function f() with
|
||||||
// the id.
|
// the id.
|
||||||
func (s Server) EachID(t backend.Type, f func(backend.ID)) error {
|
func (s Server) EachID(t backend.Type, f func(backend.ID)) error {
|
||||||
|
@ -348,27 +342,53 @@ func (s Server) Key() *Key {
|
||||||
return s.key
|
return s.key
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each calls Each() with the given parameters, Decrypt() on the ciphertext
|
type ServerStats struct {
|
||||||
// and, on successful decryption, f with the plaintext.
|
Blobs, Trees uint
|
||||||
func (s Server) EachDecrypted(t backend.Type, f func(backend.ID, []byte, error)) error {
|
Bytes uint64
|
||||||
if s.key == nil {
|
}
|
||||||
return errors.New("key for server not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return s.Each(t, func(id backend.ID, data []byte, e error) {
|
// Stats returns statistics for this backend and the server.
|
||||||
if e != nil {
|
func (s Server) Stats() (ServerStats, error) {
|
||||||
f(id, nil, e)
|
blobs := backend.NewIDSet()
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf, err := s.key.Decrypt([]byte{}, data)
|
// load all trees, in parallel
|
||||||
|
worker := func(wg *sync.WaitGroup, c <-chan backend.ID) {
|
||||||
|
for id := range c {
|
||||||
|
tree, err := LoadTree(s, id)
|
||||||
|
// ignore error and advance to next tree
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f(id, nil, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f(id, buf, nil)
|
for _, id := range tree.Map.StorageIDs() {
|
||||||
|
blobs.Insert(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
idCh := make(chan backend.ID)
|
||||||
|
|
||||||
|
// start workers
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < maxConcurrency; i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go worker(&wg, idCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
// list ids
|
||||||
|
trees := 0
|
||||||
|
err := s.EachID(backend.Tree, func(id backend.ID) {
|
||||||
|
trees++
|
||||||
|
idCh <- id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
close(idCh)
|
||||||
|
|
||||||
|
// wait for workers
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
return ServerStats{Blobs: uint(blobs.Len()), Trees: uint(trees)}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proxy methods to backend
|
// Proxy methods to backend
|
||||||
|
|
|
@ -123,3 +123,18 @@ func BenchmarkSaveFrom(t *testing.B) {
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerStats(t *testing.T) {
|
||||||
|
be := setupBackend(t)
|
||||||
|
defer teardownBackend(t, be)
|
||||||
|
key := setupKey(t, be, "geheim")
|
||||||
|
server := restic.NewServerWithKey(be, key)
|
||||||
|
|
||||||
|
// archive a few files
|
||||||
|
sn := snapshot(t, server, *benchArchiveDirectory)
|
||||||
|
t.Logf("archived snapshot %v", sn.ID)
|
||||||
|
|
||||||
|
stats, err := server.Stats()
|
||||||
|
ok(t, err)
|
||||||
|
t.Logf("stats: %v", stats)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue