Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unixfs: integrate pb.Data into FSNode to avoid duplicating fields #5098

Merged
merged 1 commit into from
Jun 13, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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