lotus/cmd/lotus-shed/bitfield.go

347 lines
6.8 KiB
Go
Raw Normal View History

2020-04-28 08:41:59 +00:00
package main
import (
"encoding/base64"
"encoding/hex"
"fmt"
2020-09-18 00:38:30 +00:00
"io"
2020-04-28 08:41:59 +00:00
"os"
"github.com/urfave/cli/v2"
2020-06-05 22:59:01 +00:00
"golang.org/x/xerrors"
2020-04-28 08:41:59 +00:00
"github.com/filecoin-project/go-bitfield"
2020-04-28 08:41:59 +00:00
rlepluslazy "github.com/filecoin-project/go-bitfield/rle"
)
var bitFieldCmd = &cli.Command{
Name: "bitfield",
2020-11-28 13:44:12 +00:00
Usage: "Bitfield analyze tool",
2020-04-28 08:41:59 +00:00
Description: "analyze bitfields",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "enc",
Value: "base64",
Usage: "specify input encoding to parse",
},
},
Subcommands: []*cli.Command{
2020-11-28 13:44:12 +00:00
bitFieldEncodeCmd,
bitFieldDecodeCmd,
2020-11-28 13:54:30 +00:00
bitFieldRunsCmd,
bitFieldStatCmd,
bitFieldMergeCmd,
2020-09-17 17:57:42 +00:00
bitFieldIntersectCmd,
2020-09-18 00:38:30 +00:00
bitFieldSubCmd,
2020-04-28 08:41:59 +00:00
},
}
var bitFieldRunsCmd = &cli.Command{
Name: "runs",
2020-11-28 12:17:56 +00:00
Usage: "Bitfield bit runs",
2020-04-28 08:41:59 +00:00
Description: "print bit runs in a bitfield",
Action: func(cctx *cli.Context) error {
2020-11-28 13:44:12 +00:00
dec, err := decodeToByte(cctx, 0)
if err != nil {
return err
2020-04-28 08:41:59 +00:00
}
rle, err := rlepluslazy.FromBuf(dec)
if err != nil {
return xerrors.Errorf("opening rle: %w", err)
}
rit, err := rle.RunIterator()
if err != nil {
return xerrors.Errorf("getting run iterator: %w", err)
}
var idx uint64
for rit.HasNext() {
r, err := rit.NextRun()
if err != nil {
return xerrors.Errorf("next run: %w", err)
}
if !r.Valid() {
fmt.Print("!INVALID ")
}
s := "TRUE "
if !r.Val {
s = "FALSE"
}
2020-11-28 12:17:56 +00:00
fmt.Printf("@%08d %s * %d\n", idx, s, r.Len)
2020-04-28 08:41:59 +00:00
idx += r.Len
}
return nil
},
}
var bitFieldStatCmd = &cli.Command{
Name: "stat",
2020-11-28 12:03:26 +00:00
Usage: "Bitfield stats",
2020-04-28 08:41:59 +00:00
Description: "print bitfield stats",
Action: func(cctx *cli.Context) error {
2020-11-28 13:44:12 +00:00
dec, err := decodeToByte(cctx, 0)
if err != nil {
return err
2020-04-28 08:41:59 +00:00
}
2020-11-28 12:03:26 +00:00
fmt.Printf("Raw length: %d bits (%d bytes)\n", len(dec)*8, len(dec))
2020-04-28 08:41:59 +00:00
rle, err := rlepluslazy.FromBuf(dec)
if err != nil {
return xerrors.Errorf("opening rle: %w", err)
}
rit, err := rle.RunIterator()
if err != nil {
return xerrors.Errorf("getting run iterator: %w", err)
}
var ones, zeros, oneRuns, zeroRuns, invalid uint64
for rit.HasNext() {
r, err := rit.NextRun()
if err != nil {
return xerrors.Errorf("next run: %w", err)
}
if !r.Valid() {
invalid++
}
if r.Val {
ones += r.Len
oneRuns++
} else {
zeros += r.Len
zeroRuns++
}
}
if _, err := rle.Count(); err != nil { // check overflows
fmt.Println("Error: ", err)
}
2020-04-28 08:41:59 +00:00
fmt.Printf("Decoded length: %d bits\n", ones+zeros)
fmt.Printf("\tOnes: %d\n", ones)
fmt.Printf("\tZeros: %d\n", zeros)
fmt.Printf("Runs: %d\n", oneRuns+zeroRuns)
fmt.Printf("\tOne Runs: %d\n", oneRuns)
fmt.Printf("\tZero Runs: %d\n", zeroRuns)
fmt.Printf("Invalid runs: %d\n", invalid)
return nil
},
}
var bitFieldDecodeCmd = &cli.Command{
Name: "decode",
2020-11-28 11:14:48 +00:00
Usage: "Bitfield to decimal number",
Description: "decode bitfield and print all numbers in it",
Action: func(cctx *cli.Context) error {
2020-09-17 17:57:42 +00:00
rle, err := decode(cctx, 0)
if err != nil {
return err
}
2020-09-17 17:57:42 +00:00
vals, err := rle.All(100000000000)
if err != nil {
return xerrors.Errorf("getting all items: %w", err)
}
2020-09-17 17:57:42 +00:00
fmt.Println(vals)
return nil
},
}
2020-11-28 13:54:30 +00:00
var bitFieldMergeCmd = &cli.Command{
Name: "merge",
Usage: "Merge 2 bitfields",
Description: "Merge 2 bitfields and print the resulting bitfield",
Action: func(cctx *cli.Context) error {
a, err := decode(cctx, 0)
if err != nil {
return err
}
b, err := decode(cctx, 1)
if err != nil {
return err
}
o, err := bitfield.MergeBitFields(a, b)
if err != nil {
return xerrors.Errorf("merge: %w", err)
}
str, err := encode(cctx, o)
if err != nil {
return err
}
fmt.Println(str)
return nil
},
}
2020-09-17 17:57:42 +00:00
var bitFieldIntersectCmd = &cli.Command{
Name: "intersect",
2020-11-28 13:44:12 +00:00
Usage: "Intersect 2 bitfields",
Description: "intersect 2 bitfields and print the resulting bitfield",
2020-09-17 17:57:42 +00:00
Action: func(cctx *cli.Context) error {
2020-11-28 13:07:14 +00:00
a, err := decode(cctx, 0)
if err != nil {
2020-09-17 17:57:42 +00:00
return err
}
2020-11-28 13:07:14 +00:00
b, err := decode(cctx, 1)
if err != nil {
2020-09-17 17:57:42 +00:00
return err
}
o, err := bitfield.IntersectBitField(a, b)
if err != nil {
return xerrors.Errorf("intersect: %w", err)
}
2020-11-28 13:07:14 +00:00
str, err := encode(cctx, o)
2020-09-17 17:57:42 +00:00
if err != nil {
return err
}
2020-11-28 13:07:14 +00:00
fmt.Println(str)
2020-09-18 00:38:30 +00:00
return nil
},
}
var bitFieldSubCmd = &cli.Command{
Name: "sub",
2020-11-28 13:44:12 +00:00
Usage: "Subtract 2 bitfields",
Description: "subtract 2 bitfields and print the resulting bitfield",
2020-09-18 00:38:30 +00:00
Action: func(cctx *cli.Context) error {
2020-11-28 13:44:12 +00:00
a, err := decode(cctx, 0)
2020-09-18 00:38:30 +00:00
if err != nil {
return err
}
2020-11-28 13:44:12 +00:00
b, err := decode(cctx, 1)
2020-09-18 00:38:30 +00:00
if err != nil {
return err
}
o, err := bitfield.SubtractBitField(a, b)
if err != nil {
2020-11-28 13:44:12 +00:00
return xerrors.Errorf("subtract: %w", err)
2020-09-18 00:38:30 +00:00
}
2020-11-28 13:44:12 +00:00
str, err := encode(cctx, o)
2020-09-18 00:38:30 +00:00
if err != nil {
return err
}
2020-11-28 13:44:12 +00:00
fmt.Println(str)
2020-09-18 00:38:30 +00:00
return nil
},
}
var bitFieldEncodeCmd = &cli.Command{
Name: "encode",
2020-11-28 09:29:15 +00:00
Usage: "Decimal number to bitfield",
2020-09-18 00:38:30 +00:00
Description: "encode a series of decimal numbers into a bitfield",
2020-09-18 00:40:01 +00:00
ArgsUsage: "[infile]",
2020-09-18 00:38:30 +00:00
Action: func(cctx *cli.Context) error {
f, err := os.Open(cctx.Args().First())
if err != nil {
return err
}
2020-09-18 01:00:31 +00:00
defer f.Close() // nolint
2020-09-18 00:38:30 +00:00
out := bitfield.New()
for {
var i uint64
_, err := fmt.Fscan(f, &i)
if err == io.EOF {
break
}
out.Set(i)
}
2020-11-28 12:56:16 +00:00
str, err := encode(cctx, out)
2020-09-18 00:38:30 +00:00
if err != nil {
return err
}
2020-11-28 12:56:16 +00:00
fmt.Println(str)
return nil
},
}
2020-09-17 17:57:42 +00:00
2020-11-28 12:56:16 +00:00
func encode(cctx *cli.Context, field bitfield.BitField) (string, error) {
s, err := field.RunIterator()
if err != nil {
return "", err
}
bytes, err := rlepluslazy.EncodeRuns(s, []byte{})
if err != nil {
return "", err
}
var str string
switch cctx.String("enc") {
case "base64":
str = base64.StdEncoding.EncodeToString(bytes)
case "hex":
str = hex.EncodeToString(bytes)
default:
return "", fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
}
return str, nil
}
2020-11-28 11:14:48 +00:00
func decode(cctx *cli.Context, i int) (bitfield.BitField, error) {
2020-11-28 13:44:12 +00:00
b, err := decodeToByte(cctx, i)
if err != nil {
return bitfield.BitField{}, err
}
return bitfield.NewFromBytes(b)
}
func decodeToByte(cctx *cli.Context, i int) ([]byte, error) {
2020-09-17 17:57:42 +00:00
var val string
if cctx.Args().Present() {
2020-11-28 11:14:48 +00:00
if i >= cctx.NArg() {
2020-11-28 13:44:12 +00:00
return nil, xerrors.Errorf("need more than %d args", i)
2020-09-17 17:57:42 +00:00
}
2020-11-28 11:14:48 +00:00
val = cctx.Args().Get(i)
2020-09-17 17:57:42 +00:00
} else {
2020-11-28 11:14:48 +00:00
if i > 0 {
2020-11-28 13:44:12 +00:00
return nil, xerrors.Errorf("need more than %d args", i)
2020-09-17 17:57:42 +00:00
}
r, err := io.ReadAll(os.Stdin)
2020-09-17 17:57:42 +00:00
if err != nil {
2020-11-28 13:44:12 +00:00
return nil, err
2020-09-17 17:57:42 +00:00
}
2020-11-28 13:44:12 +00:00
val = string(r)
2020-09-17 17:57:42 +00:00
}
var dec []byte
switch cctx.String("enc") {
case "base64":
d, err := base64.StdEncoding.DecodeString(val)
if err != nil {
2020-11-28 13:44:12 +00:00
return nil, fmt.Errorf("decoding base64 value: %w", err)
2020-09-17 17:57:42 +00:00
}
dec = d
case "hex":
d, err := hex.DecodeString(val)
if err != nil {
2020-11-28 13:44:12 +00:00
return nil, fmt.Errorf("decoding hex value: %w", err)
2020-09-17 17:57:42 +00:00
}
dec = d
default:
2020-11-28 13:44:12 +00:00
return nil, fmt.Errorf("unrecognized encoding: %s", cctx.String("enc"))
2020-09-17 17:57:42 +00:00
}
2020-11-28 13:44:12 +00:00
return dec, nil
2020-09-17 17:57:42 +00:00
}