| // Copyright 2025 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a MIT |
| // license that can be found in the LICENSE file. |
| |
| /* |
| * Project: cockroach |
| * Issue or PR : https://github.com/cockroachdb/cockroach/pull/7504 |
| * Buggy version: bc963b438cdc3e0ad058a5282358e5aee0595e17 |
| * fix commit-id: cab761b9f5ee5dee1448bc5d6b1d9f5a0ff0bad5 |
| * Flaky: 1/100 |
| */ |
| package main |
| |
| import ( |
| "os" |
| "runtime" |
| "runtime/pprof" |
| "sync" |
| "time" |
| ) |
| |
| func init() { |
| register("Cockroach7504", Cockroach7504) |
| } |
| |
| func MakeCacheKey_cockroach7504(lease *LeaseState_cockroach7504) int { |
| return lease.id |
| } |
| |
| type LeaseState_cockroach7504 struct { |
| mu sync.Mutex // L1 |
| id int |
| } |
| type LeaseSet_cockroach7504 struct { |
| data []*LeaseState_cockroach7504 |
| } |
| |
| func (l *LeaseSet_cockroach7504) find(id int) *LeaseState_cockroach7504 { |
| return l.data[id] |
| } |
| |
| func (l *LeaseSet_cockroach7504) remove(s *LeaseState_cockroach7504) { |
| for i := 0; i < len(l.data); i++ { |
| if s == l.data[i] { |
| l.data = append(l.data[:i], l.data[i+1:]...) |
| break |
| } |
| } |
| } |
| |
| type tableState_cockroach7504 struct { |
| tableNameCache *tableNameCache_cockroach7504 |
| mu sync.Mutex // L3 |
| active *LeaseSet_cockroach7504 |
| } |
| |
| func (t *tableState_cockroach7504) release(lease *LeaseState_cockroach7504) { |
| t.mu.Lock() // L3 |
| defer t.mu.Unlock() // L3 |
| |
| s := t.active.find(MakeCacheKey_cockroach7504(lease)) |
| s.mu.Lock() // L1 |
| runtime.Gosched() |
| defer s.mu.Unlock() // L1 |
| |
| t.removeLease(s) |
| } |
| func (t *tableState_cockroach7504) removeLease(lease *LeaseState_cockroach7504) { |
| t.active.remove(lease) |
| t.tableNameCache.remove(lease) // L1 acquire/release |
| } |
| |
| type tableNameCache_cockroach7504 struct { |
| mu sync.Mutex // L2 |
| tables map[int]*LeaseState_cockroach7504 |
| } |
| |
| func (c *tableNameCache_cockroach7504) get(id int) { |
| c.mu.Lock() // L2 |
| defer c.mu.Unlock() // L2 |
| lease, ok := c.tables[id] |
| if !ok { |
| return |
| } |
| if lease == nil { |
| panic("nil lease in name cache") |
| } |
| lease.mu.Lock() // L1 |
| defer lease.mu.Unlock() // L1 |
| } |
| |
| func (c *tableNameCache_cockroach7504) remove(lease *LeaseState_cockroach7504) { |
| c.mu.Lock() // L2 |
| runtime.Gosched() |
| defer c.mu.Unlock() // L2 |
| key := MakeCacheKey_cockroach7504(lease) |
| existing, ok := c.tables[key] |
| if !ok { |
| return |
| } |
| if existing == lease { |
| delete(c.tables, key) |
| } |
| } |
| |
| type LeaseManager_cockroach7504 struct { |
| _ [64]byte |
| tableNames *tableNameCache_cockroach7504 |
| tables map[int]*tableState_cockroach7504 |
| } |
| |
| func (m *LeaseManager_cockroach7504) AcquireByName(id int) { |
| m.tableNames.get(id) |
| } |
| |
| func (m *LeaseManager_cockroach7504) findTableState(lease *LeaseState_cockroach7504) *tableState_cockroach7504 { |
| existing, ok := m.tables[lease.id] |
| if !ok { |
| return nil |
| } |
| return existing |
| } |
| |
| func (m *LeaseManager_cockroach7504) Release(lease *LeaseState_cockroach7504) { |
| t := m.findTableState(lease) |
| t.release(lease) |
| } |
| func NewLeaseManager_cockroach7504(tname *tableNameCache_cockroach7504, ts *tableState_cockroach7504) *LeaseManager_cockroach7504 { |
| mgr := &LeaseManager_cockroach7504{ |
| tableNames: tname, |
| tables: make(map[int]*tableState_cockroach7504), |
| } |
| mgr.tables[0] = ts |
| return mgr |
| } |
| func NewLeaseSet_cockroach7504(n int) *LeaseSet_cockroach7504 { |
| lset := &LeaseSet_cockroach7504{} |
| for i := 0; i < n; i++ { |
| lease := new(LeaseState_cockroach7504) |
| lset.data = append(lset.data, lease) |
| } |
| return lset |
| } |
| |
| func Cockroach7504() { |
| prof := pprof.Lookup("goroutineleak") |
| defer func() { |
| time.Sleep(100 * time.Millisecond) |
| prof.WriteTo(os.Stdout, 2) |
| }() |
| for i := 0; i < 100; i++ { |
| go func() { |
| leaseNum := 2 |
| lset := NewLeaseSet_cockroach7504(leaseNum) |
| |
| nc := &tableNameCache_cockroach7504{ |
| tables: make(map[int]*LeaseState_cockroach7504), |
| } |
| for i := 0; i < leaseNum; i++ { |
| nc.tables[i] = lset.find(i) |
| } |
| |
| ts := &tableState_cockroach7504{ |
| tableNameCache: nc, |
| active: lset, |
| } |
| |
| mgr := NewLeaseManager_cockroach7504(nc, ts) |
| |
| // G1 |
| go func() { |
| // lock L2-L1 |
| mgr.AcquireByName(0) |
| }() |
| |
| // G2 |
| go func() { |
| // lock L1-L2 |
| mgr.Release(lset.find(0)) |
| }() |
| }() |
| } |
| } |