Feat: use datastore.DiskUsage() and add --size-only to "repo stat"
This makes use of the PersistentDatastore DiskUsage method to obtain the Repo's storage usage (GetStorageUsage()). Additionally, the --size-only flag has been added to the "ipfs repo stat" command. This avoids counting the number of objects in the repository and returns faster. License: MIT Signed-off-by: Hector Sanjuan <hector@protocol.ai>
Hector Sanjuan committed
Jan 5, 2018 at 17:52 UTC
79b388c690afec7d25813caf945c6ab27e4b6ee3
3 files changed
+55
-43
core/commands/repo.go
+28
-11
@@ -150,14 +150,20 @@ var repoStatCmd = &cmds.Command{
150
Helptext: cmdkit.HelpText{
151
Tagline: "Get stats for the currently used repo.",
152
ShortDescription: `
153
-'ipfs repo stat' is a plumbing command that will scan the local
154
-set of stored objects and print repo statistics. It outputs to stdout:
153
+'ipfs repo stat' provides information about the local set of
154
+stored objects. It outputs:
155
+
156
+RepoSize int Size in bytes that the repo is currently taking.
157
+StorageMax string Maximum datastore size (from configuration)
158
NumObjects int Number of objects in the local repo.
159
RepoPath string The path to the repo being currently used.
157
-RepoSize int Size in bytes that the repo is currently taking.
160
Version string The repo version.
161
`,
162
},
163
+ Options: []cmdkit.Option{
164
+ cmdkit.BoolOption("size-only", "Only report RepoSize and StorageMax."),
165
+ cmdkit.BoolOption("human", "Output sizes in MiB."),
166
+ },
167
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
168
n, err := GetNode(env)
169
if err != nil {
@@ -165,7 +171,14 @@ Version string The repo version.
171
return
172
}
173
168
- stat, err := corerepo.RepoStat(n, req.Context)
174
+ statF := corerepo.RepoStat
175
+
176
+ sizeOnly, _ := req.Options["size-only"].(bool)
177
+ if sizeOnly {
178
+ statF = corerepo.RepoSize
179
+ }
180
+
181
+ stat, err := statF(req.Context, n)
182
if err != nil {
183
res.SetError(err, cmdkit.ErrNormal)
184
return
@@ -173,9 +186,6 @@ Version string The repo version.
186
187
cmds.EmitOnce(res, stat)
188
},
176
- Options: []cmdkit.Option{
177
- cmdkit.BoolOption("human", "Output RepoSize in MiB."),
178
- },
189
Type: corerepo.Stat{},
190
Encoders: cmds.EncoderMap{
191
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
@@ -184,17 +194,19 @@ Version string The repo version.
194
return e.TypeErr(stat, v)
195
}
196
187
- human, _ := req.Options["human"].(bool)
188
-
197
wtr := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
198
+ defer wtr.Flush()
199
+
200
+ human, _ := req.Options["human"].(bool)
201
+ sizeOnly, _ := req.Options["size-only"].(bool)
202
191
- fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects)
203
sizeInMiB := stat.RepoSize / (1024 * 1024)
204
if human && sizeInMiB > 0 {
205
fmt.Fprintf(wtr, "RepoSize (MiB):\t%d\n", sizeInMiB)
206
} else {
207
fmt.Fprintf(wtr, "RepoSize:\t%d\n", stat.RepoSize)
208
}
209
+
210
if stat.StorageMax != corerepo.NoLimit {
211
maxSizeInMiB := stat.StorageMax / (1024 * 1024)
212
if human && maxSizeInMiB > 0 {
@@ -203,9 +215,14 @@ Version string The repo version.
215
fmt.Fprintf(wtr, "StorageMax:\t%d\n", stat.StorageMax)
216
}
217
}
218
+
219
+ if sizeOnly {
220
+ return nil
221
+ }
222
+
223
+ fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects)
224
fmt.Fprintf(wtr, "RepoPath:\t%s\n", stat.RepoPath)
225
fmt.Fprintf(wtr, "Version:\t%s\n", stat.Version)
208
- wtr.Flush()
226
227
return nil
228
core/corerepo/stat.go
+25
-9
@@ -5,27 +5,28 @@ import (
5
"math"
6
7
context "context"
8
+
9
"github.com/ipfs/go-ipfs/core"
10
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
11
12
humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
13
)
14
15
+// Stat wraps information about the objects stored on disk.
16
type Stat struct {
15
- NumObjects uint64
17
RepoSize uint64 // size in bytes
18
+ StorageMax uint64 // size in bytes
19
+ NumObjects uint64
20
RepoPath string
21
Version string
19
- StorageMax uint64 // size in bytes
22
}
23
24
// NoLimit represents the value for unlimited storage
25
const NoLimit uint64 = math.MaxUint64
26
25
-func RepoStat(n *core.IpfsNode, ctx context.Context) (*Stat, error) {
26
- r := n.Repo
27
-
28
- usage, err := r.GetStorageUsage()
27
+// RepoStat returns a *Stat object with all the fields set.
28
+func RepoStat(ctx context.Context, n *core.IpfsNode) (*Stat, error) {
29
+ sizeStat, err := RepoSize(ctx, n)
30
if err != nil {
31
return nil, err
32
}
@@ -45,11 +46,29 @@ func RepoStat(n *core.IpfsNode, ctx context.Context) (*Stat, error) {
46
return nil, err
47
}
48
49
+ return &Stat{
50
+ NumObjects: count,
51
+ RepoSize: sizeStat.RepoSize,
52
+ StorageMax: sizeStat.StorageMax,
53
+ RepoPath: path,
54
+ Version: fmt.Sprintf("fs-repo@%d", fsrepo.RepoVersion),
55
+ }, nil
56
+}
57
+
58
+// RepoSize returns a *Stat object with the RepoSize and StorageMax fields set.
59
+func RepoSize(ctx context.Context, n *core.IpfsNode) (*Stat, error) {
60
+ r := n.Repo
61
+
62
cfg, err := r.Config()
63
if err != nil {
64
return nil, err
65
}
66
67
+ usage, err := r.GetStorageUsage()
68
+ if err != nil {
69
+ return nil, err
70
+ }
71
+
72
storageMax := NoLimit
73
if cfg.Datastore.StorageMax != "" {
74
storageMax, err = humanize.ParseBytes(cfg.Datastore.StorageMax)
@@ -59,10 +78,7 @@ func RepoStat(n *core.IpfsNode, ctx context.Context) (*Stat, error) {
78
}
79
80
return &Stat{
62
- NumObjects: count,
81
RepoSize: usage,
64
- RepoPath: path,
65
- Version: fmt.Sprintf("fs-repo@%d", fsrepo.RepoVersion),
82
StorageMax: storageMax,
83
}, nil
84
}
repo/fsrepo/fsrepo.go
+2
-23
@@ -27,6 +27,7 @@ import (
27
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
28
lockfile "gx/ipfs/QmYzCZUe9CBDkyPNPcRNqXQK8KKhtUfXvc88PkFujAEJPe/go-fs-lock"
29
logging "gx/ipfs/QmcVVHfdyv15GVPk7NrxdWjh2hLVccXnoD8j2tyQShiXJb/go-log"
30
+ ds "gx/ipfs/QmeiCcJfDW1GJnWUArudsv5rQsihpi4oyddPhdqo3CfX6i/go-datastore"
31
)
32
33
// LockFile is the filename of the repo lock, relative to config dir
@@ -672,29 +673,7 @@ func (r *FSRepo) Datastore() repo.Datastore {
673
674
// GetStorageUsage computes the storage space taken by the repo in bytes
675
func (r *FSRepo) GetStorageUsage() (uint64, error) {
675
- pth, err := config.PathRoot()
676
- if err != nil {
677
- return 0, err
678
- }
679
-
680
- pth, err = filepath.EvalSymlinks(pth)
681
- if err != nil {
682
- log.Debugf("filepath.EvalSymlinks error: %s", err)
683
- return 0, err
684
- }
685
-
686
- var du uint64
687
- err = filepath.Walk(pth, func(p string, f os.FileInfo, err error) error {
688
- if err != nil {
689
- log.Debugf("filepath.Walk error: %s", err)
690
- return nil
691
- }
692
- if f != nil {
693
- du += uint64(f.Size())
694
- }
695
- return nil
696
- })
697
- return du, err
676
+ return ds.DiskUsage(r.Datastore())
677
}
678
679
func (r *FSRepo) SwarmKey() ([]byte, error) {