提交 79b388c6 作者: Hector Sanjuan

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: 's avatarHector Sanjuan <hector@protocol.ai>
上级 e7938a18
......@@ -150,14 +150,20 @@ var repoStatCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Get stats for the currently used repo.",
ShortDescription: `
'ipfs repo stat' is a plumbing command that will scan the local
set of stored objects and print repo statistics. It outputs to stdout:
'ipfs repo stat' provides information about the local set of
stored objects. It outputs:
RepoSize int Size in bytes that the repo is currently taking.
StorageMax string Maximum datastore size (from configuration)
NumObjects int Number of objects in the local repo.
RepoPath string The path to the repo being currently used.
RepoSize int Size in bytes that the repo is currently taking.
Version string The repo version.
`,
},
Options: []cmdkit.Option{
cmdkit.BoolOption("size-only", "Only report RepoSize and StorageMax."),
cmdkit.BoolOption("human", "Output sizes in MiB."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
n, err := GetNode(env)
if err != nil {
......@@ -165,7 +171,14 @@ Version string The repo version.
return
}
stat, err := corerepo.RepoStat(n, req.Context)
statF := corerepo.RepoStat
sizeOnly, _ := req.Options["size-only"].(bool)
if sizeOnly {
statF = corerepo.RepoSize
}
stat, err := statF(req.Context, n)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
......@@ -173,9 +186,6 @@ Version string The repo version.
cmds.EmitOnce(res, stat)
},
Options: []cmdkit.Option{
cmdkit.BoolOption("human", "Output RepoSize in MiB."),
},
Type: corerepo.Stat{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
......@@ -184,17 +194,19 @@ Version string The repo version.
return e.TypeErr(stat, v)
}
human, _ := req.Options["human"].(bool)
wtr := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
defer wtr.Flush()
human, _ := req.Options["human"].(bool)
sizeOnly, _ := req.Options["size-only"].(bool)
fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects)
sizeInMiB := stat.RepoSize / (1024 * 1024)
if human && sizeInMiB > 0 {
fmt.Fprintf(wtr, "RepoSize (MiB):\t%d\n", sizeInMiB)
} else {
fmt.Fprintf(wtr, "RepoSize:\t%d\n", stat.RepoSize)
}
if stat.StorageMax != corerepo.NoLimit {
maxSizeInMiB := stat.StorageMax / (1024 * 1024)
if human && maxSizeInMiB > 0 {
......@@ -203,9 +215,14 @@ Version string The repo version.
fmt.Fprintf(wtr, "StorageMax:\t%d\n", stat.StorageMax)
}
}
if sizeOnly {
return nil
}
fmt.Fprintf(wtr, "NumObjects:\t%d\n", stat.NumObjects)
fmt.Fprintf(wtr, "RepoPath:\t%s\n", stat.RepoPath)
fmt.Fprintf(wtr, "Version:\t%s\n", stat.Version)
wtr.Flush()
return nil
......
......@@ -5,27 +5,28 @@ import (
"math"
context "context"
"github.com/ipfs/go-ipfs/core"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
)
// Stat wraps information about the objects stored on disk.
type Stat struct {
NumObjects uint64
RepoSize uint64 // size in bytes
StorageMax uint64 // size in bytes
NumObjects uint64
RepoPath string
Version string
StorageMax uint64 // size in bytes
}
// NoLimit represents the value for unlimited storage
const NoLimit uint64 = math.MaxUint64
func RepoStat(n *core.IpfsNode, ctx context.Context) (*Stat, error) {
r := n.Repo
usage, err := r.GetStorageUsage()
// RepoStat returns a *Stat object with all the fields set.
func RepoStat(ctx context.Context, n *core.IpfsNode) (*Stat, error) {
sizeStat, err := RepoSize(ctx, n)
if err != nil {
return nil, err
}
......@@ -45,11 +46,29 @@ func RepoStat(n *core.IpfsNode, ctx context.Context) (*Stat, error) {
return nil, err
}
return &Stat{
NumObjects: count,
RepoSize: sizeStat.RepoSize,
StorageMax: sizeStat.StorageMax,
RepoPath: path,
Version: fmt.Sprintf("fs-repo@%d", fsrepo.RepoVersion),
}, nil
}
// RepoSize returns a *Stat object with the RepoSize and StorageMax fields set.
func RepoSize(ctx context.Context, n *core.IpfsNode) (*Stat, error) {
r := n.Repo
cfg, err := r.Config()
if err != nil {
return nil, err
}
usage, err := r.GetStorageUsage()
if err != nil {
return nil, err
}
storageMax := NoLimit
if cfg.Datastore.StorageMax != "" {
storageMax, err = humanize.ParseBytes(cfg.Datastore.StorageMax)
......@@ -59,10 +78,7 @@ func RepoStat(n *core.IpfsNode, ctx context.Context) (*Stat, error) {
}
return &Stat{
NumObjects: count,
RepoSize: usage,
RepoPath: path,
Version: fmt.Sprintf("fs-repo@%d", fsrepo.RepoVersion),
StorageMax: storageMax,
}, nil
}
......@@ -27,6 +27,7 @@ import (
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
lockfile "gx/ipfs/QmYzCZUe9CBDkyPNPcRNqXQK8KKhtUfXvc88PkFujAEJPe/go-fs-lock"
logging "gx/ipfs/QmcVVHfdyv15GVPk7NrxdWjh2hLVccXnoD8j2tyQShiXJb/go-log"
ds "gx/ipfs/QmeiCcJfDW1GJnWUArudsv5rQsihpi4oyddPhdqo3CfX6i/go-datastore"
)
// LockFile is the filename of the repo lock, relative to config dir
......@@ -672,29 +673,7 @@ func (r *FSRepo) Datastore() repo.Datastore {
// GetStorageUsage computes the storage space taken by the repo in bytes
func (r *FSRepo) GetStorageUsage() (uint64, error) {
pth, err := config.PathRoot()
if err != nil {
return 0, err
}
pth, err = filepath.EvalSymlinks(pth)
if err != nil {
log.Debugf("filepath.EvalSymlinks error: %s", err)
return 0, err
}
var du uint64
err = filepath.Walk(pth, func(p string, f os.FileInfo, err error) error {
if err != nil {
log.Debugf("filepath.Walk error: %s", err)
return nil
}
if f != nil {
du += uint64(f.Size())
}
return nil
})
return du, err
return ds.DiskUsage(r.Datastore())
}
func (r *FSRepo) SwarmKey() ([]byte, error) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论