Skip to content

Commit fed535d

Browse files
authored
Introduce single power table cache (#1007)
* Vendor singleflight Signed-off-by: Jakub Sztandera <[email protected]> * Update singleflight to Generics Signed-off-by: Jakub Sztandera <[email protected]> * Introduce centralised power table cache Signed-off-by: Jakub Sztandera <[email protected]> * Include full BSD License Signed-off-by: Jakub Sztandera <[email protected]> * use standard singleflight package Signed-off-by: Jakub Sztandera <[email protected]> --------- Signed-off-by: Jakub Sztandera <[email protected]>
1 parent 298fe67 commit fed535d

File tree

4 files changed

+77
-5
lines changed

4 files changed

+77
-5
lines changed

ec/caching.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package ec
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/filecoin-project/go-f3/gpbft"
8+
lru "github.com/hashicorp/golang-lru/v2"
9+
"golang.org/x/sync/singleflight"
10+
)
11+
12+
type PowerCachingECWrapper struct {
13+
Backend
14+
15+
cache *lru.Cache[string, gpbft.PowerEntries]
16+
17+
smaphore chan struct{}
18+
dedup singleflight.Group
19+
}
20+
21+
func NewPowerCachingECWrapper(backend Backend, concurrency int, cacheSize int) *PowerCachingECWrapper {
22+
cache, err := lru.New[string, gpbft.PowerEntries](cacheSize)
23+
if err != nil {
24+
panic(err)
25+
}
26+
smaphore := make(chan struct{}, concurrency)
27+
28+
return &PowerCachingECWrapper{
29+
Backend: backend,
30+
cache: cache,
31+
smaphore: smaphore,
32+
}
33+
}
34+
35+
func (p *PowerCachingECWrapper) GetPowerTable(ctx context.Context, tsk gpbft.TipSetKey) (gpbft.PowerEntries, error) {
36+
entry, ok := p.cache.Get(string(tsk))
37+
if ok {
38+
return entry, nil
39+
}
40+
41+
ch := p.dedup.DoChan(string(tsk),
42+
// break context cancellation chain as the dedup group might start with short context and then get called with longer one
43+
func() (any, error) { return p.executeGetPowerTable(context.WithoutCancel(ctx), tsk) })
44+
45+
select {
46+
case <-ctx.Done():
47+
return nil, ctx.Err()
48+
case res := <-ch:
49+
if res.Err != nil {
50+
return nil, fmt.Errorf("getting power table: %w", res.Err)
51+
}
52+
return res.Val.(gpbft.PowerEntries), nil
53+
}
54+
}
55+
56+
func (p *PowerCachingECWrapper) executeGetPowerTable(ctx context.Context, tsk gpbft.TipSetKey) (gpbft.PowerEntries, error) {
57+
// take semaphore
58+
p.smaphore <- struct{}{}
59+
defer func() { <-p.smaphore }()
60+
61+
res, err := p.Backend.GetPowerTable(ctx, tsk)
62+
if err != nil {
63+
return nil, fmt.Errorf("getting power table: %w", err)
64+
}
65+
66+
p.cache.Add(string(tsk), res)
67+
return res, nil
68+
}

f3.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"errors"
66
"fmt"
77
"path/filepath"
8+
"runtime"
89
"strings"
910
"sync/atomic"
1011
"time"
@@ -62,16 +63,19 @@ type F3 struct {
6263
// New creates and setups f3 with libp2p
6364
// The context is used for initialization not runtime.
6465
func New(_ctx context.Context, manifest manifest.Manifest, ds datastore.Datastore, h host.Host,
65-
ps *pubsub.PubSub, verif gpbft.Verifier, ec ec.Backend, diskPath string) (*F3, error) {
66+
ps *pubsub.PubSub, verif gpbft.Verifier, ecBackend ec.Backend, diskPath string) (*F3, error) {
6667
runningCtx, cancel := context.WithCancel(context.WithoutCancel(_ctx))
68+
69+
// concurrency is limited to half of the number of CPUs, and cache size is set to 256 which is more than 2x max ECChain size
70+
ecBackend = ec.NewPowerCachingECWrapper(ecBackend, max(runtime.NumCPU()/2, 8), 256)
6771
return &F3{
6872
verifier: verif,
6973
mfst: manifest,
7074
diskPath: diskPath,
7175
outboundMessages: make(chan *gpbft.MessageBuilder, 128),
7276
host: h,
7377
ds: ds,
74-
ec: ec,
78+
ec: ecBackend,
7579
pubsub: ps,
7680
clock: clock.GetClock(runningCtx),
7781
runningCtx: runningCtx,

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ require (
3232
go.uber.org/zap v1.27.0
3333
golang.org/x/crypto v0.36.0
3434
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
35-
golang.org/x/sync v0.12.0
35+
golang.org/x/sync v0.15.0
3636
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
3737
)
3838

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,8 +616,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
616616
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
617617
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
618618
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
619-
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
620-
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
619+
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
620+
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
621621
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
622622
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
623623
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

0 commit comments

Comments
 (0)