Skip to content
This repository was archived by the owner on Jun 19, 2023. It is now read-only.

Commit a6bac41

Browse files
committed
fix(arc): striped locking on last byte of CID
1 parent 3d591e3 commit a6bac41

File tree

1 file changed

+26
-2
lines changed

1 file changed

+26
-2
lines changed

arc_cache.go

+26-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package blockstore
22

33
import (
44
"context"
5+
"sync"
56

67
lru "github.com/hashicorp/golang-lru"
78
blocks "github.com/ipfs/go-block-format"
@@ -16,7 +17,9 @@ type cacheSize int
1617
// block Cids. This provides block access-time improvements, allowing
1718
// to short-cut many searches without query-ing the underlying datastore.
1819
type arccache struct {
19-
arc *lru.TwoQueueCache
20+
arc *lru.TwoQueueCache
21+
lks [256]sync.Mutex
22+
2023
blockstore Blockstore
2124

2225
hits metrics.Counter
@@ -28,7 +31,7 @@ func newARCCachedBS(ctx context.Context, bs Blockstore, lruSize int) (*arccache,
2831
if err != nil {
2932
return nil, err
3033
}
31-
c := &arccache{arc: arc, blockstore: bs}
34+
c := &arccache{arc: arc, lks: [256]sync.Mutex{}, blockstore: bs}
3235
c.hits = metrics.NewCtx(ctx, "arc.hits_total", "Number of ARC cache hits").Counter()
3336
c.total = metrics.NewCtx(ctx, "arc_total", "Total number of ARC cache requests").Counter()
3437

@@ -40,6 +43,9 @@ func (b *arccache) DeleteBlock(k cid.Cid) error {
4043
return nil
4144
}
4245

46+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
47+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
48+
4349
b.arc.Remove(k) // Invalidate cache before deleting.
4450
err := b.blockstore.DeleteBlock(k)
4551
if err == nil {
@@ -76,6 +82,10 @@ func (b *arccache) Has(k cid.Cid) (bool, error) {
7682
if has, _, ok := b.hasCached(k); ok {
7783
return has, nil
7884
}
85+
86+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
87+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
88+
7989
has, err := b.blockstore.Has(k)
8090
if err != nil {
8191
return false, err
@@ -96,6 +106,10 @@ func (b *arccache) GetSize(k cid.Cid) (int, error) {
96106
}
97107
// we have it but don't know the size, ask the datastore.
98108
}
109+
110+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
111+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
112+
99113
blockSize, err := b.blockstore.GetSize(k)
100114
if err == ErrNotFound {
101115
b.cacheHave(k, false)
@@ -115,6 +129,9 @@ func (b *arccache) Get(k cid.Cid) (blocks.Block, error) {
115129
return nil, ErrNotFound
116130
}
117131

132+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
133+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
134+
118135
bl, err := b.blockstore.Get(k)
119136
if bl == nil && err == ErrNotFound {
120137
b.cacheHave(k, false)
@@ -129,6 +146,9 @@ func (b *arccache) Put(bl blocks.Block) error {
129146
return nil
130147
}
131148

149+
b.lks[bl.Cid().Bytes()[len(bl.Cid().Bytes())-1]].Lock()
150+
defer b.lks[bl.Cid().Bytes()[len(bl.Cid().Bytes())-1]].Unlock()
151+
132152
err := b.blockstore.Put(bl)
133153
if err == nil {
134154
b.cacheSize(bl.Cid(), len(bl.RawData()))
@@ -141,9 +161,13 @@ func (b *arccache) PutMany(bs []blocks.Block) error {
141161
for _, block := range bs {
142162
// call put on block if result is inconclusive or we are sure that
143163
// the block isn't in storage
164+
144165
if has, _, ok := b.hasCached(block.Cid()); !ok || (ok && !has) {
145166
good = append(good, block)
167+
b.lks[block.Cid().Bytes()[len(block.Cid().Bytes())-1]].Lock()
168+
defer b.lks[block.Cid().Bytes()[len(block.Cid().Bytes())-1]].Unlock()
146169
}
170+
147171
}
148172
err := b.blockstore.PutMany(good)
149173
if err != nil {

0 commit comments

Comments
 (0)