Skip to content

Commit d1b4cc1

Browse files
committed
Merge branch 'master' into feat/10710-mfs-fuse-mount
1 parent 6e1a455 commit d1b4cc1

File tree

15 files changed

+130
-54
lines changed

15 files changed

+130
-54
lines changed

config/internal.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ type InternalBitswap struct {
1414
EngineTaskWorkerCount OptionalInteger
1515
MaxOutstandingBytesPerPeer OptionalInteger
1616
ProviderSearchDelay OptionalDuration
17+
ProviderSearchMaxResults OptionalInteger
1718
WantHaveReplaceSize OptionalInteger
1819
}

core/corehttp/webui.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package corehttp
22

33
// WebUI version confirmed to work with this Kubo version
4-
const WebUIPath = "/ipfs/bafybeibpaa5kqrj4gkemiswbwndjqiryl65cks64ypwtyerxixu56gnvvm" // v4.6.0
4+
const WebUIPath = "/ipfs/bafybeibfd5kbebqqruouji6ct5qku3tay273g7mt24mmrfzrsfeewaal5y" // v4.7.0
55

66
// WebUIPaths is a list of all past webUI paths.
77
var WebUIPaths = []string{
88
WebUIPath,
9+
"/ipfs/bafybeibpaa5kqrj4gkemiswbwndjqiryl65cks64ypwtyerxixu56gnvvm", // v4.6.0
910
"/ipfs/bafybeiata4qg7xjtwgor6r5dw63jjxyouenyromrrb4lrewxrlvav7gzgi", // v4.5.0
1011
"/ipfs/bafybeigp3zm7cqoiciqk5anlheenqjsgovp7j7zq6hah4nu6iugdgb4nby", // v4.4.2
1112
"/ipfs/bafybeiatztgdllxnp5p6zu7bdwhjmozsmd7jprff4bdjqjljxtylitvss4", // v4.4.1

core/node/bitswap.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const (
2828
DefaultEngineTaskWorkerCount = 8
2929
DefaultMaxOutstandingBytesPerPeer = 1 << 20
3030
DefaultProviderSearchDelay = 1000 * time.Millisecond
31+
DefaultMaxProviders = 10 // matching BitswapClientDefaultMaxProviders from https://github.com/ipfs/boxo/blob/v0.29.1/bitswap/internal/defaults/defaults.go#L15
3132
DefaultWantHaveReplaceSize = 1024
3233
)
3334

@@ -79,11 +80,13 @@ func Bitswap(provide bool) interface{} {
7980

8081
var provider routing.ContentDiscovery
8182
if provide {
82-
// We need to hardcode the default because it is an
83-
// internal setting in boxo.
83+
var maxProviders int = DefaultMaxProviders
84+
if in.Cfg.Internal.Bitswap != nil {
85+
maxProviders = int(in.Cfg.Internal.Bitswap.ProviderSearchMaxResults.WithDefault(DefaultMaxProviders))
86+
}
8487
pqm, err := rpqm.New(bitswapNetwork,
8588
in.Rt,
86-
rpqm.WithMaxProviders(10),
89+
rpqm.WithMaxProviders(maxProviders),
8790
rpqm.WithIgnoreProviders(in.Cfg.Routing.IgnoreProviders...),
8891
)
8992
if err != nil {

core/node/core.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ func FetcherConfig(bs blockservice.BlockService) FetchersOut {
115115
// path resolution should not fetch new blocks via exchange.
116116
offlineBs := blockservice.New(bs.Blockstore(), offline.Exchange(bs.Blockstore()))
117117
offlineIpldFetcher := bsfetcher.NewFetcherConfig(offlineBs)
118+
offlineIpldFetcher.SkipNotFound = true // carries onto the UnixFSFetcher below
118119
offlineIpldFetcher.PrototypeChooser = dagpb.AddSupportToChooser(bsfetcher.DefaultPrototypeChooser)
119120
offlineUnixFSFetcher := offlineIpldFetcher.WithReifier(unixfsnode.Reify)
120121

core/node/provider.go

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import (
77

88
"github.com/ipfs/boxo/blockstore"
99
"github.com/ipfs/boxo/fetcher"
10+
"github.com/ipfs/boxo/mfs"
1011
pin "github.com/ipfs/boxo/pinning/pinner"
1112
provider "github.com/ipfs/boxo/provider"
13+
"github.com/ipfs/go-cid"
1214
"github.com/ipfs/kubo/repo"
1315
irouting "github.com/ipfs/kubo/routing"
1416
"go.uber.org/fx"
@@ -136,14 +138,8 @@ func OnlineProviders(useStrategicProviding bool, reprovideStrategy string, repro
136138

137139
var keyProvider fx.Option
138140
switch reprovideStrategy {
139-
case "all", "":
140-
keyProvider = fx.Provide(newProvidingStrategy(false, false))
141-
case "roots":
142-
keyProvider = fx.Provide(newProvidingStrategy(true, true))
143-
case "pinned":
144-
keyProvider = fx.Provide(newProvidingStrategy(true, false))
145-
case "flat":
146-
keyProvider = fx.Provide(provider.NewBlockstoreProvider)
141+
case "all", "", "roots", "pinned", "mfs", "pinned+mfs", "flat":
142+
keyProvider = fx.Provide(newProvidingStrategy(reprovideStrategy))
147143
default:
148144
return fx.Error(fmt.Errorf("unknown reprovider strategy %q", reprovideStrategy))
149145
}
@@ -159,32 +155,68 @@ func OfflineProviders() fx.Option {
159155
return fx.Provide(provider.NewNoopProvider)
160156
}
161157

162-
func newProvidingStrategy(onlyPinned, onlyRoots bool) interface{} {
158+
func mfsProvider(mfsRoot *mfs.Root, fetcher fetcher.Factory) provider.KeyChanFunc {
159+
return func(ctx context.Context) (<-chan cid.Cid, error) {
160+
err := mfsRoot.FlushMemFree(ctx)
161+
if err != nil {
162+
return nil, fmt.Errorf("error flushing mfs, cannot provide MFS: %w", err)
163+
}
164+
rootNode, err := mfsRoot.GetDirectory().GetNode()
165+
if err != nil {
166+
return nil, fmt.Errorf("error loading mfs root, cannot provide MFS: %w", err)
167+
}
168+
169+
kcf := provider.NewDAGProvider(rootNode.Cid(), fetcher)
170+
return kcf(ctx)
171+
}
172+
173+
}
174+
175+
func mfsRootProvider(mfsRoot *mfs.Root) provider.KeyChanFunc {
176+
return func(ctx context.Context) (<-chan cid.Cid, error) {
177+
rootNode, err := mfsRoot.GetDirectory().GetNode()
178+
if err != nil {
179+
return nil, fmt.Errorf("error loading mfs root, cannot provide MFS: %w", err)
180+
}
181+
ch := make(chan cid.Cid, 1)
182+
ch <- rootNode.Cid()
183+
close(ch)
184+
return ch, nil
185+
}
186+
}
187+
188+
func newProvidingStrategy(strategy string) interface{} {
163189
type input struct {
164190
fx.In
165-
Pinner pin.Pinner
166-
Blockstore blockstore.Blockstore
167-
IPLDFetcher fetcher.Factory `name:"ipldFetcher"`
191+
Pinner pin.Pinner
192+
Blockstore blockstore.Blockstore
193+
OfflineIPLDFetcher fetcher.Factory `name:"offlineIpldFetcher"`
194+
OfflineUnixFSFetcher fetcher.Factory `name:"offlineUnixfsFetcher"`
195+
MFSRoot *mfs.Root
168196
}
169197
return func(in input) provider.KeyChanFunc {
170-
// Pinner-related CIDs will be buffered in memory to avoid
171-
// deadlocking the pinner when the providing process is slow.
172-
173-
if onlyRoots {
174-
return provider.NewBufferedProvider(
175-
provider.NewPinnedProvider(true, in.Pinner, in.IPLDFetcher),
198+
switch strategy {
199+
case "roots":
200+
return provider.NewBufferedProvider(provider.NewPinnedProvider(true, in.Pinner, in.OfflineIPLDFetcher))
201+
case "pinned":
202+
return provider.NewBufferedProvider(provider.NewPinnedProvider(false, in.Pinner, in.OfflineIPLDFetcher))
203+
case "pinned+mfs":
204+
return provider.NewPrioritizedProvider(
205+
provider.NewBufferedProvider(provider.NewPinnedProvider(false, in.Pinner, in.OfflineIPLDFetcher)),
206+
mfsProvider(in.MFSRoot, in.OfflineUnixFSFetcher),
176207
)
177-
}
178-
179-
if onlyPinned {
180-
return provider.NewBufferedProvider(
181-
provider.NewPinnedProvider(false, in.Pinner, in.IPLDFetcher),
208+
case "mfs":
209+
return mfsProvider(in.MFSRoot, in.OfflineUnixFSFetcher)
210+
case "flat":
211+
return provider.NewBlockstoreProvider(in.Blockstore)
212+
default: // "all", ""
213+
return provider.NewPrioritizedProvider(
214+
provider.NewPrioritizedProvider(
215+
provider.NewBufferedProvider(provider.NewPinnedProvider(true, in.Pinner, in.OfflineIPLDFetcher)),
216+
mfsRootProvider(in.MFSRoot),
217+
),
218+
provider.NewBlockstoreProvider(in.Blockstore),
182219
)
183220
}
184-
185-
return provider.NewPrioritizedProvider(
186-
provider.NewBufferedProvider(provider.NewPinnedProvider(true, in.Pinner, in.IPLDFetcher)),
187-
provider.NewBlockstoreProvider(in.Blockstore),
188-
)
189221
}
190222
}

docs/changelogs/v0.35.md

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ This release was brought to you by the [Shipyard](http://ipshipyard.com/) team.
1010

1111
- [Overview](#overview)
1212
- [🔦 Highlights](#-highlights)
13+
- [Dedicated `Reprovider.Strategy` for MFS](#dedicated-reproviderstrategy-for-mfs)
14+
- [Additional new configuration options](#additional-new-configuration-options)
15+
- [Grid view in WebUI](#grid-view-in-webui)
16+
- [Expose MFS as FUSE mount point](#expose-mfs-as-fuse-mount-point)
1317
- [📦️ Important dependency updates](#-important-dependency-updates)
1418
- [📝 Changelog](#-changelog)
1519
- [👨‍👩‍👧‍👦 Contributors](#-contributors)
@@ -18,15 +22,35 @@ This release was brought to you by the [Shipyard](http://ipshipyard.com/) team.
1822

1923
### 🔦 Highlights
2024

21-
##### `Routing.IgnoreProviders`
25+
#### Dedicated `Reprovider.Strategy` for MFS
2226

23-
This new option allows ignoring specific peer IDs when returned by the content
24-
routing system as providers of content. See the
25-
[documentation](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingignoreproviders)
26-
for for information.
27+
The [Mutable File System (MFS)](https://docs.ipfs.tech/concepts/glossary/#mfs) in Kubo is a UnixFS filesystem managed with [`ipfs files`](https://docs.ipfs.tech/reference/kubo/cli/#ipfs-files) commands. It supports familiar file operations like cp and mv within a folder-tree structure, automatically updating a MerkleDAG and a "root CID" that reflects the current MFS state. Files in MFS are protected from garbage collection, offering a simpler alternative to `ipfs pin`. This makes it a popular choice for tools like [IPFS Desktop](https://docs.ipfs.tech/install/ipfs-desktop/) and the [WebUI](https://github.com/ipfs/ipfs-webui/#readme).
28+
29+
Previously, the `pinned` reprovider strategy required manual pin management: each dataset update meant pinning the new version and unpinning the old one. Now, new strategies—`mfs` and `pinned+mfs`—let users limit announcements to data explicitly placed in MFS. This simplifies updating datasets and announcing only the latest version to the Amino DHT.
30+
31+
Users relying on the `pinned` strategy can switch to `pinned+mfs` and use MFS alone to manage updates and announcements, eliminating the need for manual pinning and unpinning. We hope this makes it easier to publish just the data that matters to you.
32+
33+
See [`Reprovider.Strategy`](https://github.com/ipfs/kubo/blob/master/docs/config.md#reproviderstrategy) for more details.
34+
35+
#### Additional new configuration options
36+
37+
- [`Internal.Bitswap.ProviderSearchMaxResults`](https://github.com/ipfs/kubo/blob/master/docs/config.md##internalbitswapprovidersearchmaxresults) for adjusting the maximum number of providers bitswap client should aim at before it stops searching for new ones.
38+
- [`Routing.IgnoreProviders`](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingignoreproviders) allows ignoring specific peer IDs when returned by the content routing system as providers of content.
39+
40+
#### Grid view in WebUI
41+
42+
The WebUI, accessible at http://127.0.0.1:5001/webui/, now includes support for the grid view on the _Files_ screen:
43+
44+
> ![image](https://github.com/user-attachments/assets/80dcf0d0-8103-426f-ae91-416fb25d32b6)
45+
46+
#### Expose MFS as a FUSE mount point
47+
48+
The MFS root is now available as a read/write FUSE mount point at `/mfs`. This filesystem is mounted in the same way as `/ipfs` and `/ipns` when running `ipfs mount` or `ipfs daemon --mount`.
2749

2850
#### 📦️ Important dependency updates
2951

52+
- update `ipfs-webui` to [v4.7.0](https://github.com/ipfs/ipfs-webui/releases/tag/v4.7.0)
53+
3054
### 📝 Changelog
3155

3256
### 👨‍👩‍👧‍👦 Contributors

docs/config.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ config file at runtime.
7979
- [`Internal.Bitswap.EngineBlockstoreWorkerCount`](#internalbitswapengineblockstoreworkercount)
8080
- [`Internal.Bitswap.EngineTaskWorkerCount`](#internalbitswapenginetaskworkercount)
8181
- [`Internal.Bitswap.MaxOutstandingBytesPerPeer`](#internalbitswapmaxoutstandingbytesperpeer)
82-
- [`Internal.Bitswap.ProviderSearchDelay`](#internalbitswapprovidersearchdelay)
82+
- [`Internal.Bitswap.ProviderSearchDelay`](#internalbitswapprovidersearchdelay)
83+
- [`Internal.Bitswap.ProviderSearchMaxResults`](#internalbitswapprovidersearchmaxresults)
8384
- [`Internal.UnixFSShardingSizeThreshold`](#internalunixfsshardingsizethreshold)
8485
- [`Ipns`](#ipns)
8586
- [`Ipns.RepublishPeriod`](#ipnsrepublishperiod)
@@ -119,7 +120,7 @@ config file at runtime.
119120
- [`Routing.Type`](#routingtype)
120121
- [`Routing.AcceleratedDHTClient`](#routingaccelerateddhtclient)
121122
- [`Routing.LoopbackAddressesOnLanDHT`](#routingloopbackaddressesonlandht)
122-
- [`Routing.IgnoreProviders`](#routingignoreproviders)
123+
- [`Routing.IgnoreProviders`](#routingignoreproviders)
123124
- [`Routing.Routers`](#routingrouters)
124125
- [`Routing.Routers: Type`](#routingrouters-type)
125126
- [`Routing.Routers: Parameters`](#routingrouters-parameters)
@@ -1181,14 +1182,21 @@ deteriorate the quality provided to less aggressively-wanting peers.
11811182

11821183
Type: `optionalInteger` (byte count, `null` means default which is 1MB)
11831184

1184-
### `Internal.Bitswap.ProviderSearchDelay`
1185+
#### `Internal.Bitswap.ProviderSearchDelay`
11851186

11861187
This parameter determines how long to wait before looking for providers outside of bitswap.
11871188
Other routing systems like the Amino DHT are able to provide results in less than a second, so lowering
11881189
this number will allow faster peers lookups in some cases.
11891190

11901191
Type: `optionalDuration` (`null` means default which is 1s)
11911192

1193+
#### `Internal.Bitswap.ProviderSearchMaxResults`
1194+
1195+
Maximum number of providers bitswap client should aim at before it stops searching for new ones.
1196+
Setting to 0 means unlimited.
1197+
1198+
Type: `optionalInteger` (`null` means default which is 10)
1199+
11921200
### `Internal.UnixFSShardingSizeThreshold`
11931201

11941202
The sharding threshold used internally to decide whether a UnixFS directory should be sharded or not.
@@ -1587,21 +1595,26 @@ Type: `optionalDuration` (unset for the default)
15871595
Tells reprovider what should be announced. Valid strategies are:
15881596

15891597
- `"all"` - announce all CIDs of stored blocks
1590-
- Order: root blocks of direct and recursive pins are announced first, then the rest of blockstore
1591-
- `"pinned"` - only announce pinned CIDs recursively (both roots and child blocks)
1598+
- Order: root blocks of direct and recursive pins and MFS root are announced first, then the rest of blockstore
1599+
- `"pinned"` - only announce recursively pinned CIDs (`ipfs pin add -r`, both roots and child blocks)
15921600
- Order: root blocks of direct and recursive pins are announced first, then the child blocks of recursive pins
1593-
- `"roots"` - only announce the root block of explicitly pinned CIDs
1601+
- `"roots"` - only announce the root block of explicitly pinned CIDs (`ipfs pin add`)
15941602
- **⚠️ BE CAREFUL:** node with `roots` strategy will not announce child blocks.
15951603
It makes sense only for use cases where the entire DAG is fetched in full,
15961604
and a graceful resume does not have to be guaranteed: the lack of child
15971605
announcements means an interrupted retrieval won't be able to find
15981606
providers for the missing block in the middle of a file, unless the peer
15991607
happens to already be connected to a provider and ask for child CID over
16001608
bitswap.
1609+
- `"mfs"` - announce only the local CIDs that are part of the MFS (`ipfs files`)
1610+
- Note: MFS is lazy-loaded. Only the MFS blocks present in local datastore are announced.
1611+
- `"pinned+mfs"` - a combination of the `pinned` and `mfs` strategies.
1612+
- **ℹ️ NOTE:** This is the suggested strategy for users who run without GC and don't want to provide everything in cache.
1613+
- Order: first `pinned` and then the locally available part of `mfs`.
16011614
- `"flat"` - same as `all`, announce all CIDs of stored blocks, but without prioritizing anything.
16021615

16031616
> [!IMPORTANT]
1604-
> Reproviding larger pinsets using the `all`, `pinned`, or `roots` strategies requires additional memory, with an estimated ~1 GiB of RAM per 20 million items for reproviding to the Amino DHT.
1617+
> Reproviding larger pinsets using the `all`, `mfs`, `pinned`, `pinned+mfs` or `roots` strategies requires additional memory, with an estimated ~1 GiB of RAM per 20 million items for reproviding to the Amino DHT.
16051618
> This is due to the use of a buffered provider, which avoids holding a lock on the entire pinset during the reprovide cycle.
16061619
> The `flat` strategy can be used to lower memory requirements, but only recommended if memory utilization is too high, prioritization of pins is not necessary, and it is acceptable to announce every block cached in the local repository.
16071620

docs/examples/kubo-as-a-library/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ go 1.24
77
replace github.com/ipfs/kubo => ./../../..
88

99
require (
10-
github.com/ipfs/boxo v0.29.1
10+
github.com/ipfs/boxo v0.29.2-0.20250409154342-bbaf2e146dfb
1111
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
1212
github.com/libp2p/go-libp2p v0.41.1
1313
github.com/multiformats/go-multiaddr v0.15.0

docs/examples/kubo-as-a-library/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,8 +298,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
298298
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
299299
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
300300
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
301-
github.com/ipfs/boxo v0.29.1 h1:z61ZT4YDfTHLjXTsu/+3wvJ8aJlExthDSOCpx6Nh8xc=
302-
github.com/ipfs/boxo v0.29.1/go.mod h1:MkDJStXiJS9U99cbAijHdcmwNfVn5DKYBmQCOgjY2NU=
301+
github.com/ipfs/boxo v0.29.2-0.20250409154342-bbaf2e146dfb h1:kA7c3CF6/d8tUwGJR/SwIfaRz7Xk7Fbyoh2ePZAFMlw=
302+
github.com/ipfs/boxo v0.29.2-0.20250409154342-bbaf2e146dfb/go.mod h1:omQZmLS7LegSpBy3m4CrAB9/SO7Fq3pfv+5y1FOd+gI=
303303
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
304304
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
305305
github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ require (
2121
github.com/hashicorp/go-version v1.7.0
2222
github.com/ipfs-shipyard/nopfs v0.0.14
2323
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0
24-
github.com/ipfs/boxo v0.29.1
24+
github.com/ipfs/boxo v0.29.2-0.20250409154342-bbaf2e146dfb
2525
github.com/ipfs/go-block-format v0.2.0
2626
github.com/ipfs/go-cid v0.5.0
2727
github.com/ipfs/go-cidutil v0.1.0

0 commit comments

Comments
 (0)