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

Commit 66266c5

Browse files
committed
fix(arc): striped locking on last byte of CID
- fixes #64
1 parent fb07d7b commit 66266c5

File tree

1 file changed

+27
-2
lines changed

1 file changed

+27
-2
lines changed

arc_cache.go

+27-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"
@@ -17,7 +18,9 @@ type cacheSize int
1718
// size. This provides block access-time improvements, allowing
1819
// to short-cut many searches without querying the underlying datastore.
1920
type arccache struct {
20-
cache *lru.TwoQueueCache
21+
cache *lru.TwoQueueCache
22+
lks [256]sync.Mutex
23+
2124
blockstore Blockstore
2225
viewer Viewer
2326

@@ -33,7 +36,7 @@ func newARCCachedBS(ctx context.Context, bs Blockstore, lruSize int) (*arccache,
3336
if err != nil {
3437
return nil, err
3538
}
36-
c := &arccache{cache: cache, blockstore: bs}
39+
c := &arccache{cache: cache, lks: [256]sync.Mutex{}, blockstore: bs}
3740
c.hits = metrics.NewCtx(ctx, "arc.hits_total", "Number of ARC cache hits").Counter()
3841
c.total = metrics.NewCtx(ctx, "arc_total", "Total number of ARC cache requests").Counter()
3942
if v, ok := bs.(Viewer); ok {
@@ -47,6 +50,9 @@ func (b *arccache) DeleteBlock(k cid.Cid) error {
4750
return nil
4851
}
4952

53+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
54+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
55+
5056
b.cache.Remove(k) // Invalidate cache before deleting.
5157
err := b.blockstore.DeleteBlock(k)
5258
if err == nil {
@@ -59,6 +65,10 @@ func (b *arccache) Has(k cid.Cid) (bool, error) {
5965
if has, _, ok := b.queryCache(k); ok {
6066
return has, nil
6167
}
68+
69+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
70+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
71+
6272
has, err := b.blockstore.Has(k)
6373
if err != nil {
6474
return false, err
@@ -79,6 +89,10 @@ func (b *arccache) GetSize(k cid.Cid) (int, error) {
7989
}
8090
// we have it but don't know the size, ask the datastore.
8191
}
92+
93+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
94+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
95+
8296
blockSize, err := b.blockstore.GetSize(k)
8397
if err == ErrNotFound {
8498
b.cacheHave(k, false)
@@ -110,6 +124,9 @@ func (b *arccache) View(k cid.Cid, callback func([]byte) error) error {
110124
return ErrNotFound
111125
}
112126

127+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
128+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
129+
113130
return b.viewer.View(k, callback)
114131
}
115132

@@ -123,6 +140,9 @@ func (b *arccache) Get(k cid.Cid) (blocks.Block, error) {
123140
return nil, ErrNotFound
124141
}
125142

143+
b.lks[k.Bytes()[len(k.Bytes())-1]].Lock()
144+
defer b.lks[k.Bytes()[len(k.Bytes())-1]].Unlock()
145+
126146
bl, err := b.blockstore.Get(k)
127147
if bl == nil && err == ErrNotFound {
128148
b.cacheHave(k, false)
@@ -137,6 +157,9 @@ func (b *arccache) Put(bl blocks.Block) error {
137157
return nil
138158
}
139159

160+
b.lks[bl.Cid().Bytes()[len(bl.Cid().Bytes())-1]].Lock()
161+
defer b.lks[bl.Cid().Bytes()[len(bl.Cid().Bytes())-1]].Unlock()
162+
140163
err := b.blockstore.Put(bl)
141164
if err == nil {
142165
b.cacheSize(bl.Cid(), len(bl.RawData()))
@@ -151,6 +174,8 @@ func (b *arccache) PutMany(bs []blocks.Block) error {
151174
// the block isn't in storage
152175
if has, _, ok := b.queryCache(block.Cid()); !ok || (ok && !has) {
153176
good = append(good, block)
177+
b.lks[block.Cid().Bytes()[len(block.Cid().Bytes())-1]].Lock()
178+
defer b.lks[block.Cid().Bytes()[len(block.Cid().Bytes())-1]].Unlock()
154179
}
155180
}
156181
err := b.blockstore.PutMany(good)

0 commit comments

Comments
 (0)