未验证 提交 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() { ...@@ -64,6 +64,7 @@ func main() {
gatewayFlags(), gatewayFlags(),
syncFlags(), syncFlags(),
rmrFlags(), rmrFlags(),
infoFlags(),
benchmarkFlags(), benchmarkFlags(),
gcFlags(), gcFlags(),
checkFlags(), checkFlags(),
......
...@@ -23,6 +23,7 @@ COMMANDS: ...@@ -23,6 +23,7 @@ COMMANDS:
gateway S3-compatible gateway gateway S3-compatible gateway
sync sync between two storage sync sync between two storage
rmr remove directories recursively rmr remove directories recursively
info show internal information for paths or inodes
benchmark run benchmark, including read/write/stat big/small files benchmark run benchmark, including read/write/stat big/small files
gc collect any leaked objects gc collect any leaked objects
fsck Check consistency of file system fsck Check consistency of file system
...@@ -306,6 +307,24 @@ Remove all files in directories recursively. ...@@ -306,6 +307,24 @@ Remove all files in directories recursively.
juicefs rmr PATH ... 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 ## juicefs benchmark
### Description ### Description
......
...@@ -28,6 +28,8 @@ const ( ...@@ -28,6 +28,8 @@ const (
CompactChunk = 1001 CompactChunk = 1001
// Rmr is a message to remove a directory recursively. // Rmr is a message to remove a directory recursively.
Rmr = 1002 Rmr = 1002
// Info is a message to get the internal info for file or directory.
Info = 1003
) )
const ( const (
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package vfs package vfs
import ( import (
"bytes"
"fmt"
"os" "os"
"syscall" "syscall"
"time" "time"
...@@ -107,6 +109,36 @@ func handleInternalMsg(ctx Context, msg []byte) []byte { ...@@ -107,6 +109,36 @@ func handleInternalMsg(ctx Context, msg []byte) []byte {
name := string(r.Get(int(r.Get8()))) name := string(r.Get(int(r.Get8())))
r := m.Rmr(ctx, inode, name) r := m.Rmr(ctx, inode, name)
return []byte{uint8(r)} 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: default:
logger.Warnf("unknown message type: %d", cmd) logger.Warnf("unknown message type: %d", cmd)
return []byte{uint8(syscall.EINVAL & 0xff)} return []byte{uint8(syscall.EINVAL & 0xff)}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册