From 2018a146b87fd2fccb5fb4e73ca25d42dc11dece Mon Sep 17 00:00:00 2001 From: Davies Liu Date: Fri, 9 Apr 2021 11:01:52 +0800 Subject: [PATCH] Show internal information for dir/files (#288) * Add info to show internal infomation for directory or file Signed-off-by: swj <1186093704@qq.com> * show internal information for files, add docs Co-authored-by: swj <1186093704@qq.com> --- cmd/info.go | 108 +++++++++++++++++++++++++++++++++++ cmd/main.go | 1 + docs/en/command_reference.md | 19 ++++++ pkg/meta/interface.go | 2 + pkg/vfs/internal.go | 32 +++++++++++ 5 files changed, 162 insertions(+) create mode 100644 cmd/info.go diff --git a/cmd/info.go b/cmd/info.go new file mode 100644 index 00000000..ae47b36a --- /dev/null +++ b/cmd/info.go @@ -0,0 +1,108 @@ +/* + * JuiceFS, Copyright (C) 2020 Juicedata, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package main + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strconv" + + "github.com/juicedata/juicefs/pkg/meta" + "github.com/juicedata/juicefs/pkg/utils" + "github.com/urfave/cli/v2" +) + +func infoFlags() *cli.Command { + return &cli.Command{ + Name: "info", + Usage: "show internal information for paths or inodes", + ArgsUsage: "PATH or INODE", + Action: info, + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "inode", + Aliases: []string{"i"}, + Usage: "use inode instead of path (current dir should be inside JuiceFS)", + }, + }, + } +} + +func info(ctx *cli.Context) error { + if runtime.GOOS == "windows" { + logger.Infof("Windows is not supported") + return nil + } + if ctx.Args().Len() < 1 { + logger.Infof("DIR or FILE is needed") + return nil + } + for i := 0; i < ctx.Args().Len(); i++ { + path := ctx.Args().Get(i) + var d string + var inode uint64 + var err error + if ctx.Bool("inode") { + inode, err = strconv.ParseUint(path, 10, 64) + d, _ = os.Getwd() + } else { + d, err = filepath.Abs(path) + if err != nil { + logger.Fatalf("abs of %s: %s", path, err) + } + inode, err = utils.GetFileInode(d) + } + if err != nil { + logger.Errorf("lookup inode for %s: %s", path, err) + continue + } + + f := openControler(d) + if f == nil { + logger.Errorf("%s is not inside JuiceFS", path) + continue + } + + wb := utils.NewBuffer(8 + 8) + wb.Put32(meta.Info) + wb.Put32(8) + wb.Put64(inode) + _, err = f.Write(wb.Bytes()) + if err != nil { + logger.Fatalf("write message: %s", err) + } + + data := make([]byte, 4) + n, err := f.Read(data) + if err != nil { + logger.Fatalf("read size: %d %s", n, err) + } + r := utils.ReadBuffer(data) + size := r.Get32() + data = make([]byte, size) + n, err = f.Read(data) + if err != nil { + logger.Fatalf("read info: %s", err) + } + fmt.Println(path, ":") + fmt.Println(string(data[:n])) + _ = f.Close() + } + + return nil +} diff --git a/cmd/main.go b/cmd/main.go index d523ddd3..76cf209f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -64,6 +64,7 @@ func main() { gatewayFlags(), syncFlags(), rmrFlags(), + infoFlags(), benchmarkFlags(), gcFlags(), checkFlags(), diff --git a/docs/en/command_reference.md b/docs/en/command_reference.md index ccdeb826..186c5cdf 100644 --- a/docs/en/command_reference.md +++ b/docs/en/command_reference.md @@ -23,6 +23,7 @@ COMMANDS: gateway S3-compatible gateway sync sync between two storage rmr remove directories recursively + info show internal information for paths or inodes benchmark run benchmark, including read/write/stat big/small files gc collect any leaked objects fsck Check consistency of file system @@ -306,6 +307,24 @@ Remove all files in directories recursively. juicefs rmr PATH ... ``` +## juicefs info + +### Description + +Show internal information for given paths or inodes. + +### Synopsis + +``` +juicefs info [command options] PATH or INODE +``` + +### Options + +`--inode, -i`\ +use inode instead of path (current dir should be inside JuiceFS) (default: `false`) + + ## juicefs benchmark ### Description diff --git a/pkg/meta/interface.go b/pkg/meta/interface.go index 6f8fe59f..1aa71d03 100644 --- a/pkg/meta/interface.go +++ b/pkg/meta/interface.go @@ -28,6 +28,8 @@ const ( CompactChunk = 1001 // Rmr is a message to remove a directory recursively. Rmr = 1002 + // Info is a message to get the internal info for file or directory. + Info = 1003 ) const ( diff --git a/pkg/vfs/internal.go b/pkg/vfs/internal.go index 900ffb76..7e374f9d 100644 --- a/pkg/vfs/internal.go +++ b/pkg/vfs/internal.go @@ -16,6 +16,8 @@ package vfs import ( + "bytes" + "fmt" "os" "syscall" "time" @@ -107,6 +109,36 @@ func handleInternalMsg(ctx Context, msg []byte) []byte { name := string(r.Get(int(r.Get8()))) r := m.Rmr(ctx, inode, name) return []byte{uint8(r)} + case meta.Info: + var summary meta.Summary + inode := Ino(r.Get64()) + + wb := utils.NewBuffer(4) + r := m.Summary(ctx, inode, &summary) + if r != 0 { + msg := r.Error() + wb.Put32(uint32(len(msg))) + return append(wb.Bytes(), []byte(msg)...) + } + var w = bytes.NewBuffer(nil) + fmt.Fprintf(w, " inode: %d\n", inode) + fmt.Fprintf(w, " files:\t%d\n", summary.Files) + fmt.Fprintf(w, " dirs:\t%d\n", summary.Dirs) + fmt.Fprintf(w, " length:\t%d\n", summary.Length) + fmt.Fprintf(w, " size:\t%d\n", summary.Size) + + if summary.Files == 1 && summary.Dirs == 0 { + fmt.Fprintf(w, " chunks:\n") + for indx := uint64(0); indx*meta.ChunkSize < summary.Length; indx++ { + var cs []meta.Slice + _ = m.Read(ctx, inode, uint32(indx), &cs) + for _, c := range cs { + fmt.Fprintf(w, "\t%d:\t%d\t%d\t%d\t%d\n", indx, c.Chunkid, c.Size, c.Off, c.Size) + } + } + } + wb.Put32(uint32(w.Len())) + return append(wb.Bytes(), w.Bytes()...) default: logger.Warnf("unknown message type: %d", cmd) return []byte{uint8(syscall.EINVAL & 0xff)} -- GitLab