From efa924440a1742320cd38083fdaafa2da9adbae3 Mon Sep 17 00:00:00 2001 From: Ringo Hoffmann Date: Tue, 9 Mar 2021 10:18:32 +0100 Subject: [PATCH 1/4] add concurrent get expired test [#4] --- .github/workflows/main-ci.yml | 4 ++-- timedmap_test.go | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index b1b8a4c..dd3fd45 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -29,7 +29,7 @@ jobs: go get -v -t -d ./... - name: Run Tests - run: go test -v -cover ./... + run: go test -v -timeout 300s -cover ./... - name: Run Benchmarks - run: go test -bench=. -benchmem + run: go test -timeout 300s -bench=. -benchmem diff --git a/timedmap_test.go b/timedmap_test.go index a15c202..c151f47 100644 --- a/timedmap_test.go +++ b/timedmap_test.go @@ -1,6 +1,7 @@ package timedmap import ( + "sync" "testing" "time" ) @@ -275,6 +276,27 @@ func TestConcurrentReadWrite(t *testing.T) { time.Sleep(1 * time.Second) } +func TestGetExpiredConcurrent(t *testing.T) { + tm := New(dCleanupTick) + + wg := sync.WaitGroup{} + for i := 0; i < 50_000; i++ { + wg.Add(1) + go func() { + defer wg.Done() + tm.Set(1, 1, 0) + }() + + wg.Add(1) + go func() { + defer wg.Done() + tm.GetValue(1) + }() + } + + wg.Wait() +} + func TestExternalTicker(t *testing.T) { const key = "tKeySet" const val = "tValSet" From e8e3b1e180ee1f4cee92391d9747b02bad4cfb19 Mon Sep 17 00:00:00 2001 From: Ringo Hoffmann Date: Tue, 9 Mar 2021 10:21:39 +0100 Subject: [PATCH 2/4] fix expiration lock on get expired [fix #4] --- timedmap.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/timedmap.go b/timedmap.go index e4ff8aa..9f81b12 100644 --- a/timedmap.go +++ b/timedmap.go @@ -228,6 +228,8 @@ func (tm *TimedMap) get(key interface{}, sec int) *element { } if time.Now().After(v.expires) { + tm.mtx.Lock() + defer tm.mtx.Unlock() tm.expireElement(key, sec, v) return nil } From d533e81127725cbffc472dcc6e37e3bc9e23d24e Mon Sep 17 00:00:00 2001 From: Ringo Hoffmann Date: Tue, 9 Mar 2021 10:24:41 +0100 Subject: [PATCH 3/4] fix tests for go <= 1.12 --- .github/workflows/main-ci.yml | 2 +- timedmap_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index dd3fd45..cd4dddf 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - go-version: [1.12, 1.13, 1.14, ^1.14] + go-version: [1.12, 1.13, 1.14, 1.15, ^1.16] steps: - name: Set up Go 1.x diff --git a/timedmap_test.go b/timedmap_test.go index c151f47..45b4ad3 100644 --- a/timedmap_test.go +++ b/timedmap_test.go @@ -280,7 +280,7 @@ func TestGetExpiredConcurrent(t *testing.T) { tm := New(dCleanupTick) wg := sync.WaitGroup{} - for i := 0; i < 50_000; i++ { + for i := 0; i < 50000; i++ { wg.Add(1) go func() { defer wg.Done() From aa5480a88c6f4456bda92f9ab290c6b7159e1ac2 Mon Sep 17 00:00:00 2001 From: Ringo Hoffmann Date: Tue, 9 Mar 2021 10:33:08 +0100 Subject: [PATCH 4/4] add changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..01e4fbb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## v1.3.1 + +- Fix `concurrent map read and map write` panic when accessing the map concurrently while getting an existing key, which is expired at the time. [#4] \ No newline at end of file