diff --git a/server/etcdserver/quota.go b/server/etcdserver/quota.go index 33c06e619..c5fadc4b1 100644 --- a/server/etcdserver/quota.go +++ b/server/etcdserver/quota.go @@ -125,8 +125,13 @@ 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/tests/integration/v3_alarm_test.go b/tests/integration/v3_alarm_test.go index d51fb53bb..576fb0591 100644 --- a/tests/integration/v3_alarm_test.go +++ b/tests/integration/v3_alarm_test.go @@ -89,6 +89,30 @@ func TestV3StorageQuotaApply(t *testing.T) { case <-time.After(10 * time.Millisecond): } } + + // 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()