1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package index
18
19 import (
20 "context"
21 "fmt"
22 "strconv"
23 "strings"
24
25 "perkeep.org/pkg/blob"
26 "perkeep.org/pkg/sorted"
27 )
28
29 func (ix *Index) EnumerateBlobs(ctx context.Context, dest chan<- blob.SizedRef, after string, limit int) (err error) {
30 defer close(dest)
31 it := ix.s.Find("have:"+after, "have~")
32 defer func() {
33 closeErr := it.Close()
34 if err == nil {
35 err = closeErr
36 }
37 }()
38
39 afterKey := "have:" + after
40 n := int(0)
41 for n < limit && it.Next() {
42 k := it.Key()
43 if k <= afterKey {
44 continue
45 }
46 if !strings.HasPrefix(k, "have:") {
47 break
48 }
49 n++
50 br, ok := blob.Parse(k[len("have:"):])
51 if !ok {
52 continue
53 }
54 size, err := parseHaveVal(it.Value())
55 if err == nil {
56 select {
57 case dest <- blob.SizedRef{Ref: br, Size: uint32(size)}:
58 case <-ctx.Done():
59 return ctx.Err()
60 }
61 }
62 }
63 return nil
64 }
65
66 func (ix *Index) StatBlobs(ctx context.Context, blobs []blob.Ref, fn func(blob.SizedRef) error) error {
67 for _, br := range blobs {
68 key := "have:" + br.String()
69 v, err := ix.s.Get(key)
70 if err == sorted.ErrNotFound {
71 continue
72 }
73 if err != nil {
74 return fmt.Errorf("error looking up key %q: %v", key, err)
75 }
76 size, err := parseHaveVal(v)
77 if err != nil {
78 return fmt.Errorf("invalid size for key %q = %q", key, v)
79 }
80 if err := fn(blob.SizedRef{Ref: br, Size: uint32(size)}); err != nil {
81 return err
82 }
83 }
84 return nil
85 }
86
87
88
89
90
91 func parseHaveVal(val string) (size uint64, err error) {
92 pipei := strings.Index(val, "|")
93 if pipei >= 0 {
94
95 val = val[:pipei]
96 }
97 return strconv.ParseUint(val, 10, 32)
98 }