mirror of
https://github.com/ipfs/kubo.git
synced 2025-06-29 01:12:24 +08:00
Merge pull request #5098 from schomatis/feat/unixfs/fsnode-include-pb
unixfs: integrate `pb.Data` into `FSNode` to avoid duplicating fields
This commit is contained in:
@ -116,7 +116,7 @@ func (db *DagBuilderHelper) GetDagServ() ipld.DAGService {
|
|||||||
func (db *DagBuilderHelper) NewUnixfsNode() *UnixfsNode {
|
func (db *DagBuilderHelper) NewUnixfsNode() *UnixfsNode {
|
||||||
n := &UnixfsNode{
|
n := &UnixfsNode{
|
||||||
node: new(dag.ProtoNode),
|
node: new(dag.ProtoNode),
|
||||||
ufmt: &ft.FSNode{Type: ft.TFile},
|
ufmt: ft.NewFSNode(ft.TFile),
|
||||||
}
|
}
|
||||||
n.SetPrefix(db.prefix)
|
n.SetPrefix(db.prefix)
|
||||||
return n
|
return n
|
||||||
@ -161,7 +161,7 @@ func (db *DagBuilderHelper) NewLeaf(data []byte) (*UnixfsNode, error) {
|
|||||||
func (db *DagBuilderHelper) newUnixfsBlock() *UnixfsNode {
|
func (db *DagBuilderHelper) newUnixfsBlock() *UnixfsNode {
|
||||||
n := &UnixfsNode{
|
n := &UnixfsNode{
|
||||||
node: new(dag.ProtoNode),
|
node: new(dag.ProtoNode),
|
||||||
ufmt: &ft.FSNode{Type: ft.TRaw},
|
ufmt: ft.NewFSNode(ft.TRaw),
|
||||||
}
|
}
|
||||||
n.SetPrefix(db.prefix)
|
n.SetPrefix(db.prefix)
|
||||||
return n
|
return n
|
||||||
|
@ -77,7 +77,7 @@ func (n *UnixfsNode) Set(other *UnixfsNode) {
|
|||||||
n.raw = other.raw
|
n.raw = other.raw
|
||||||
n.rawnode = other.rawnode
|
n.rawnode = other.rawnode
|
||||||
if other.ufmt != nil {
|
if other.ufmt != nil {
|
||||||
n.ufmt.Data = other.ufmt.Data
|
n.ufmt.SetData(other.ufmt.GetData())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ func (n *UnixfsNode) RemoveChild(index int, dbh *DagBuilderHelper) {
|
|||||||
|
|
||||||
// SetData stores data in this node.
|
// SetData stores data in this node.
|
||||||
func (n *UnixfsNode) SetData(data []byte) {
|
func (n *UnixfsNode) SetData(data []byte) {
|
||||||
n.ufmt.Data = data
|
n.ufmt.SetData(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSize returns the total file size of this tree (including children)
|
// FileSize returns the total file size of this tree (including children)
|
||||||
|
@ -60,7 +60,7 @@ func (fi *File) Open(flags int, sync bool) (FileDescriptor, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fsn.Type {
|
switch fsn.GetType() {
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported fsnode type for 'file'")
|
return nil, fmt.Errorf("unsupported fsnode type for 'file'")
|
||||||
case ft.TSymlink:
|
case ft.TSymlink:
|
||||||
|
@ -852,7 +852,7 @@ func TestFlushing(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fsnode.Type != ft.TDirectory {
|
if fsnode.GetType() != ft.TDirectory {
|
||||||
t.Fatal("root wasnt a directory")
|
t.Fatal("root wasnt a directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,7 +526,7 @@ func dagTruncate(ctx context.Context, n ipld.Node, size uint64, ds ipld.DAGServi
|
|||||||
var cur uint64
|
var cur uint64
|
||||||
end := 0
|
end := 0
|
||||||
var modified ipld.Node
|
var modified ipld.Node
|
||||||
ndata := new(ft.FSNode)
|
ndata := ft.NewFSNode(ft.TRaw)
|
||||||
for i, lnk := range nd.Links() {
|
for i, lnk := range nd.Links() {
|
||||||
child, err := lnk.GetNode(ctx, ds)
|
child, err := lnk.GetNode(ctx, ds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -139,67 +139,101 @@ func DataSize(data []byte) (uint64, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// An FSNode represents a filesystem object.
|
// An FSNode represents a filesystem object using the UnixFS specification.
|
||||||
|
//
|
||||||
|
// The `NewFSNode` constructor should be used instead of just calling `new(FSNode)`
|
||||||
|
// to guarantee that the required (`Type` and `Filesize`) fields in the `format`
|
||||||
|
// structure are initialized before marshaling (in `GetBytes()`).
|
||||||
type FSNode struct {
|
type FSNode struct {
|
||||||
Data []byte
|
|
||||||
|
|
||||||
// total data size for each child
|
// UnixFS format defined as a protocol buffers message.
|
||||||
blocksizes []uint64
|
format pb.Data
|
||||||
|
|
||||||
// running sum of blocksizes
|
|
||||||
subtotal uint64
|
|
||||||
|
|
||||||
// node type of this node
|
|
||||||
Type pb.Data_DataType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FSNodeFromBytes unmarshal a protobuf message onto an FSNode.
|
// FSNodeFromBytes unmarshal a protobuf message onto an FSNode.
|
||||||
func FSNodeFromBytes(b []byte) (*FSNode, error) {
|
func FSNodeFromBytes(b []byte) (*FSNode, error) {
|
||||||
pbn := new(pb.Data)
|
n := new(FSNode)
|
||||||
err := proto.Unmarshal(b, pbn)
|
err := proto.Unmarshal(b, &n.format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
n := new(FSNode)
|
|
||||||
n.Data = pbn.Data
|
|
||||||
n.blocksizes = pbn.Blocksizes
|
|
||||||
n.subtotal = pbn.GetFilesize() - uint64(len(n.Data))
|
|
||||||
n.Type = pbn.GetType()
|
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFSNode creates a new FSNode structure with the given `dataType`.
|
||||||
|
//
|
||||||
|
// It initializes the (required) `Type` field (that doesn't have a `Set()`
|
||||||
|
// accessor so it must be specified at creation), otherwise the `Marshal()`
|
||||||
|
// method in `GetBytes()` would fail (`required field "Type" not set`).
|
||||||
|
//
|
||||||
|
// It also initializes the `Filesize` pointer field to ensure its value
|
||||||
|
// is never nil before marshaling, this is not a required field but it is
|
||||||
|
// done to be backwards compatible with previous `go-ipfs` versions hash.
|
||||||
|
// (If it wasn't initialized there could be cases where `Filesize` could
|
||||||
|
// have been left at nil, when the `FSNode` was created but no data or
|
||||||
|
// child nodes were set to adjust it, as is the case in `NewLeaf()`.)
|
||||||
|
func NewFSNode(dataType pb.Data_DataType) *FSNode {
|
||||||
|
n := new(FSNode)
|
||||||
|
n.format.Type = &dataType
|
||||||
|
|
||||||
|
// Initialize by `Filesize` by updating it with a dummy (zero) value.
|
||||||
|
n.UpdateFilesize(0)
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
// AddBlockSize adds the size of the next child block of this node
|
// AddBlockSize adds the size of the next child block of this node
|
||||||
func (n *FSNode) AddBlockSize(s uint64) {
|
func (n *FSNode) AddBlockSize(s uint64) {
|
||||||
n.subtotal += s
|
n.UpdateFilesize(int64(s))
|
||||||
n.blocksizes = append(n.blocksizes, s)
|
n.format.Blocksizes = append(n.format.Blocksizes, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveBlockSize removes the given child block's size.
|
// RemoveBlockSize removes the given child block's size.
|
||||||
func (n *FSNode) RemoveBlockSize(i int) {
|
func (n *FSNode) RemoveBlockSize(i int) {
|
||||||
n.subtotal -= n.blocksizes[i]
|
n.UpdateFilesize(-int64(n.format.Blocksizes[i]))
|
||||||
n.blocksizes = append(n.blocksizes[:i], n.blocksizes[i+1:]...)
|
n.format.Blocksizes = append(n.format.Blocksizes[:i], n.format.Blocksizes[i+1:]...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBytes marshals this node as a protobuf message.
|
// GetBytes marshals this node as a protobuf message.
|
||||||
func (n *FSNode) GetBytes() ([]byte, error) {
|
func (n *FSNode) GetBytes() ([]byte, error) {
|
||||||
pbn := new(pb.Data)
|
return proto.Marshal(&n.format)
|
||||||
pbn.Type = &n.Type
|
|
||||||
pbn.Filesize = proto.Uint64(uint64(len(n.Data)) + n.subtotal)
|
|
||||||
pbn.Blocksizes = n.blocksizes
|
|
||||||
pbn.Data = n.Data
|
|
||||||
return proto.Marshal(pbn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileSize returns the total size of this tree. That is, the size of
|
// FileSize returns the total size of this tree. That is, the size of
|
||||||
// the data in this node plus the size of all its children.
|
// the data in this node plus the size of all its children.
|
||||||
func (n *FSNode) FileSize() uint64 {
|
func (n *FSNode) FileSize() uint64 {
|
||||||
return uint64(len(n.Data)) + n.subtotal
|
return n.format.GetFilesize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumChildren returns the number of child blocks of this node
|
// NumChildren returns the number of child blocks of this node
|
||||||
func (n *FSNode) NumChildren() int {
|
func (n *FSNode) NumChildren() int {
|
||||||
return len(n.blocksizes)
|
return len(n.format.Blocksizes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetData retrieves the `Data` field from the internal `format`.
|
||||||
|
func (n *FSNode) GetData() []byte {
|
||||||
|
return n.format.GetData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetData sets the `Data` field from the internal `format`
|
||||||
|
// updating its `Filesize`.
|
||||||
|
func (n *FSNode) SetData(newData []byte) {
|
||||||
|
n.UpdateFilesize(int64(len(newData) - len(n.GetData())))
|
||||||
|
n.format.Data = newData
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateFilesize updates the `Filesize` field from the internal `format`
|
||||||
|
// by a signed difference (`filesizeDiff`).
|
||||||
|
// TODO: Add assert to check for `Filesize` > 0?
|
||||||
|
func (n *FSNode) UpdateFilesize(filesizeDiff int64) {
|
||||||
|
n.format.Filesize = proto.Uint64(uint64(
|
||||||
|
int64(n.format.GetFilesize()) + filesizeDiff))
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetType retrieves the `Type` field from the internal `format`.
|
||||||
|
func (n *FSNode) GetType() pb.Data_DataType {
|
||||||
|
return n.format.GetType()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata is used to store additional FSNode information.
|
// Metadata is used to store additional FSNode information.
|
||||||
|
@ -10,14 +10,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFSNode(t *testing.T) {
|
func TestFSNode(t *testing.T) {
|
||||||
fsn := new(FSNode)
|
fsn := NewFSNode(TFile)
|
||||||
fsn.Type = TFile
|
|
||||||
for i := 0; i < 16; i++ {
|
for i := 0; i < 16; i++ {
|
||||||
fsn.AddBlockSize(100)
|
fsn.AddBlockSize(100)
|
||||||
}
|
}
|
||||||
fsn.RemoveBlockSize(15)
|
fsn.RemoveBlockSize(15)
|
||||||
|
|
||||||
fsn.Data = make([]byte, 128)
|
fsn.SetData(make([]byte, 128))
|
||||||
|
|
||||||
b, err := fsn.GetBytes()
|
b, err := fsn.GetBytes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Reference in New Issue
Block a user