Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit b51e316

Browse files
authored
Merge pull request #544 from erizocosmico/fix/race-condition-object-lru
fix race condition on ObjectLRU
2 parents 7738417 + 3fd3988 commit b51e316

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

plumbing/cache/object_lru.go

+11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cache
22

33
import (
44
"container/list"
5+
"sync"
56

67
"gopkg.in/src-d/go-git.v4/plumbing"
78
)
@@ -14,6 +15,7 @@ type ObjectLRU struct {
1415
actualSize FileSize
1516
ll *list.List
1617
cache map[interface{}]*list.Element
18+
mut sync.Mutex
1719
}
1820

1921
// NewObjectLRU creates a new ObjectLRU with the given maximum size. The maximum
@@ -26,6 +28,9 @@ func NewObjectLRU(maxSize FileSize) *ObjectLRU {
2628
// will be marked as used. Otherwise, it will be inserted. A single object might
2729
// be evicted to make room for the new object.
2830
func (c *ObjectLRU) Put(obj plumbing.EncodedObject) {
31+
c.mut.Lock()
32+
defer c.mut.Unlock()
33+
2934
if c.cache == nil {
3035
c.actualSize = 0
3136
c.cache = make(map[interface{}]*list.Element, 1000)
@@ -67,6 +72,9 @@ func (c *ObjectLRU) Put(obj plumbing.EncodedObject) {
6772
// Get returns an object by its hash. It marks the object as used. If the object
6873
// is not in the cache, (nil, false) will be returned.
6974
func (c *ObjectLRU) Get(k plumbing.Hash) (plumbing.EncodedObject, bool) {
75+
c.mut.Lock()
76+
defer c.mut.Unlock()
77+
7078
ee, ok := c.cache[k]
7179
if !ok {
7280
return nil, false
@@ -78,6 +86,9 @@ func (c *ObjectLRU) Get(k plumbing.Hash) (plumbing.EncodedObject, bool) {
7886

7987
// Clear the content of this object cache.
8088
func (c *ObjectLRU) Clear() {
89+
c.mut.Lock()
90+
defer c.mut.Unlock()
91+
8192
c.ll = nil
8293
c.cache = nil
8394
c.actualSize = 0

plumbing/cache/object_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package cache
22

33
import (
4+
"fmt"
45
"io"
6+
"sync"
57
"testing"
68

79
"gopkg.in/src-d/go-git.v4/plumbing"
@@ -67,6 +69,32 @@ func (s *ObjectSuite) TestClear(c *C) {
6769
c.Assert(obj, IsNil)
6870
}
6971

72+
func (s *ObjectSuite) TestConcurrentAccess(c *C) {
73+
var wg sync.WaitGroup
74+
75+
for i := 0; i < 1000; i++ {
76+
wg.Add(3)
77+
go func(i int) {
78+
s.c.Put(newObject(fmt.Sprint(i), FileSize(i)))
79+
wg.Done()
80+
}(i)
81+
82+
go func(i int) {
83+
if i%30 == 0 {
84+
s.c.Clear()
85+
}
86+
wg.Done()
87+
}(i)
88+
89+
go func(i int) {
90+
s.c.Get(plumbing.NewHash(fmt.Sprint(i)))
91+
wg.Done()
92+
}(i)
93+
}
94+
95+
wg.Wait()
96+
}
97+
7098
type dummyObject struct {
7199
hash plumbing.Hash
72100
size FileSize

0 commit comments

Comments
 (0)