blob: 945308a76f92b1407ada9573479d8963e5e05fe6 [file] [log] [blame]
// 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))
}()
}()
}
}