Skip to content

Commit

Permalink
fix ContentPathMetadata
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Apr 10, 2024
1 parent 72561ca commit 627f24d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 48 deletions.
105 changes: 59 additions & 46 deletions gateway/backend_car.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,36 +183,41 @@ func (api *CarBackend) fetchCAR(ctx context.Context, path path.ImmutablePath, pa
}

// resolvePathWithRootsAndBlock takes a path and linksystem and returns the set of non-terminal cids, the terminal cid, the remainder, and the block corresponding to the terminal cid
func resolvePathWithRootsAndBlock(ctx context.Context, p path.ImmutablePath, unixFSLsys *ipld.LinkSystem) ([]cid.Cid, cid.Cid, []string, blocks.Block, error) {
pathRootCids, terminalCid, remainder, terminalBlk, err := resolvePathToLastWithRoots(ctx, p, unixFSLsys)
func resolvePathWithRootsAndBlock(ctx context.Context, p path.ImmutablePath, unixFSLsys *ipld.LinkSystem) (ContentPathMetadata, blocks.Block, error) {
md, terminalBlk, err := resolvePathToLastWithRoots(ctx, p, unixFSLsys)
if err != nil {
return nil, cid.Undef, nil, nil, err
return ContentPathMetadata{}, nil, err
}

terminalCid := md.LastSegment.RootCid()

if terminalBlk == nil {
lctx := ipld.LinkContext{Ctx: ctx}
lnk := cidlink.Link{Cid: terminalCid}
blockData, err := unixFSLsys.LoadRaw(lctx, lnk)
if err != nil {
return nil, cid.Undef, nil, nil, err
return ContentPathMetadata{}, nil, err
}
terminalBlk, err = blocks.NewBlockWithCid(blockData, terminalCid)
if err != nil {
return nil, cid.Undef, nil, nil, err
return ContentPathMetadata{}, nil, err

Check warning on line 203 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L203

Added line #L203 was not covered by tests
}
}

return pathRootCids, terminalCid, remainder, terminalBlk, err
return md, terminalBlk, err
}

// resolvePathToLastWithRoots takes a path and linksystem and returns the set of non-terminal cids, the terminal cid,
// the remainder pathing, the last block loaded, and the last node loaded.
//
// Note: the block returned will be nil if the terminal element is a link or the path is just a CID
func resolvePathToLastWithRoots(ctx context.Context, p path.ImmutablePath, unixFSLsys *ipld.LinkSystem) ([]cid.Cid, cid.Cid, []string, blocks.Block, error) {
func resolvePathToLastWithRoots(ctx context.Context, p path.ImmutablePath, unixFSLsys *ipld.LinkSystem) (ContentPathMetadata, blocks.Block, error) {
root, segments := p.RootCid(), p.Segments()[2:]
if len(segments) == 0 {
return nil, root, nil, nil, nil
return ContentPathMetadata{
PathSegmentRoots: []cid.Cid{root},
LastSegment: p,
}, nil, nil
}

unixFSLsys.NodeReifier = unixfsnode.Reify
Expand Down Expand Up @@ -248,31 +253,31 @@ func resolvePathToLastWithRoots(ctx context.Context, p path.ImmutablePath, unixF

nextBlk, nextNd, err := loadNode(ctx, root)
if err != nil {
return nil, cid.Undef, nil, nil, err
return ContentPathMetadata{}, nil, err

Check warning on line 256 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L256

Added line #L256 was not covered by tests
}

depth := 0
for i, elem := range segments {
nextNd, err = nextNd.LookupBySegment(ipld.ParsePathSegment(elem))
if err != nil {
return nil, cid.Undef, nil, nil, err
return ContentPathMetadata{}, nil, err
}
if nextNd.Kind() == ipld.Kind_Link {
depth = 0
lnk, err := nextNd.AsLink()
if err != nil {
return nil, cid.Undef, nil, nil, err
return ContentPathMetadata{}, nil, err

Check warning on line 269 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L269

Added line #L269 was not covered by tests
}
cidLnk, ok := lnk.(cidlink.Link)
if !ok {
return nil, cid.Undef, nil, nil, fmt.Errorf("link is not a cidlink: %v", cidLnk)
return ContentPathMetadata{}, nil, fmt.Errorf("link is not a cidlink: %v", cidLnk)

Check warning on line 273 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L273

Added line #L273 was not covered by tests
}
cids = append(cids, cidLnk.Cid)

if i < len(segments)-1 {
nextBlk, nextNd, err = loadNode(ctx, cidLnk.Cid)
if err != nil {
return nil, cid.Undef, nil, nil, err
return ContentPathMetadata{}, nil, err
}
}
} else {
Expand All @@ -282,18 +287,38 @@ func resolvePathToLastWithRoots(ctx context.Context, p path.ImmutablePath, unixF

// if last node is not a link, just return it's cid, add path to remainder and return
if nextNd.Kind() != ipld.Kind_Link {
md, err := contentMetadataFromRootsAndRemainder(cids, segments[len(segments)-depth:])
if err != nil {
return ContentPathMetadata{}, nil, err

Check warning on line 292 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L290-L292

Added lines #L290 - L292 were not covered by tests
}

// return the cid and the remainder of the path
return cids[:len(cids)-1], cids[len(cids)-1], segments[len(segments)-depth:], nextBlk, nil
return md, nextBlk, nil

Check warning on line 296 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L296

Added line #L296 was not covered by tests
}

return cids[:len(cids)-1], cids[len(cids)-1], nil, nil, nil
md, err := contentMetadataFromRootsAndRemainder(cids, nil)
return md, nil, err
}

func contentMetadataFromRootsAndRemainder(p path.ImmutablePath, pathRoots []cid.Cid, remainder []string) (ContentPathMetadata, error) {
func contentMetadataFromRootsAndRemainder(roots []cid.Cid, remainder []string) (ContentPathMetadata, error) {
if len(roots) == 0 {
return ContentPathMetadata{}, errors.New("invalid pathRoots given with length 0")

Check warning on line 305 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L305

Added line #L305 was not covered by tests
}

p, err := path.Join(path.FromCid(roots[len(roots)-1]), remainder...)
if err != nil {
return ContentPathMetadata{}, err

Check warning on line 310 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L310

Added line #L310 was not covered by tests
}

imPath, err := path.NewImmutablePath(p)
if err != nil {
return ContentPathMetadata{}, err

Check warning on line 315 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L315

Added line #L315 was not covered by tests
}

md := ContentPathMetadata{
PathSegmentRoots: pathRoots,
PathSegmentRoots: roots,
LastSegmentRemainder: remainder,
LastSegment: p,
LastSegment: imPath,
}
return md, nil
}
Expand Down Expand Up @@ -735,7 +760,7 @@ func fetchWithPartialRetries[T any](ctx context.Context, p path.ImmutablePath, i
lsys := getLinksystem(gb)

if hasSentAsyncData {
_, _, _, _, err = resolvePathToLastWithRoots(cctx, p, lsys)
_, _, err = resolvePathToLastWithRoots(cctx, p, lsys)
if err != nil {
return err

Check warning on line 765 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L765

Added line #L765 was not covered by tests
}
Expand All @@ -747,17 +772,12 @@ func fetchWithPartialRetries[T any](ctx context.Context, p path.ImmutablePath, i
}
} else {
// First resolve the path since we always need to.
pathRootCids, terminalCid, remainder, terminalBlk, err := resolvePathWithRootsAndBlock(cctx, p, lsys)
if err != nil {
return err
}

md, err := contentMetadataFromRootsAndRemainder(p, pathRootCids, remainder)
md, terminalBlk, err := resolvePathWithRootsAndBlock(cctx, p, lsys)
if err != nil {
return err
}

if len(remainder) > 0 {
if len(md.LastSegmentRemainder) > 0 {
terminalPathElementCh <- terminalPathType[T]{err: errNotUnixFS}
return nil

Check warning on line 782 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L781-L782

Added lines #L781 - L782 were not covered by tests
}
Expand All @@ -770,6 +790,8 @@ func fetchWithPartialRetries[T any](ctx context.Context, p path.ImmutablePath, i
}
}

terminalCid := md.LastSegment.RootCid()

nd, err := resolveTerminalElementFn(cctx, terminalCid, terminalBlk, lsys, params, getLsys)
if err != nil {
return err

Check warning on line 797 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L797

Added line #L797 was not covered by tests
Expand Down Expand Up @@ -857,7 +879,8 @@ func (api *CarBackend) GetBlock(ctx context.Context, p path.ImmutablePath) (Cont
lsys := getLinksystem(gb)

// First resolve the path since we always need to.
pathRoots, terminalCid, remainder, terminalBlk, err := resolvePathToLastWithRoots(ctx, p, lsys)
var terminalBlk blocks.Block
md, terminalBlk, err = resolvePathToLastWithRoots(ctx, p, lsys)
if err != nil {
return err
}
Expand All @@ -867,18 +890,13 @@ func (api *CarBackend) GetBlock(ctx context.Context, p path.ImmutablePath) (Cont
blockData = terminalBlk.RawData()
} else {
lctx := ipld.LinkContext{Ctx: ctx}
lnk := cidlink.Link{Cid: terminalCid}
lnk := cidlink.Link{Cid: md.LastSegment.RootCid()}
blockData, err = lsys.LoadRaw(lctx, lnk)
if err != nil {
return err

Check warning on line 896 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L888-L896

Added lines #L888 - L896 were not covered by tests
}
}

md, err = contentMetadataFromRootsAndRemainder(p, pathRoots, remainder)
if err != nil {
return err
}

f = files.NewBytesFile(blockData)
return nil

Check warning on line 901 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L900-L901

Added lines #L900 - L901 were not covered by tests
})
Expand Down Expand Up @@ -909,24 +927,21 @@ func (api *CarBackend) Head(ctx context.Context, p path.ImmutablePath) (ContentP
lsys := getLinksystem(gb)

Check warning on line 927 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L927

Added line #L927 was not covered by tests

// First resolve the path since we always need to.
pathRoots, terminalCid, remainder, terminalBlk, err := resolvePathWithRootsAndBlock(ctx, p, lsys)
if err != nil {
return err
}

md, err = contentMetadataFromRootsAndRemainder(p, pathRoots, remainder)
var terminalBlk blocks.Block
md, terminalBlk, err := resolvePathWithRootsAndBlock(ctx, p, lsys)
if err != nil {
return err

Check warning on line 933 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L930-L933

Added lines #L930 - L933 were not covered by tests
}

terminalCid := md.LastSegment.RootCid()
lctx := ipld.LinkContext{Ctx: ctx}
pathTerminalCidLink := cidlink.Link{Cid: terminalCid}

Check warning on line 938 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L936-L938

Added lines #L936 - L938 were not covered by tests

// Load the block at the root of the terminal path element
dataBytes := terminalBlk.RawData()

Check warning on line 941 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L941

Added line #L941 was not covered by tests

// It's not UnixFS if there is a remainder or it's not dag-pb
if len(remainder) > 0 || terminalCid.Type() != uint64(multicodec.DagPb) {
if len(md.LastSegmentRemainder) > 0 || terminalCid.Type() != uint64(multicodec.DagPb) {
n = NewHeadResponseForFile(files.NewBytesFile(dataBytes), int64(len(dataBytes)))
return nil

Check warning on line 946 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L944-L946

Added lines #L944 - L946 were not covered by tests
}
Expand Down Expand Up @@ -1044,13 +1059,11 @@ func (api *CarBackend) ResolvePath(ctx context.Context, p path.ImmutablePath) (C
lsys := getLinksystem(gb)

Check warning on line 1059 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L1059

Added line #L1059 was not covered by tests

// First resolve the path since we always need to.
pathRoots, _, remainder, _, err := resolvePathToLastWithRoots(ctx, p, lsys)
md, _, err = resolvePathToLastWithRoots(ctx, p, lsys)
if err != nil {
return err

Check warning on line 1064 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L1062-L1064

Added lines #L1062 - L1064 were not covered by tests
}

md, err = contentMetadataFromRootsAndRemainder(p, pathRoots, remainder)

return err

Check warning on line 1067 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L1067

Added line #L1067 was not covered by tests
})

Expand Down Expand Up @@ -1111,16 +1124,16 @@ func (api *CarBackend) GetCAR(ctx context.Context, p path.ImmutablePath, params
l := getLinksystem(teeBlock)

// First resolve the path since we always need to.
_, terminalCid, remainder, terminalBlk, err := resolvePathWithRootsAndBlock(ctx, p, l)
md, terminalBlk, err := resolvePathWithRootsAndBlock(ctx, p, l)
if err != nil {
return err

Check warning on line 1129 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L1129

Added line #L1129 was not covered by tests
}
if len(remainder) > 0 {
if len(md.LastSegmentRemainder) > 0 {
return nil

Check warning on line 1132 in gateway/backend_car.go

View check run for this annotation

Codecov / codecov/patch

gateway/backend_car.go#L1132

Added line #L1132 was not covered by tests
}

if cw == nil {
cw, err = storage.NewWritable(w, []cid.Cid{terminalCid}, carv2.WriteAsCarV1(true), carv2.AllowDuplicatePuts(params.Duplicates.Bool()))
cw, err = storage.NewWritable(w, []cid.Cid{md.LastSegment.RootCid()}, carv2.WriteAsCarV1(true), carv2.AllowDuplicatePuts(params.Duplicates.Bool()))
if err != nil {
// io.PipeWriter.CloseWithError always returns nil.
_ = w.CloseWithError(err)
Expand Down
3 changes: 1 addition & 2 deletions gateway/backend_car_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,13 +755,12 @@ func TestCarBackendGetHAMTDirectory(t *testing.T) {
// Expect a request for a non-existent index.html file
// Note: this is an implementation detail related to the directory request above
// Note: the order of cases 3 and 4 here are implementation specific as well
expectedUri := "/ipfs/bafybeid3fd2xxdcd3dbj7trb433h2aqssn6xovjbwnkargjv7fuog4xjdi/hamtDir/index.html"
expectedUri := "/ipfs/bafybeignui4g7l6cvqyy4t6vnbl2fjtego4ejmpcia77jhhwnksmm4bejm/index.html"
if request.URL.Path != expectedUri {
panic(fmt.Errorf("expected URI %s, got %s", expectedUri, request.RequestURI))
}

if err := sendBlocks(ctx, dirWithMultiblockHAMTandFiles, writer, []string{
"bafybeid3fd2xxdcd3dbj7trb433h2aqssn6xovjbwnkargjv7fuog4xjdi", // root dir
"bafybeignui4g7l6cvqyy4t6vnbl2fjtego4ejmpcia77jhhwnksmm4bejm", // hamt root
"bafybeiccgo7euew77gkqkhezn3pozfrciiibqz2u3spdqmgjvd5wqskipm", // inner hamt nodes start here
}); err != nil {
Expand Down

0 comments on commit 627f24d

Please sign in to comment.