未验证 提交 2018a146 编写于 作者: D Davies Liu 提交者: GitHub

Show internal information for dir/files (#288)

* Add info to show internal infomation for directory or file
Signed-off-by: Nswj <1186093704@qq.com>

* show internal information for files, add docs
Co-authored-by: Nswj <1186093704@qq.com>
上级 3dc93718
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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
}
......@@ -64,6 +64,7 @@ func main() {
gatewayFlags(),
syncFlags(),
rmrFlags(),
infoFlags(),
benchmarkFlags(),
gcFlags(),
checkFlags(),
......
......@@ -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
......
......@@ -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 (
......
......@@ -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)}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册