diff --git a/etcdserver/quota.go b/etcdserver/quota.go index 6d70430e73cb..a26c66a6aba5 100644 --- a/etcdserver/quota.go +++ b/etcdserver/quota.go @@ -135,8 +135,14 @@ func NewBackendQuota(s *EtcdServer, name string) Quota { } func (b *backendQuota) Available(v interface{}) bool { + cost := b.Cost(v) + // if there are no mutating requests, it's safe to pass through + if cost == 0 { + return true + } + // TODO: maybe optimize backend.Size() - return b.s.Backend().Size()+int64(b.Cost(v)) < b.maxBackendBytes + return b.s.Backend().Size()+int64(cost) < b.maxBackendBytes } func (b *backendQuota) Cost(v interface{}) int { diff --git a/integration/v3_alarm_test.go b/integration/v3_alarm_test.go index 9a71f87f26d3..cee34ddff52a 100644 --- a/integration/v3_alarm_test.go +++ b/integration/v3_alarm_test.go @@ -92,6 +92,30 @@ func TestV3StorageQuotaApply(t *testing.T) { } } + // txn with non-mutating Ops should go through when NOSPACE alarm is raised + _, err = kvc0.Txn(context.TODO(), &pb.TxnRequest{ + Compare: []*pb.Compare{ + { + Key: key, + Result: pb.Compare_EQUAL, + Target: pb.Compare_CREATE, + TargetUnion: &pb.Compare_CreateRevision{CreateRevision: 0}, + }, + }, + Success: []*pb.RequestOp{ + { + Request: &pb.RequestOp_RequestDeleteRange{ + RequestDeleteRange: &pb.DeleteRangeRequest{ + Key: key, + }, + }, + }, + }, + }) + if err != nil { + t.Fatal(err) + } + ctx, cancel := context.WithTimeout(context.TODO(), RequestWaitTimeout) defer cancel()