Add lock overload protection (#20876)

Reject new lock requests immediately when 1000 goroutines are queued 
for the local lock mutex.

We do not reject unlocking, refreshing, or maintenance; they add to the count.

The limit is set to allow for bursty behavior but prevent requests from 
overloading the server completely.
This commit is contained in:
Klaus Post
2025-01-31 11:54:34 -08:00
committed by GitHub
parent abb385af41
commit bdb3db6dad
4 changed files with 290 additions and 122 deletions

View File

@@ -3,6 +3,8 @@ package cmd
// Code generated by github.com/tinylib/msgp DO NOT EDIT.
import (
"time"
"github.com/tinylib/msgp/msgp"
)
@@ -506,6 +508,36 @@ func (z *lockStats) DecodeMsg(dc *msgp.Reader) (err error) {
err = msgp.WrapError(err, "Reads")
return
}
case "LockQueue":
z.LockQueue, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "LockQueue")
return
}
case "LocksAbandoned":
z.LocksAbandoned, err = dc.ReadInt()
if err != nil {
err = msgp.WrapError(err, "LocksAbandoned")
return
}
case "LastCleanup":
if dc.IsNil() {
err = dc.ReadNil()
if err != nil {
err = msgp.WrapError(err, "LastCleanup")
return
}
z.LastCleanup = nil
} else {
if z.LastCleanup == nil {
z.LastCleanup = new(time.Time)
}
*z.LastCleanup, err = dc.ReadTime()
if err != nil {
err = msgp.WrapError(err, "LastCleanup")
return
}
}
default:
err = dc.Skip()
if err != nil {
@@ -518,10 +550,10 @@ func (z *lockStats) DecodeMsg(dc *msgp.Reader) (err error) {
}
// EncodeMsg implements msgp.Encodable
func (z lockStats) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 3
func (z *lockStats) EncodeMsg(en *msgp.Writer) (err error) {
// map header, size 6
// write "Total"
err = en.Append(0x83, 0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c)
err = en.Append(0x86, 0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c)
if err != nil {
return
}
@@ -550,15 +582,52 @@ func (z lockStats) EncodeMsg(en *msgp.Writer) (err error) {
err = msgp.WrapError(err, "Reads")
return
}
// write "LockQueue"
err = en.Append(0xa9, 0x4c, 0x6f, 0x63, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65)
if err != nil {
return
}
err = en.WriteInt(z.LockQueue)
if err != nil {
err = msgp.WrapError(err, "LockQueue")
return
}
// write "LocksAbandoned"
err = en.Append(0xae, 0x4c, 0x6f, 0x63, 0x6b, 0x73, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x64)
if err != nil {
return
}
err = en.WriteInt(z.LocksAbandoned)
if err != nil {
err = msgp.WrapError(err, "LocksAbandoned")
return
}
// write "LastCleanup"
err = en.Append(0xab, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x75, 0x70)
if err != nil {
return
}
if z.LastCleanup == nil {
err = en.WriteNil()
if err != nil {
return
}
} else {
err = en.WriteTime(*z.LastCleanup)
if err != nil {
err = msgp.WrapError(err, "LastCleanup")
return
}
}
return
}
// MarshalMsg implements msgp.Marshaler
func (z lockStats) MarshalMsg(b []byte) (o []byte, err error) {
func (z *lockStats) MarshalMsg(b []byte) (o []byte, err error) {
o = msgp.Require(b, z.Msgsize())
// map header, size 3
// map header, size 6
// string "Total"
o = append(o, 0x83, 0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c)
o = append(o, 0x86, 0xa5, 0x54, 0x6f, 0x74, 0x61, 0x6c)
o = msgp.AppendInt(o, z.Total)
// string "Writes"
o = append(o, 0xa6, 0x57, 0x72, 0x69, 0x74, 0x65, 0x73)
@@ -566,6 +635,19 @@ func (z lockStats) MarshalMsg(b []byte) (o []byte, err error) {
// string "Reads"
o = append(o, 0xa5, 0x52, 0x65, 0x61, 0x64, 0x73)
o = msgp.AppendInt(o, z.Reads)
// string "LockQueue"
o = append(o, 0xa9, 0x4c, 0x6f, 0x63, 0x6b, 0x51, 0x75, 0x65, 0x75, 0x65)
o = msgp.AppendInt(o, z.LockQueue)
// string "LocksAbandoned"
o = append(o, 0xae, 0x4c, 0x6f, 0x63, 0x6b, 0x73, 0x41, 0x62, 0x61, 0x6e, 0x64, 0x6f, 0x6e, 0x65, 0x64)
o = msgp.AppendInt(o, z.LocksAbandoned)
// string "LastCleanup"
o = append(o, 0xab, 0x4c, 0x61, 0x73, 0x74, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x75, 0x70)
if z.LastCleanup == nil {
o = msgp.AppendNil(o)
} else {
o = msgp.AppendTime(o, *z.LastCleanup)
}
return
}
@@ -605,6 +687,35 @@ func (z *lockStats) UnmarshalMsg(bts []byte) (o []byte, err error) {
err = msgp.WrapError(err, "Reads")
return
}
case "LockQueue":
z.LockQueue, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "LockQueue")
return
}
case "LocksAbandoned":
z.LocksAbandoned, bts, err = msgp.ReadIntBytes(bts)
if err != nil {
err = msgp.WrapError(err, "LocksAbandoned")
return
}
case "LastCleanup":
if msgp.IsNil(bts) {
bts, err = msgp.ReadNilBytes(bts)
if err != nil {
return
}
z.LastCleanup = nil
} else {
if z.LastCleanup == nil {
z.LastCleanup = new(time.Time)
}
*z.LastCleanup, bts, err = msgp.ReadTimeBytes(bts)
if err != nil {
err = msgp.WrapError(err, "LastCleanup")
return
}
}
default:
bts, err = msgp.Skip(bts)
if err != nil {
@@ -618,7 +729,12 @@ func (z *lockStats) UnmarshalMsg(bts []byte) (o []byte, err error) {
}
// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
func (z lockStats) Msgsize() (s int) {
s = 1 + 6 + msgp.IntSize + 7 + msgp.IntSize + 6 + msgp.IntSize
func (z *lockStats) Msgsize() (s int) {
s = 1 + 6 + msgp.IntSize + 7 + msgp.IntSize + 6 + msgp.IntSize + 10 + msgp.IntSize + 15 + msgp.IntSize + 12
if z.LastCleanup == nil {
s += msgp.NilSize
} else {
s += msgp.TimeSize
}
return
}