Skip to content

Commit a4e8c5c

Browse files
committed
ipfs: use cached nodes when resolving paths
1 parent 99cef89 commit a4e8c5c

File tree

4 files changed

+72
-100
lines changed

4 files changed

+72
-100
lines changed

internal/filesystem/ipfs/ipfs.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
coreiface "github.com/ipfs/boxo/coreiface"
1515
coreoptions "github.com/ipfs/boxo/coreiface/options"
1616
corepath "github.com/ipfs/boxo/coreiface/path"
17+
ipath "github.com/ipfs/boxo/path"
18+
"github.com/ipfs/boxo/path/resolver"
1719
"github.com/ipfs/go-cid"
1820
cbor "github.com/ipfs/go-ipld-cbor"
1921
ipld "github.com/ipfs/go-ipld-format"
@@ -30,6 +32,7 @@ type (
3032
ctx context.Context
3133
cancel context.CancelFunc
3234
core coreiface.CoreAPI
35+
resolver resolver.Resolver
3336
nodeCache *ipfsNodeCache
3437
dirCache *ipfsDirCache
3538
info nodeInfo
@@ -76,6 +79,7 @@ func NewIPFS(core coreiface.CoreAPI, options ...IPFSOption) (*IPFS, error) {
7679
fsys.cancel()
7780
return nil, err
7881
}
82+
fsys.resolver = newPathResolver(fsys.getNode)
7983
return fsys, nil
8084
}
8185

@@ -201,7 +205,7 @@ func (fsys *IPFS) toCID(op, goPath string) (cid.Cid, error) {
201205
if len(names) == 1 {
202206
return rootCID, nil
203207
}
204-
nodeCID, err := fsys.walkLinks(rootCID, names[1:])
208+
nodeCID, err := fsys.resolvePath(goPath)
205209
if err != nil {
206210
kind := resolveErrKind(err)
207211
return cid.Cid{}, fserrors.New(op, goPath, err, kind)
@@ -299,12 +303,14 @@ func (fsys *IPFS) nodeContext() (context.Context, context.CancelFunc) {
299303
return context.WithTimeout(ctx, timeout)
300304
}
301305

302-
func (fsys *IPFS) walkLinks(root cid.Cid, names []string) (cid.Cid, error) {
306+
func (fsys *IPFS) resolvePath(goPath string) (cid.Cid, error) {
303307
var (
304-
ctx = fsys.ctx
305-
resolver = newPathResolver(fsys.core)
308+
ctx = fsys.ctx
309+
resolver = fsys.resolver
310+
iPath = ipath.FromString(goPath)
311+
leaf, _, err = resolver.ResolveToLastNode(ctx, iPath)
306312
)
307-
return walkLinks(ctx, root, names, resolver)
313+
return leaf, err
308314
}
309315

310316
func (fsys *IPFS) Open(name string) (fs.File, error) {

internal/filesystem/ipfs/ipns.go

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ import (
1515
lru "github.com/hashicorp/golang-lru/v2"
1616
coreiface "github.com/ipfs/boxo/coreiface"
1717
corepath "github.com/ipfs/boxo/coreiface/path"
18+
ipath "github.com/ipfs/boxo/path"
19+
"github.com/ipfs/boxo/path/resolver"
1820
"github.com/ipfs/go-cid"
21+
ipld "github.com/ipfs/go-ipld-format"
1922
)
2023

2124
type (
@@ -27,6 +30,7 @@ type (
2730
IPNS struct {
2831
ctx context.Context
2932
core coreiface.CoreAPI
33+
resolver resolver.Resolver
3034
ipfs fs.FS
3135
cancel context.CancelFunc
3236
rootCache *ipnsRootCache
@@ -187,27 +191,43 @@ func (fsys *IPNS) toCID(op, goPath string) (cid.Cid, error) {
187191
return rootCID, nil
188192
}
189193
var (
190-
leafCid cid.Cid
191-
err error
192-
)
193-
// Re-use cid cache if available.
194-
// Otherwise resolve all directly.
195-
if ipfs, ok := fsys.ipfs.(*IPFS); ok {
196-
leafCid, err = ipfs.walkLinks(rootCID, names[1:])
197-
} else {
198-
var (
199-
ctx = fsys.ctx
200-
resolver = newPathResolver(fsys.core)
194+
components = append(
195+
[]string{rootCID.String()},
196+
names[1:]...,
201197
)
202-
leafCid, err = walkLinks(ctx, rootCID, names[1:], resolver)
203-
}
198+
ipfsPath = path.Join(components...)
199+
leafCid, err = fsys.resolvePath(ipfsPath)
200+
)
204201
if err != nil {
205202
kind := resolveErrKind(err)
206203
return cid.Cid{}, fserrors.New(op, goPath, err, kind)
207204
}
208205
return leafCid, nil
209206
}
210207

208+
func (fsys *IPNS) fetchNode(cid cid.Cid) (ipld.Node, error) {
209+
ctx, cancel := fsys.nodeContext()
210+
defer cancel()
211+
return fsys.core.Dag().Get(ctx, cid)
212+
}
213+
214+
func (fsys *IPNS) resolvePath(goPath string) (cid.Cid, error) {
215+
if ipfs, ok := fsys.ipfs.(*IPFS); ok {
216+
return ipfs.resolvePath(goPath)
217+
}
218+
resolver := fsys.resolver
219+
if resolver == nil {
220+
resolver = newPathResolver(fsys.fetchNode)
221+
fsys.resolver = resolver
222+
}
223+
var (
224+
ctx = fsys.ctx
225+
iPath = ipath.FromString(goPath)
226+
leaf, _, err = resolver.ResolveToLastNode(ctx, iPath)
227+
)
228+
return leaf, err
229+
}
230+
211231
func (fsys *IPNS) nodeContext() (context.Context, context.CancelFunc) {
212232
var (
213233
ctx = fsys.ctx

internal/filesystem/ipfs/resolve.go

Lines changed: 28 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,29 @@ package ipfs
22

33
import (
44
"context"
5-
"io"
65

76
fserrors "github.com/djdv/go-filesystem-utils/internal/filesystem/errors"
87
"github.com/ipfs/boxo/blockservice"
9-
coreiface "github.com/ipfs/boxo/coreiface"
10-
ipath "github.com/ipfs/boxo/coreiface/path"
118
"github.com/ipfs/boxo/exchange"
129
bsfetcher "github.com/ipfs/boxo/fetcher/impl/blockservice"
1310
"github.com/ipfs/boxo/path/resolver"
1411
blocks "github.com/ipfs/go-block-format"
1512
"github.com/ipfs/go-cid"
13+
ipld "github.com/ipfs/go-ipld-format"
1614
"github.com/ipfs/go-unixfsnode"
1715
dagpb "github.com/ipld/go-codec-dagpb"
1816
)
1917

2018
type (
21-
coreBlockStore struct {
22-
blocks coreiface.BlockAPI
23-
validate bool
24-
}
25-
blockFetcher struct {
26-
coreiface.APIDagService
27-
}
19+
fnBlockStore getNodeFunc
20+
fnBlockFetcher getNodeFunc
21+
getNodeFunc func(cid cid.Cid) (ipld.Node, error)
2822
)
2923

30-
func newPathResolver(api coreiface.CoreAPI) resolver.Resolver {
24+
func newPathResolver(getNodeFn getNodeFunc) resolver.Resolver {
3125
var (
32-
blockstore = newCoreBlockStore(api.Block())
33-
fetcher = makeBlockFetcher(api.Dag())
26+
blockstore = newCoreBlockStore(getNodeFn)
27+
fetcher = makeBlockFetcher(getNodeFn)
3428
service = blockservice.New(blockstore, fetcher)
3529
config = bsfetcher.NewFetcherConfig(service)
3630
)
@@ -39,89 +33,62 @@ func newPathResolver(api coreiface.CoreAPI) resolver.Resolver {
3933
return resolver.NewBasicResolver(fetcherFactory)
4034
}
4135

42-
func newCoreBlockStore(blocks coreiface.BlockAPI) *coreBlockStore {
43-
return &coreBlockStore{blocks: blocks}
44-
}
45-
46-
func makeBlockFetcher(dag coreiface.APIDagService) exchange.Interface {
47-
return blockFetcher{APIDagService: dag}
36+
func newCoreBlockStore(getNodeFn getNodeFunc) fnBlockStore {
37+
return fnBlockStore(getNodeFn)
4838
}
4939

50-
func (bs *coreBlockStore) fetch(ctx context.Context, c cid.Cid) (blocks.Block, error) {
51-
blockReader, err := bs.blocks.Get(ctx, ipath.IpfsPath(c))
52-
if err != nil {
53-
return nil, err
54-
}
55-
blockData, err := io.ReadAll(blockReader)
56-
if err != nil {
57-
return nil, err
58-
}
59-
if bs.validate {
60-
nc, err := c.Prefix().Sum(blockData)
61-
if err != nil {
62-
return nil, blocks.ErrWrongHash
63-
}
64-
if !nc.Equals(c) {
65-
return nil, blocks.ErrWrongHash
66-
}
67-
}
68-
return blocks.NewBlockWithCid(blockData, c)
40+
func makeBlockFetcher(getNodeFn getNodeFunc) exchange.Interface {
41+
return fnBlockFetcher(getNodeFn)
6942
}
7043

71-
func (bs *coreBlockStore) Has(ctx context.Context, c cid.Cid) (bool, error) {
72-
blk, err := bs.fetch(ctx, c)
44+
func (getNodeFn fnBlockStore) Has(_ context.Context, c cid.Cid) (bool, error) {
45+
blk, err := getNodeFn(c)
7346
if err != nil {
7447
return false, err
7548
}
7649
return blk != nil, nil
7750
}
7851

79-
func (bs *coreBlockStore) Get(ctx context.Context, c cid.Cid) (blocks.Block, error) {
80-
blk, err := bs.fetch(ctx, c)
81-
if err != nil {
82-
return nil, err
83-
}
84-
return blk, nil
52+
func (getNodeFn fnBlockStore) Get(_ context.Context, c cid.Cid) (blocks.Block, error) {
53+
return getNodeFn(c)
8554
}
8655

87-
func (bs *coreBlockStore) GetSize(ctx context.Context, c cid.Cid) (int, error) {
88-
blk, err := bs.fetch(ctx, c)
56+
func (getNodeFn fnBlockStore) GetSize(ctx context.Context, c cid.Cid) (int, error) {
57+
blk, err := getNodeFn(c)
8958
if err != nil {
9059
return 0, err
9160
}
9261
return len(blk.RawData()), nil
9362
}
9463

95-
func (bs *coreBlockStore) HashOnRead(enabled bool) {
96-
bs.validate = enabled
97-
}
64+
func (fnBlockStore) HashOnRead(bool) {}
9865

99-
func (*coreBlockStore) Put(context.Context, blocks.Block) error {
66+
func (fnBlockStore) Put(context.Context, blocks.Block) error {
10067
return fserrors.ErrUnsupported
10168
}
10269

103-
func (*coreBlockStore) PutMany(context.Context, []blocks.Block) error {
70+
func (fnBlockStore) PutMany(context.Context, []blocks.Block) error {
10471
return fserrors.ErrUnsupported
10572
}
10673

107-
func (*coreBlockStore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
74+
func (fnBlockStore) AllKeysChan(ctx context.Context) (<-chan cid.Cid, error) {
10875
return nil, fserrors.ErrUnsupported
10976
}
11077

111-
func (*coreBlockStore) DeleteBlock(context.Context, cid.Cid) error {
78+
func (fnBlockStore) DeleteBlock(context.Context, cid.Cid) error {
11279
return fserrors.ErrUnsupported
11380
}
11481

115-
func (bf blockFetcher) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) {
116-
return bf.APIDagService.Get(ctx, c)
82+
func (getNodeFn fnBlockFetcher) GetBlock(_ context.Context, c cid.Cid) (blocks.Block, error) {
83+
return getNodeFn(c)
11784
}
11885

119-
func (bf blockFetcher) GetBlocks(ctx context.Context, cids []cid.Cid) (<-chan blocks.Block, error) {
86+
func (blockGetter fnBlockFetcher) GetBlocks(ctx context.Context, cids []cid.Cid) (<-chan blocks.Block, error) {
12087
out := make(chan blocks.Block)
12188
go func() {
12289
defer close(out)
12390
for _, c := range cids {
124-
block, err := bf.GetBlock(ctx, c)
91+
block, err := blockGetter.GetBlock(ctx, c)
12592
if err != nil {
12693
return
12794
}
@@ -135,10 +102,10 @@ func (bf blockFetcher) GetBlocks(ctx context.Context, cids []cid.Cid) (<-chan bl
135102
return out, nil
136103
}
137104

138-
func (blockFetcher) NotifyNewBlocks(ctx context.Context, blocks ...blocks.Block) error {
105+
func (fnBlockFetcher) NotifyNewBlocks(ctx context.Context, blocks ...blocks.Block) error {
139106
return nil
140107
}
141108

142-
func (blockFetcher) Close() error {
109+
func (fnBlockFetcher) Close() error {
143110
return nil
144111
}

internal/filesystem/ipfs/shared.go

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"io"
77
"io/fs"
8-
"path"
98
"strings"
109
"time"
1110

@@ -16,9 +15,6 @@ import (
1615
dag "github.com/ipfs/boxo/ipld/merkledag"
1716
"github.com/ipfs/boxo/ipld/unixfs"
1817
unixpb "github.com/ipfs/boxo/ipld/unixfs/pb"
19-
ipath "github.com/ipfs/boxo/path"
20-
"github.com/ipfs/boxo/path/resolver"
21-
"github.com/ipfs/go-cid"
2218
ipfscmds "github.com/ipfs/go-ipfs-cmds"
2319
cbor "github.com/ipfs/go-ipld-cbor"
2420
ipld "github.com/ipfs/go-ipld-format"
@@ -56,7 +52,6 @@ type (
5652
modTime time.Time
5753
permissions fs.FileMode
5854
}
59-
getNodeFunc func(cid.Cid) (ipld.Node, error)
6055
)
6156

6257
const (
@@ -370,22 +365,6 @@ func drainThenSendErr(ch chan filesystem.StreamDirEntry, err error) {
370365
ch <- newErrorEntry(err)
371366
}
372367

373-
func walkLinks(ctx context.Context,
374-
root cid.Cid, names []string,
375-
resolver resolver.Resolver,
376-
) (cid.Cid, error) {
377-
var (
378-
iPath = ipath.FromCid(root)
379-
components = append(
380-
[]string{string(iPath)},
381-
names...,
382-
)
383-
nodePath = ipath.FromString(path.Join(components...))
384-
)
385-
leaf, _, err := resolver.ResolveToLastNode(ctx, nodePath)
386-
return leaf, err
387-
}
388-
389368
func fsTypeName(mode fs.FileMode) string {
390369
switch mode.Type() {
391370
case fs.FileMode(0):

0 commit comments

Comments
 (0)