@cryptotaxi247 / kubo / commits / 79b388c69

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) {