Skip to content

Commit d3ba306

Browse files
committed
feat: warn users who are falling behind reprovides
Fixes: ipfs#9704 Fixes: ipfs#9702 Depends on: ipfs#273
1 parent 117e211 commit d3ba306

File tree

4 files changed

+90
-9
lines changed

4 files changed

+90
-9
lines changed

core/commands/stat_provide.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import (
77
"time"
88

99
humanize "github.com/dustin/go-humanize"
10+
"github.com/ipfs/boxo/provider"
1011
cmds "github.com/ipfs/go-ipfs-cmds"
1112
"github.com/ipfs/kubo/core/commands/cmdenv"
12-
13-
"github.com/ipfs/boxo/provider"
13+
"golang.org/x/exp/constraints"
1414
)
1515

1616
var statProvideCmd = &cmds.Command{
@@ -64,7 +64,7 @@ func humanDuration(val time.Duration) string {
6464
return val.Truncate(time.Microsecond).String()
6565
}
6666

67-
func humanNumber(n int) string {
67+
func humanNumber[T constraints.Float | constraints.Integer](n T) string {
6868
nf := float64(n)
6969
str := humanSI(nf, 0)
7070
fullStr := humanFull(nf, 0)

core/node/provider.go

+79-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"time"
77

8+
"github.com/ipfs/boxo/blockstore"
89
"github.com/ipfs/boxo/fetcher"
910
pin "github.com/ipfs/boxo/pinning/pinner"
1011
provider "github.com/ipfs/boxo/provider"
@@ -14,11 +15,87 @@ import (
1415
)
1516

1617
func ProviderSys(reprovideInterval time.Duration) fx.Option {
17-
return fx.Provide(func(lc fx.Lifecycle, cr irouting.ProvideManyRouter, keyProvider provider.KeyChanFunc, repo repo.Repo) (provider.System, error) {
18+
const magicThroughputReportCount = 128
19+
return fx.Provide(func(lc fx.Lifecycle, cr irouting.ProvideManyRouter, keyProvider provider.KeyChanFunc, repo repo.Repo, bs blockstore.Blockstore) (provider.System, error) {
1820
sys, err := provider.New(repo.Datastore(),
1921
provider.Online(cr),
2022
provider.ReproviderInterval(reprovideInterval),
2123
provider.KeyProvider(keyProvider),
24+
provider.ThroughputReport(func(reprovide bool, complete bool, keysProvided uint, duration time.Duration) bool {
25+
avgProvideSpeed := duration / time.Duration(keysProvided)
26+
count := uint64(keysProvided)
27+
28+
if !reprovide || !complete {
29+
// We don't know how many CIDs we have to provide, try to fetch it from the blockstore.
30+
// But don't try for too long as this might be very expensive if you have a huge datastore.
31+
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
32+
defer cancel()
33+
34+
// FIXME: I want a running counter of blocks so size of blockstore can be an O(1) lookup.
35+
ch, err := bs.AllKeysChan(ctx)
36+
if err != nil {
37+
logger.Errorf("fetching AllKeysChain in provider ThroughputReport: %v", err)
38+
return false
39+
}
40+
count = 0
41+
countLoop:
42+
for {
43+
select {
44+
case _, ok := <-ch:
45+
if !ok {
46+
break countLoop
47+
}
48+
count++
49+
case <-ctx.Done():
50+
// really big blockstore mode
51+
52+
// how many blocks would be in a 10TiB blockstore with 128KiB blocks.
53+
const probableBigBlockstore = (10 * 1024 * 1024 * 1024 * 1024) / (128 * 1024)
54+
// How long per block that lasts us.
55+
expectedProvideSpeed := reprovideInterval / probableBigBlockstore
56+
if avgProvideSpeed > expectedProvideSpeed {
57+
// FIXME(@Jorropo): add link to the accelerated DHT client docs once this isn't experimental anymore.
58+
logger.Errorf(`
59+
🔔🔔🔔 YOU MAY BE FALLING BEHIND DHT REPROVIDES! 🔔🔔🔔
60+
61+
⚠️ Your system might be struggling to keep up with DHT reprovides!
62+
Meaning your content being partially or completely inacessible on the network.
63+
We observed that you recently provided %d keys at an average rate of %v per key.
64+
65+
🕑 An attempt to estimate your blockstore size timed out after 5 minutes,
66+
implying your blockstore might be exceedingly large. Assuming a considerable
67+
size of 10TiB, it would take %v to provide the complete set.
68+
69+
⏰ The total provide time needs to stay under 24 hours to prevent falling behind!
70+
71+
💡 Consider enabling the Accelerated DHT to enhance your system performance.`,
72+
keysProvided, avgProvideSpeed, avgProvideSpeed*probableBigBlockstore)
73+
return false
74+
}
75+
}
76+
}
77+
}
78+
79+
// How long per block that lasts us.
80+
expectedProvideSpeed := reprovideInterval / time.Duration(count)
81+
if avgProvideSpeed > expectedProvideSpeed {
82+
// FIXME(@Jorropo): add link to the accelerated DHT client docs once this isn't experimental anymore.
83+
logger.Errorf(`
84+
🔔🔔🔔 YOU ARE FALLING BEHIND DHT REPROVIDES! 🔔🔔🔔
85+
86+
⚠️ Your system is struggling to keep up with DHT reprovides!
87+
Meaning your content being partially or completely inacessible on the network.
88+
We observed that you recently provided %d keys at an average rate of %v per key.
89+
90+
💾 Your total CID count is ~%d which would total at %v reprovide process.
91+
92+
⏰ The total provide time needs to stay under 24 hours to prevent falling behind!
93+
94+
💡 Consider enabling the Accelerated DHT to enhance your reprovide throughput.`,
95+
keysProvided, avgProvideSpeed, count, avgProvideSpeed*time.Duration(count))
96+
}
97+
return false
98+
}, magicThroughputReportCount),
2299
)
23100
if err != nil {
24101
return nil, err
@@ -56,7 +133,7 @@ func OnlineProviders(useStrategicProviding bool, reprovideStrategy string, repro
56133

57134
return fx.Options(
58135
keyProvider,
59-
fx.Provide(ProviderSys(reprovideInterval)),
136+
ProviderSys(reprovideInterval),
60137
)
61138
}
62139

go.mod

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/gogo/protobuf v1.3.2
1717
github.com/google/uuid v1.3.0
1818
github.com/hashicorp/go-multierror v1.1.1
19-
github.com/ipfs/boxo v0.8.2-0.20230510114019-33e3f0cd052b
19+
github.com/ipfs/boxo v0.8.2-0.20230515125142-da153f4690bd
2020
github.com/ipfs/go-block-format v0.1.2
2121
github.com/ipfs/go-cid v0.4.1
2222
github.com/ipfs/go-cidutil v0.1.0
@@ -81,6 +81,7 @@ require (
8181
go.uber.org/fx v1.19.2
8282
go.uber.org/zap v1.24.0
8383
golang.org/x/crypto v0.9.0
84+
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
8485
golang.org/x/mod v0.10.0
8586
golang.org/x/sync v0.1.0
8687
golang.org/x/sys v0.8.0
@@ -214,7 +215,6 @@ require (
214215
go.uber.org/atomic v1.10.0 // indirect
215216
go.uber.org/multierr v1.11.0 // indirect
216217
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
217-
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
218218
golang.org/x/net v0.10.0 // indirect
219219
golang.org/x/oauth2 v0.5.0 // indirect
220220
golang.org/x/term v0.8.0 // indirect

go.sum

+6-2
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,12 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
354354
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
355355
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
356356
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
357-
github.com/ipfs/boxo v0.8.2-0.20230510114019-33e3f0cd052b h1:6EVpfwbBgwhfZOA19i55jOGokKOy+OaQAm1dg4RbXmc=
358-
github.com/ipfs/boxo v0.8.2-0.20230510114019-33e3f0cd052b/go.mod h1:Ej2r08Z4VIaFKqY08UXMNhwcLf6VekHhK8c+KqA1B9Y=
357+
github.com/ipfs/boxo v0.8.2-0.20230511175036-cedadbf667d7 h1:Nbe1zkYEMv81oRfJJH2kCyXr+ENuR+mbTko7/jvXEs8=
358+
github.com/ipfs/boxo v0.8.2-0.20230511175036-cedadbf667d7/go.mod h1:LbIQUU7IEKw2AMm8sCLgJ/hljd/4yyiMtPzc68nveOc=
359+
github.com/ipfs/boxo v0.8.2-0.20230511183253-30d1ef9a3fa6 h1:qaocp22F74W6YHDEE4qxS5Zn2b6lDN5mZeBbIVAgqFA=
360+
github.com/ipfs/boxo v0.8.2-0.20230511183253-30d1ef9a3fa6/go.mod h1:LbIQUU7IEKw2AMm8sCLgJ/hljd/4yyiMtPzc68nveOc=
361+
github.com/ipfs/boxo v0.8.2-0.20230515125142-da153f4690bd h1:2WrEH+ymhrJK7G0ouf6GhUvFTY7fBr0labD4+DHmgok=
362+
github.com/ipfs/boxo v0.8.2-0.20230515125142-da153f4690bd/go.mod h1:LbIQUU7IEKw2AMm8sCLgJ/hljd/4yyiMtPzc68nveOc=
359363
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
360364
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
361365
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=

0 commit comments

Comments
 (0)