]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.15] sync: delete dirty keys inside Map.LoadAndDelete
authorChangkun Ou <hi@changkun.us>
Mon, 24 Aug 2020 11:45:27 +0000 (13:45 +0200)
committerBryan C. Mills <bcmills@google.com>
Thu, 27 Aug 2020 20:27:35 +0000 (20:27 +0000)
Updates #40999
Fixes #41011

Change-Id: Ie32427e5cb5ed512b976b554850f50be156ce9f2
Reviewed-on: https://go-review.googlesource.com/c/go/+/250197
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
(cherry picked from commit 94953d3e5928c8a577bad7911aabbf627269ef77)
Reviewed-on: https://go-review.googlesource.com/c/go/+/250297
Run-TryBot: Bryan C. Mills <bcmills@google.com>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
src/sync/map.go
src/sync/map_test.go

index a61e2ebdd67f72c07773eff50946dad1db6cbe74..9ad25353ff48cef7c541de24e3382c346dc44f61 100644 (file)
@@ -274,6 +274,7 @@ func (m *Map) LoadAndDelete(key interface{}) (value interface{}, loaded bool) {
                e, ok = read.m[key]
                if !ok && read.amended {
                        e, ok = m.dirty[key]
+                       delete(m.dirty, key)
                        // Regardless of whether the entry was present, record a miss: this key
                        // will take the slow path until the dirty map is promoted to the read
                        // map.
index 4ae989a6d5d8175108f3119888f70888ec252290..7f163caa5c95d111845844e41fa401065b4a9766 100644 (file)
@@ -9,6 +9,7 @@ import (
        "reflect"
        "runtime"
        "sync"
+       "sync/atomic"
        "testing"
        "testing/quick"
 )
@@ -171,3 +172,26 @@ func TestConcurrentRange(t *testing.T) {
                }
        }
 }
+
+func TestIssue40999(t *testing.T) {
+       var m sync.Map
+
+       // Since the miss-counting in missLocked (via Delete)
+       // compares the miss count with len(m.dirty),
+       // add an initial entry to bias len(m.dirty) above the miss count.
+       m.Store(nil, struct{}{})
+
+       var finalized uint32
+
+       // Set finalizers that count for collected keys. A non-zero count
+       // indicates that keys have not been leaked.
+       for atomic.LoadUint32(&finalized) == 0 {
+               p := new(int)
+               runtime.SetFinalizer(p, func(*int) {
+                       atomic.AddUint32(&finalized, 1)
+               })
+               m.Store(p, struct{}{})
+               m.Delete(p)
+               runtime.GC()
+       }
+}