Skip to content

Commit

Permalink
Merge pull request #5098 from schomatis/feat/unixfs/fsnode-include-pb
Browse files Browse the repository at this point in the history
unixfs: integrate `pb.Data` into `FSNode` to avoid duplicating fields
  • Loading branch information
whyrusleeping authored Jun 13, 2018
2 parents c224ba1 + 934b8b0 commit 9f9ddd5
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 39 deletions.
4 changes: 2 additions & 2 deletions importer/helpers/dagbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (db *DagBuilderHelper) GetDagServ() ipld.DAGService {
func (db *DagBuilderHelper) NewUnixfsNode() *UnixfsNode {
n := &UnixfsNode{
node: new(dag.ProtoNode),
ufmt: &ft.FSNode{Type: ft.TFile},
ufmt: ft.NewFSNode(ft.TFile),
}
n.SetPrefix(db.prefix)
return n
Expand Down Expand Up @@ -161,7 +161,7 @@ func (db *DagBuilderHelper) NewLeaf(data []byte) (*UnixfsNode, error) {
func (db *DagBuilderHelper) newUnixfsBlock() *UnixfsNode {
n := &UnixfsNode{
node: new(dag.ProtoNode),
ufmt: &ft.FSNode{Type: ft.TRaw},
ufmt: ft.NewFSNode(ft.TRaw),
}
n.SetPrefix(db.prefix)
return n
Expand Down
4 changes: 2 additions & 2 deletions importer/helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (n *UnixfsNode) Set(other *UnixfsNode) {
n.raw = other.raw
n.rawnode = other.rawnode
if other.ufmt != nil {
n.ufmt.Data = other.ufmt.Data
n.ufmt.SetData(other.ufmt.GetData())
}
}

Expand Down Expand Up @@ -127,7 +127,7 @@ func (n *UnixfsNode) RemoveChild(index int, dbh *DagBuilderHelper) {

// SetData stores data in this node.
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)
Expand Down
2 changes: 1 addition & 1 deletion mfs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (fi *File) Open(flags int, sync bool) (FileDescriptor, error) {
return nil, err
}

switch fsn.Type {
switch fsn.GetType() {
default:
return nil, fmt.Errorf("unsupported fsnode type for 'file'")
case ft.TSymlink:
Expand Down
2 changes: 1 addition & 1 deletion mfs/mfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ func TestFlushing(t *testing.T) {
t.Fatal(err)
}

if fsnode.Type != ft.TDirectory {
if fsnode.GetType() != ft.TDirectory {
t.Fatal("root wasnt a directory")
}

Expand Down
2 changes: 1 addition & 1 deletion unixfs/mod/dagmodifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ func dagTruncate(ctx context.Context, n ipld.Node, size uint64, ds ipld.DAGServi
var cur uint64
end := 0
var modified ipld.Node
ndata := new(ft.FSNode)
ndata := ft.NewFSNode(ft.TRaw)
for i, lnk := range nd.Links() {
child, err := lnk.GetNode(ctx, ds)
if err != nil {
Expand Down
92 changes: 63 additions & 29 deletions unixfs/unixfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Data []byte

// total data size for each child
blocksizes []uint64

// running sum of blocksizes
subtotal uint64

// node type of this node
Type pb.Data_DataType
// UnixFS format defined as a protocol buffers message.
format pb.Data
}

// FSNodeFromBytes unmarshal a protobuf message onto an FSNode.
func FSNodeFromBytes(b []byte) (*FSNode, error) {
pbn := new(pb.Data)
err := proto.Unmarshal(b, pbn)
n := new(FSNode)
err := proto.Unmarshal(b, &n.format)
if err != nil {
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
}

// 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
func (n *FSNode) AddBlockSize(s uint64) {
n.subtotal += s
n.blocksizes = append(n.blocksizes, s)
n.UpdateFilesize(int64(s))
n.format.Blocksizes = append(n.format.Blocksizes, s)
}

// RemoveBlockSize removes the given child block's size.
func (n *FSNode) RemoveBlockSize(i int) {
n.subtotal -= n.blocksizes[i]
n.blocksizes = append(n.blocksizes[:i], n.blocksizes[i+1:]...)
n.UpdateFilesize(-int64(n.format.Blocksizes[i]))
n.format.Blocksizes = append(n.format.Blocksizes[:i], n.format.Blocksizes[i+1:]...)
}

// GetBytes marshals this node as a protobuf message.
func (n *FSNode) GetBytes() ([]byte, error) {
pbn := new(pb.Data)
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)
return proto.Marshal(&n.format)
}

// 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.
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
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.
Expand Down
5 changes: 2 additions & 3 deletions unixfs/unixfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ import (
)

func TestFSNode(t *testing.T) {
fsn := new(FSNode)
fsn.Type = TFile
fsn := NewFSNode(TFile)
for i := 0; i < 16; i++ {
fsn.AddBlockSize(100)
}
fsn.RemoveBlockSize(15)

fsn.Data = make([]byte, 128)
fsn.SetData(make([]byte, 128))

b, err := fsn.GetBytes()
if err != nil {
Expand Down

0 comments on commit 9f9ddd5

Please sign in to comment.