Merge pull request #25243 from smarterclayton/explore_quantity

Provide an int64 version of Quantity that is much faster
This commit is contained in:
Daniel Smith 2016-05-19 16:56:48 -07:00
commit 5448400b1c
52 changed files with 2592 additions and 1217 deletions

View File

@ -927,10 +927,10 @@ func parseResourceList(m utilconfig.ConfigurationMap) (api.ResourceList, error)
if err != nil {
return nil, err
}
if q.Amount.Sign() == -1 {
if q.Sign() == -1 {
return nil, fmt.Errorf("resource quantity for %q cannot be negative: %v", k, v)
}
rl[api.ResourceName(k)] = *q
rl[api.ResourceName(k)] = q
default:
return nil, fmt.Errorf("cannot reserve %q resource", k)
}

View File

@ -85,14 +85,8 @@ func podResources(pod *api.Pod, resourceName api.ResourceName, def, min resource
}
// add up the request and limit sum for all containers
err = requestSum.Add(request)
if err != nil {
return
}
err = limitSum.Add(limit)
if err != nil {
return
}
requestSum.Add(request)
limitSum.Add(limit)
// optionally write request and limit back
if write {

View File

@ -25,11 +25,10 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg4_inf_v0 "gopkg.in/inf.v0"
pkg1_api "k8s.io/kubernetes/pkg/api"
pkg3_resource "k8s.io/kubernetes/pkg/api/resource"
pkg2_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg5_types "k8s.io/kubernetes/pkg/types"
pkg4_types "k8s.io/kubernetes/pkg/types"
"reflect"
"runtime"
time "time"
@ -65,13 +64,12 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg4_inf_v0.Dec
var v1 pkg1_api.ConditionStatus
var v2 pkg3_resource.Quantity
var v3 pkg2_unversioned.Time
var v4 pkg5_types.UID
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
var v0 pkg1_api.ConditionStatus
var v1 pkg3_resource.Quantity
var v2 pkg2_unversioned.Time
var v3 pkg4_types.UID
var v4 time.Time
_, _, _, _, _ = v0, v1, v2, v3, v4
}
}

View File

@ -25,11 +25,10 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg4_inf_v0 "gopkg.in/inf.v0"
pkg3_resource "k8s.io/kubernetes/pkg/api/resource"
pkg2_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg1_v1 "k8s.io/kubernetes/pkg/api/v1"
pkg5_types "k8s.io/kubernetes/pkg/types"
pkg4_types "k8s.io/kubernetes/pkg/types"
"reflect"
"runtime"
time "time"
@ -65,13 +64,12 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg4_inf_v0.Dec
var v1 pkg3_resource.Quantity
var v2 pkg2_unversioned.Time
var v3 pkg1_v1.ConditionStatus
var v4 pkg5_types.UID
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
var v0 pkg3_resource.Quantity
var v1 pkg2_unversioned.Time
var v2 pkg1_v1.ConditionStatus
var v3 pkg4_types.UID
var v4 time.Time
_, _, _, _, _ = v0, v1, v2, v3, v4
}
}

View File

@ -68,7 +68,7 @@ else
linux/amd64
linux/arm
linux/arm64
linux/ppc64le
#linux/ppc64le # temporarily disabled due to a linking error
)
# If we update this we should also update the set of golang compilers we build
@ -78,7 +78,7 @@ else
linux/386
linux/arm
linux/arm64
linux/ppc64le
#linux/ppc64le # temporarily disabled due to a linking error
darwin/amd64
darwin/386
windows/amd64

View File

@ -58,16 +58,7 @@ var Semantic = conversion.EqualitiesOrDie(
// TODO: if we decide it's important, it should be safe to start comparing the format.
//
// Uninitialized quantities are equivalent to 0 quantities.
if a.Amount == nil && b.MilliValue() == 0 {
return true
}
if b.Amount == nil && a.MilliValue() == 0 {
return true
}
if a.Amount == nil || b.Amount == nil {
return false
}
return a.Amount.Cmp(b.Amount) == 0
return a.Cmp(b) == 0
},
func(a, b unversioned.Time) bool {
return a.UTC() == b.UTC()

View File

@ -23,8 +23,6 @@ import (
"k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/labels"
inf "gopkg.in/inf.v0"
)
func TestConversionError(t *testing.T) {
@ -56,8 +54,8 @@ func TestSemantic(t *testing.T) {
{resource.Quantity{}, resource.MustParse("0"), true},
{resource.Quantity{}, resource.MustParse("1m"), false},
{
resource.Quantity{Amount: inf.NewDec(5, 0), Format: resource.BinarySI},
resource.Quantity{Amount: inf.NewDec(5, 0), Format: resource.DecimalSI},
resource.NewQuantity(5, resource.BinarySI),
resource.NewQuantity(5, resource.DecimalSI),
true,
},
{resource.MustParse("2m"), resource.MustParse("1m"), false},

298
pkg/api/resource/amount.go Normal file
View File

@ -0,0 +1,298 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"math/big"
"strconv"
inf "gopkg.in/inf.v0"
)
// Scale is used for getting and setting the base-10 scaled value.
// Base-2 scales are omitted for mathematical simplicity.
// See Quantity.ScaledValue for more details.
type Scale int32
// infScale adapts a Scale value to an inf.Scale value.
func (s Scale) infScale() inf.Scale {
return inf.Scale(-s) // inf.Scale is upside-down
}
const (
Nano Scale = -9
Micro Scale = -6
Milli Scale = -3
Kilo Scale = 3
Mega Scale = 6
Giga Scale = 9
Tera Scale = 12
Peta Scale = 15
Exa Scale = 18
)
var (
Zero = int64Amount{}
// Used by quantity strings - treat as read only
zeroBytes = []byte("0")
)
// int64Amount represents a fixed precision numerator and arbitary scale exponent. It is faster
// than operations on inf.Dec for values that can be represented as int64.
type int64Amount struct {
value int64
scale Scale
}
// Sign returns 0 if the value is zero, -1 if it is less than 0, or 1 if it is greater than 0.
func (a int64Amount) Sign() int {
switch {
case a.value == 0:
return 0
case a.value > 0:
return 1
default:
return -1
}
}
// AsInt64 returns the current amount as an int64 at scale 0, or false if the value cannot be
// represented in an int64 OR would result in a loss of precision. This method is intended as
// an optimization to avoid calling AsDec.
func (a int64Amount) AsInt64() (int64, bool) {
if a.scale == 0 {
return a.value, true
}
if a.scale < 0 {
// TODO: attempt to reduce factors, although it is assumed that factors are reduced prior
// to the int64Amount being created.
return 0, false
}
return positiveScaleInt64(a.value, a.scale)
}
// AsScaledInt64 returns an int64 representing the value of this amount at the specified scale,
// rounding up, or false if that would result in overflow. (1e20).AsScaledInt64(1) would result
// in overflow because 1e19 is not representable as an int64. Note that setting a scale larger
// than the current value may result in loss of precision - i.e. (1e-6).AsScaledInt64(0) would
// return 1, because 0.000001 is rounded up to 1.
func (a int64Amount) AsScaledInt64(scale Scale) (result int64, ok bool) {
if a.scale < scale {
result, _ = negativeScaleInt64(a.value, scale-a.scale)
return result, true
}
return positiveScaleInt64(a.value, a.scale-scale)
}
// AsDec returns an inf.Dec representation of this value.
func (a int64Amount) AsDec() *inf.Dec {
var base inf.Dec
base.SetUnscaled(a.value)
base.SetScale(inf.Scale(-a.scale))
return &base
}
// Cmp returns 0 if a and b are equal, 1 if a is greater than b, or -1 if a is less than b.
func (a int64Amount) Cmp(b int64Amount) int {
switch {
case a.scale == b.scale:
// compare only the unscaled portion
case a.scale > b.scale:
result, remainder, exact := divideByScaleInt64(b.value, a.scale-b.scale)
if !exact {
return a.AsDec().Cmp(b.AsDec())
}
if result == a.value {
switch {
case remainder == 0:
return 0
case remainder > 0:
return -1
default:
return 1
}
}
b.value = result
default:
result, remainder, exact := divideByScaleInt64(a.value, b.scale-a.scale)
if !exact {
return a.AsDec().Cmp(b.AsDec())
}
if result == b.value {
switch {
case remainder == 0:
return 0
case remainder > 0:
return 1
default:
return -1
}
}
a.value = result
}
switch {
case a.value == b.value:
return 0
case a.value < b.value:
return -1
default:
return 1
}
}
// Add adds two int64Amounts together, matching scales. It will return false and not mutate
// a if overflow or underflow would result.
func (a *int64Amount) Add(b int64Amount) bool {
switch {
case b.value == 0:
return true
case a.value == 0:
a.value = b.value
a.scale = b.scale
return true
case a.scale == b.scale:
c, ok := int64Add(a.value, b.value)
if !ok {
return false
}
a.value = c
case a.scale > b.scale:
c, ok := positiveScaleInt64(a.value, a.scale-b.scale)
if !ok {
return false
}
c, ok = int64Add(c, b.value)
if !ok {
return false
}
a.scale = b.scale
a.value = c
default:
c, ok := positiveScaleInt64(b.value, b.scale-a.scale)
if !ok {
return false
}
c, ok = int64Add(a.value, c)
if !ok {
return false
}
a.value = c
}
return true
}
// Sub removes the value of b from the current amount, or returns false if underflow would result.
func (a *int64Amount) Sub(b int64Amount) bool {
return a.Add(int64Amount{value: -b.value, scale: b.scale})
}
// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
func (a int64Amount) AsScale(scale Scale) (int64Amount, bool) {
if a.scale >= scale {
return a, true
}
result, exact := negativeScaleInt64(a.value, scale-a.scale)
return int64Amount{value: result, scale: scale}, exact
}
// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
func (a int64Amount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
mantissa := a.value
exponent = int32(a.scale)
amount, times := removeInt64Factors(mantissa, 10)
exponent += int32(times)
// make sure exponent is a multiple of 3
var ok bool
switch exponent % 3 {
case 1, -2:
amount, ok = int64MultiplyScale10(amount)
if !ok {
return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
}
exponent = exponent - 1
case 2, -1:
amount, ok = int64MultiplyScale100(amount)
if !ok {
return infDecAmount{a.AsDec()}.AsCanonicalBytes(out)
}
exponent = exponent - 2
}
return strconv.AppendInt(out, amount, 10), exponent
}
// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
// return []byte("2048"), 1.
func (a int64Amount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
value, ok := a.AsScaledInt64(0)
if !ok {
return infDecAmount{a.AsDec()}.AsCanonicalBase1024Bytes(out)
}
amount, exponent := removeInt64Factors(value, 1024)
return strconv.AppendInt(out, amount, 10), exponent
}
// infDecAmount implements common operations over an inf.Dec that are specific to the quantity
// representation.
type infDecAmount struct {
*inf.Dec
}
// AsScale adjusts this amount to set a minimum scale, rounding up, and returns true iff no precision
// was lost. (1.1e5).AsScale(5) would return 1.1e5, but (1.1e5).AsScale(6) would return 1e6.
func (a infDecAmount) AsScale(scale Scale) (infDecAmount, bool) {
tmp := &inf.Dec{}
tmp.Round(a.Dec, scale.infScale(), inf.RoundUp)
return infDecAmount{tmp}, tmp.Cmp(a.Dec) == 0
}
// AsCanonicalBytes accepts a buffer to write the base-10 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. The value is adjusted
// until the exponent is a multiple of 3 - i.e. 1.1e5 would return "110", 3.
func (a infDecAmount) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
mantissa := a.Dec.UnscaledBig()
exponent = int32(-a.Dec.Scale())
amount := big.NewInt(0).Set(mantissa)
// move all factors of 10 into the exponent for easy reasoning
amount, times := removeBigIntFactors(amount, bigTen)
exponent += times
// make sure exponent is a multiple of 3
for exponent%3 != 0 {
amount.Mul(amount, bigTen)
exponent--
}
return append(out, amount.String()...), exponent
}
// AsCanonicalBase1024Bytes accepts a buffer to write the base-1024 string value of this field to, and returns
// either that buffer or a larger buffer and the current exponent of the value. 2048 is 2 * 1024 ^ 1 and would
// return []byte("2048"), 1.
func (a infDecAmount) AsCanonicalBase1024Bytes(out []byte) (result []byte, exponent int32) {
tmp := &inf.Dec{}
tmp.Round(a.Dec, 0, inf.RoundUp)
amount, exponent := removeBigIntFactors(tmp.UnscaledBig(), big1024)
return append(out, amount.String()...), exponent
}

View File

@ -0,0 +1,111 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"testing"
)
func TestInt64AmountAsInt64(t *testing.T) {
for _, test := range []struct {
value int64
scale Scale
result int64
ok bool
}{
{100, 0, 100, true},
{100, 1, 1000, true},
{100, -5, 0, false},
{100, 100, 0, false},
} {
r, ok := int64Amount{value: test.value, scale: test.scale}.AsInt64()
if r != test.result {
t.Errorf("%v: unexpected result: %d", test, r)
}
if ok != test.ok {
t.Errorf("%v: unexpected ok: %t", test, ok)
}
}
}
func TestInt64AmountAdd(t *testing.T) {
for _, test := range []struct {
a, b, c int64Amount
ok bool
}{
{int64Amount{value: 100, scale: 1}, int64Amount{value: 10, scale: 2}, int64Amount{value: 200, scale: 1}, true},
{int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 2}, int64Amount{value: 110, scale: 1}, true},
{int64Amount{value: 100, scale: 1}, int64Amount{value: 1, scale: 100}, int64Amount{value: 1, scale: 100}, false},
{int64Amount{value: -5, scale: 2}, int64Amount{value: 50, scale: 1}, int64Amount{value: 0, scale: 1}, true},
{int64Amount{value: -5, scale: 2}, int64Amount{value: 5, scale: 2}, int64Amount{value: 0, scale: 2}, true},
{int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 1, scale: -1}, int64Amount{value: 0, scale: -1}, false},
{int64Amount{value: mostPositive, scale: -1}, int64Amount{value: 0, scale: -1}, int64Amount{value: mostPositive, scale: -1}, true},
{int64Amount{value: mostPositive / 10, scale: 1}, int64Amount{value: 10, scale: 0}, int64Amount{value: mostPositive, scale: -1}, false},
} {
c := test.a
ok := c.Add(test.b)
if ok != test.ok {
t.Errorf("%v: unexpected ok: %t", test, ok)
}
if ok {
if c != test.c {
t.Errorf("%v: unexpected result: %d", test, c)
}
} else {
if c != test.a {
t.Errorf("%v: overflow addition mutated source: %d", test, c)
}
}
// addition is commutative
c = test.b
if ok := c.Add(test.a); ok != test.ok {
t.Errorf("%v: unexpected ok: %t", test, ok)
}
if ok {
if c != test.c {
t.Errorf("%v: unexpected result: %d", test, c)
}
} else {
if c != test.b {
t.Errorf("%v: overflow addition mutated source: %d", test, c)
}
}
}
}
func TestInt64AsCanonicalString(t *testing.T) {
for _, test := range []struct {
value int64
scale Scale
result string
exponent int32
}{
{100, 0, "100", 0},
{100, 1, "1", 3},
{100, -1, "10", 0},
{10800, -10, "1080", -9},
} {
r, exp := int64Amount{value: test.value, scale: test.scale}.AsCanonicalBytes(nil)
if string(r) != test.result {
t.Errorf("%v: unexpected result: %s", test, r)
}
if exp != test.exponent {
t.Errorf("%v: unexpected exponent: %d", test, exp)
}
}
}

View File

@ -21,35 +21,27 @@ limitations under the License.
package resource
import (
inf_v0 "gopkg.in/inf.v0"
conversion "k8s.io/kubernetes/pkg/conversion"
)
func DeepCopy_resource_Quantity(in Quantity, out *Quantity, c *conversion.Cloner) error {
if in.Amount != nil {
in, out := in.Amount, &out.Amount
*out = new(inf_v0.Dec)
if newVal, err := c.DeepCopy(*in); err != nil {
if newVal, err := c.DeepCopy(in.i); err != nil {
return err
} else {
**out = newVal.(inf_v0.Dec)
out.i = newVal.(int64Amount)
}
if newVal, err := c.DeepCopy(in.d); err != nil {
return err
} else {
out.Amount = nil
out.d = newVal.(infDecAmount)
}
out.Format = in.Format
return nil
}
func DeepCopy_resource_QuantityProto(in QuantityProto, out *QuantityProto, c *conversion.Cloner) error {
out.Format = in.Format
out.Scale = in.Scale
if in.Bigint != nil {
in, out := in.Bigint, &out.Bigint
if in.s != nil {
in, out := in.s, &out.s
*out = make([]byte, len(in))
copy(*out, in)
} else {
out.Bigint = nil
out.s = nil
}
out.Format = in.Format
return nil
}

View File

@ -26,7 +26,6 @@ limitations under the License.
It has these top-level messages:
Quantity
QuantityProto
*/
package resource
@ -34,8 +33,6 @@ import proto "github.com/gogo/protobuf/proto"
import fmt "fmt"
import math "math"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
@ -44,328 +41,6 @@ var _ = math.Inf
func (m *Quantity) Reset() { *m = Quantity{} }
func (*Quantity) ProtoMessage() {}
func (m *QuantityProto) Reset() { *m = QuantityProto{} }
func (m *QuantityProto) String() string { return proto.CompactTextString(m) }
func (*QuantityProto) ProtoMessage() {}
func init() {
proto.RegisterType((*Quantity)(nil), "k8s.io.kubernetes.pkg.api.resource.Quantity")
proto.RegisterType((*QuantityProto)(nil), "k8s.io.kubernetes.pkg.api.resource.QuantityProto")
}
func (m *QuantityProto) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
if err != nil {
return nil, err
}
return data[:n], nil
}
func (m *QuantityProto) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
data[i] = 0xa
i++
i = encodeVarintGenerated(data, i, uint64(len(m.Format)))
i += copy(data[i:], m.Format)
data[i] = 0x10
i++
i = encodeVarintGenerated(data, i, uint64(m.Scale))
if m.Bigint != nil {
data[i] = 0x1a
i++
i = encodeVarintGenerated(data, i, uint64(len(m.Bigint)))
i += copy(data[i:], m.Bigint)
}
return i, nil
}
func encodeFixed64Generated(data []byte, offset int, v uint64) int {
data[offset] = uint8(v)
data[offset+1] = uint8(v >> 8)
data[offset+2] = uint8(v >> 16)
data[offset+3] = uint8(v >> 24)
data[offset+4] = uint8(v >> 32)
data[offset+5] = uint8(v >> 40)
data[offset+6] = uint8(v >> 48)
data[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Generated(data []byte, offset int, v uint32) int {
data[offset] = uint8(v)
data[offset+1] = uint8(v >> 8)
data[offset+2] = uint8(v >> 16)
data[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintGenerated(data []byte, offset int, v uint64) int {
for v >= 1<<7 {
data[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
data[offset] = uint8(v)
return offset + 1
}
func (m *QuantityProto) Size() (n int) {
var l int
_ = l
l = len(m.Format)
n += 1 + l + sovGenerated(uint64(l))
n += 1 + sovGenerated(uint64(m.Scale))
if m.Bigint != nil {
l = len(m.Bigint)
n += 1 + l + sovGenerated(uint64(l))
}
return n
}
func sovGenerated(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozGenerated(x uint64) (n int) {
return sovGenerated(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *QuantityProto) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: QuantityProto: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: QuantityProto: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Format", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Format = Format(data[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Scale", wireType)
}
m.Scale = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.Scale |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Bigint", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Bigint = append(m.Bigint[:0], data[iNdEx:postIndex]...)
if m.Bigint == nil {
m.Bigint = []byte{}
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(data[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGenerated(data []byte) (n int, err error) {
l := len(data)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if data[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthGenerated
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipGenerated(data[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow")
)

View File

@ -84,26 +84,10 @@ option go_package = "resource";
// cause implementors to also use a fixed point implementation.
//
// +protobuf=true
// +protobuf.embed=QuantityProto
// +protobuf.embed=string
// +protobuf.options.marshal=false
// +protobuf.options.(gogoproto.goproto_stringer)=false
message Quantity {
optional QuantityProto QuantityProto = 1;
}
// QuantityProto is a struct that is equivalent to Quantity, but intended for
// protobuf marshalling/unmarshalling. It is generated into a serialization
// that matches Quantity. Do not use in Go structs.
//
// +protobuf=true
message QuantityProto {
// The format of the quantity
optional string format = 1;
// The scale dimension of the value
optional int32 scale = 2;
// Bigint is serialized as a raw bytes array
optional bytes bigint = 3;
optional string string = 1;
}

327
pkg/api/resource/math.go Normal file
View File

@ -0,0 +1,327 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"math/big"
inf "gopkg.in/inf.v0"
)
const (
// maxInt64Factors is the highest value that will be checked when removing factors of 10 from an int64.
// It is also the maximum decimal digits that can be represented with an int64.
maxInt64Factors = 18
)
var (
// Commonly needed big.Int values-- treat as read only!
bigTen = big.NewInt(10)
bigZero = big.NewInt(0)
bigOne = big.NewInt(1)
bigThousand = big.NewInt(1000)
big1024 = big.NewInt(1024)
// Commonly needed inf.Dec values-- treat as read only!
decZero = inf.NewDec(0, 0)
decOne = inf.NewDec(1, 0)
decMinusOne = inf.NewDec(-1, 0)
decThousand = inf.NewDec(1000, 0)
dec1024 = inf.NewDec(1024, 0)
decMinus1024 = inf.NewDec(-1024, 0)
// Largest (in magnitude) number allowed.
maxAllowed = infDecAmount{inf.NewDec((1<<63)-1, 0)} // == max int64
// The maximum value we can represent milli-units for.
// Compare with the return value of Quantity.Value() to
// see if it's safe to use Quantity.MilliValue().
MaxMilliValue = int64(((1 << 63) - 1) / 1000)
)
const mostNegative = -(mostPositive + 1)
const mostPositive = 1<<63 - 1
// int64Add returns a+b, or false if that would overflow int64.
func int64Add(a, b int64) (int64, bool) {
c := a + b
switch {
case a > 0 && b > 0:
if c < 0 {
return 0, false
}
case a < 0 && b < 0:
if c > 0 {
return 0, false
}
if a == mostNegative && b == mostNegative {
return 0, false
}
}
return c, true
}
// int64Multiply returns a*b, or false if that would overflow or underflow int64.
func int64Multiply(a, b int64) (int64, bool) {
if a == 0 || b == 0 || a == 1 || b == 1 {
return a * b, true
}
if a == mostNegative || b == mostNegative {
return 0, false
}
c := a * b
return c, c/b == a
}
// int64MultiplyScale returns a*b, assuming b is greater than one, or false if that would overflow or underflow int64.
// Use when b is known to be greater than one.
func int64MultiplyScale(a int64, b int64) (int64, bool) {
if a == 0 || a == 1 {
return a * b, true
}
if a == mostNegative && b != 1 {
return 0, false
}
c := a * b
return c, c/b == a
}
// int64MultiplyScale10 multiplies a by 10, or returns false if that would overflow. This method is faster than
// int64Multiply(a, 10) because the compiler can optimize constant factor multiplication.
func int64MultiplyScale10(a int64) (int64, bool) {
if a == 0 || a == 1 {
return a * 10, true
}
if a == mostNegative {
return 0, false
}
c := a * 10
return c, c/10 == a
}
// int64MultiplyScale100 multiplies a by 100, or returns false if that would overflow. This method is faster than
// int64Multiply(a, 100) because the compiler can optimize constant factor multiplication.
func int64MultiplyScale100(a int64) (int64, bool) {
if a == 0 || a == 1 {
return a * 100, true
}
if a == mostNegative {
return 0, false
}
c := a * 100
return c, c/100 == a
}
// int64MultiplyScale1000 multiplies a by 1000, or returns false if that would overflow. This method is faster than
// int64Multiply(a, 1000) because the compiler can optimize constant factor multiplication.
func int64MultiplyScale1000(a int64) (int64, bool) {
if a == 0 || a == 1 {
return a * 1000, true
}
if a == mostNegative {
return 0, false
}
c := a * 1000
return c, c/1000 == a
}
// positiveScaleInt64 multiplies base by 10^scale, returning false if the
// value overflows. Passing a negative scale is undefined.
func positiveScaleInt64(base int64, scale Scale) (int64, bool) {
switch scale {
case 0:
return base, true
case 1:
return int64MultiplyScale10(base)
case 2:
return int64MultiplyScale100(base)
case 3:
return int64MultiplyScale1000(base)
case 6:
return int64MultiplyScale(base, 1000000)
case 9:
return int64MultiplyScale(base, 1000000000)
default:
value := base
var ok bool
for i := Scale(0); i < scale; i++ {
if value, ok = int64MultiplyScale(value, 10); !ok {
return 0, false
}
}
return value, true
}
}
// negativeScaleInt64 reduces base by the provided scale, rounding up, until the
// value is zero or the scale is reached. Passing a negative scale is undefined.
// The value returned, if not exact, is rounded away from zero.
func negativeScaleInt64(base int64, scale Scale) (result int64, exact bool) {
if scale == 0 {
return base, true
}
value := base
var fraction bool
for i := Scale(0); i < scale; i++ {
if !fraction && value%10 != 0 {
fraction = true
}
value = value / 10
if value == 0 {
if fraction {
if base > 0 {
return 1, false
}
return -1, false
}
return 0, true
}
}
if fraction {
if base > 0 {
value += 1
} else {
value += -1
}
}
return value, !fraction
}
func pow10Int64(b int64) int64 {
switch b {
case 0:
return 1
case 1:
return 10
case 2:
return 100
case 3:
return 1000
case 4:
return 10000
case 5:
return 100000
case 6:
return 1000000
case 7:
return 10000000
case 8:
return 100000000
case 9:
return 1000000000
case 10:
return 10000000000
case 11:
return 100000000000
case 12:
return 1000000000000
case 13:
return 10000000000000
case 14:
return 100000000000000
case 15:
return 1000000000000000
case 16:
return 10000000000000000
case 17:
return 100000000000000000
case 18:
return 1000000000000000000
default:
return 0
}
}
// powInt64 raises a to the bth power. Is not overflow aware.
func powInt64(a, b int64) int64 {
p := int64(1)
for b > 0 {
if b&1 != 0 {
p *= a
}
b >>= 1
a *= a
}
return p
}
// negativeScaleInt64 returns the result of dividing base by scale * 10 and the remainder, or
// false if no such division is possible. Dividing by negative scales is undefined.
func divideByScaleInt64(base int64, scale Scale) (result, remainder int64, exact bool) {
if scale == 0 {
return base, 0, true
}
// the max scale representable in base 10 in an int64 is 18 decimal places
if scale >= 18 {
return 0, base, false
}
divisor := pow10Int64(int64(scale))
return base / divisor, base % divisor, true
}
// removeInt64Factors divides in a loop; the return values have the property that
// value == result * base ^ scale
func removeInt64Factors(value int64, base int64) (result int64, times int32) {
times = 0
result = value
negative := result < 0
if negative {
result = -result
}
switch base {
// allow the compiler to optimize the common cases
case 10:
for result >= 10 && result%10 == 0 {
times++
result = result / 10
}
// allow the compiler to optimize the common cases
case 1024:
for result >= 1024 && result%1024 == 0 {
times++
result = result / 1024
}
default:
for result >= base && result%base == 0 {
times++
result = result / base
}
}
if negative {
result = -result
}
return result, times
}
// removeBigIntFactors divides in a loop; the return values have the property that
// d == result * factor ^ times
// d may be modified in place.
// If d == 0, then the return values will be (0, 0)
func removeBigIntFactors(d, factor *big.Int) (result *big.Int, times int32) {
q := big.NewInt(0)
m := big.NewInt(0)
for d.Cmp(bigZero) != 0 {
q.DivMod(d, factor, m)
if m.Cmp(bigZero) != 0 {
break
}
times++
d, q = q, d
}
return d, times
}

View File

@ -0,0 +1,211 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resource
import (
"testing"
)
func TestDetectOverflowAdd(t *testing.T) {
for _, test := range []struct {
a, b int64
c int64
ok bool
}{
{0, 0, 0, true},
{-1, 1, 0, true},
{0, 1, 1, true},
{2, 2, 4, true},
{2, -2, 0, true},
{-2, -2, -4, true},
{mostNegative, -1, 0, false},
{mostNegative, 1, mostNegative + 1, true},
{mostPositive, -1, mostPositive - 1, true},
{mostPositive, 1, 0, false},
{mostNegative, mostPositive, -1, true},
{mostPositive, mostNegative, -1, true},
{mostPositive, mostPositive, 0, false},
{mostNegative, mostNegative, 0, false},
{-mostPositive, mostNegative, 0, false},
{mostNegative, -mostPositive, 0, false},
{-mostPositive, -mostPositive, 0, false},
} {
c, ok := int64Add(test.a, test.b)
if c != test.c {
t.Errorf("%v: unexpected result: %d", test, c)
}
if ok != test.ok {
t.Errorf("%v: unexpected overflow: %t", test, ok)
}
// addition is commutative
d, ok2 := int64Add(test.b, test.a)
if c != d || ok != ok2 {
t.Errorf("%v: not commutative: %d %t", test, d, ok2)
}
}
}
func TestDetectOverflowMultiply(t *testing.T) {
for _, test := range []struct {
a, b int64
c int64
ok bool
}{
{0, 0, 0, true},
{-1, 1, -1, true},
{-1, -1, 1, true},
{1, 1, 1, true},
{0, 1, 0, true},
{1, 0, 0, true},
{2, 2, 4, true},
{2, -2, -4, true},
{-2, -2, 4, true},
{mostNegative, -1, 0, false},
{mostNegative, 1, mostNegative, true},
{mostPositive, -1, -mostPositive, true},
{mostPositive, 1, mostPositive, true},
{mostNegative, mostPositive, 0, false},
{mostPositive, mostNegative, 0, false},
{mostPositive, mostPositive, 1, false},
{mostNegative, mostNegative, 0, false},
{-mostPositive, mostNegative, 0, false},
{mostNegative, -mostPositive, 0, false},
{-mostPositive, -mostPositive, 1, false},
} {
c, ok := int64Multiply(test.a, test.b)
if c != test.c {
t.Errorf("%v: unexpected result: %d", test, c)
}
if ok != test.ok {
t.Errorf("%v: unexpected overflow: %t", test, ok)
}
// multiplication is commutative
d, ok2 := int64Multiply(test.b, test.a)
if c != d || ok != ok2 {
t.Errorf("%v: not commutative: %d %t", test, d, ok2)
}
}
}
func TestDetectOverflowScale(t *testing.T) {
for _, a := range []int64{0, -1, 1, 10, -10, mostPositive, mostNegative, -mostPositive} {
for _, b := range []int64{1, 2, 10, 100, 1000, mostPositive} {
expect, expectOk := int64Multiply(a, b)
c, ok := int64MultiplyScale(a, b)
if c != expect {
t.Errorf("%d*%d: unexpected result: %d", a, b, c)
}
if ok != expectOk {
t.Errorf("%d*%d: unexpected overflow: %t", a, b, ok)
}
}
for _, test := range []struct {
base int64
fn func(a int64) (int64, bool)
}{
{10, int64MultiplyScale10},
{100, int64MultiplyScale100},
{1000, int64MultiplyScale1000},
} {
expect, expectOk := int64Multiply(a, test.base)
c, ok := test.fn(a)
if c != expect {
t.Errorf("%d*%d: unexpected result: %d", a, test.base, c)
}
if ok != expectOk {
t.Errorf("%d*%d: unexpected overflow: %t", a, test.base, ok)
}
}
}
}
func TestRemoveInt64Factors(t *testing.T) {
for _, test := range []struct {
value int64
max int64
result int64
scale int32
}{
{100, 10, 1, 2},
{100, 10, 1, 2},
{100, 100, 1, 1},
{1, 10, 1, 0},
} {
r, s := removeInt64Factors(test.value, test.max)
if r != test.result {
t.Errorf("%v: unexpected result: %d", test, r)
}
if s != test.scale {
t.Errorf("%v: unexpected scale: %d", test, s)
}
}
}
func TestNegativeScaleInt64(t *testing.T) {
for _, test := range []struct {
base int64
scale Scale
result int64
exact bool
}{
{1234567, 0, 1234567, true},
{1234567, 1, 123457, false},
{1234567, 2, 12346, false},
{1234567, 3, 1235, false},
{1234567, 4, 124, false},
{-1234567, 0, -1234567, true},
{-1234567, 1, -123457, false},
{-1234567, 2, -12346, false},
{-1234567, 3, -1235, false},
{-1234567, 4, -124, false},
{1000, 0, 1000, true},
{1000, 1, 100, true},
{1000, 2, 10, true},
{1000, 3, 1, true},
{1000, 4, 1, false},
{-1000, 0, -1000, true},
{-1000, 1, -100, true},
{-1000, 2, -10, true},
{-1000, 3, -1, true},
{-1000, 4, -1, false},
{0, 0, 0, true},
{0, 1, 0, true},
{0, 2, 0, true},
// negative scale is undefined behavior
{1000, -1, 1000, true},
} {
result, exact := negativeScaleInt64(test.base, test.scale)
if result != test.result {
t.Errorf("%v: unexpected result: %d", test, result)
}
if exact != test.exact {
t.Errorf("%v: unexpected exact: %t", test, exact)
}
}
}

View File

@ -17,10 +17,12 @@ limitations under the License.
package resource
import (
"bytes"
"errors"
"fmt"
"math/big"
"regexp"
"strconv"
"strings"
flag "github.com/spf13/pflag"
@ -86,19 +88,34 @@ import (
// cause implementors to also use a fixed point implementation.
//
// +protobuf=true
// +protobuf.embed=QuantityProto
// +protobuf.embed=string
// +protobuf.options.marshal=false
// +protobuf.options.(gogoproto.goproto_stringer)=false
type Quantity struct {
// Amount is public, so you can manipulate it if the accessor
// functions are not sufficient.
Amount *inf.Dec
// i is the quantity in int64 scaled form, if d.Dec == nil
i int64Amount
// d is the quantity in inf.Dec form if d.Dec != nil
d infDecAmount
// s is the generated value of this quantity to avoid recalculation
s []byte
// Change Format at will. See the comment for Canonicalize for
// more details.
Format
}
// CanonicalValue allows a quantity amount to be converted to a string.
type CanonicalValue interface {
// AsCanonicalBytes returns a byte array representing the string representation
// of the value mantissa and an int32 representing its exponent in base-10. Callers may
// pass a byte slice to the method to avoid allocations.
AsCanonicalBytes(out []byte) ([]byte, int32)
// AsCanonicalBase1024Bytes returns a byte array representing the string representation
// of the value mantissa and an int32 representing its exponent in base-1024. Callers
// may pass a byte slice to the method to avoid allocations.
AsCanonicalBase1024Bytes(out []byte) ([]byte, int32)
}
// Format lists the three possible formattings of a quantity.
type Format string
@ -115,26 +132,9 @@ func MustParse(str string) Quantity {
if err != nil {
panic(fmt.Errorf("cannot parse '%v': %v", str, err))
}
return *q
return q
}
// Scale is used for getting and setting the base-10 scaled value.
// Base-2 scales are omitted for mathematical simplicity.
// See Quantity.ScaledValue for more details.
type Scale int
const (
Nano Scale = -9
Micro Scale = -6
Milli Scale = -3
Kilo Scale = 3
Mega Scale = 6
Giga Scale = 9
Tera Scale = 12
Peta Scale = 15
Exa Scale = 18
)
const (
// splitREString is used to separate a number from its suffix; as such,
// this is overly permissive, but that's OK-- it will be checked later.
@ -149,47 +149,189 @@ var (
ErrFormatWrong = errors.New("quantities must match the regular expression '" + splitREString + "'")
ErrNumeric = errors.New("unable to parse numeric part of quantity")
ErrSuffix = errors.New("unable to parse quantity's suffix")
// Commonly needed big.Int values-- treat as read only!
bigTen = big.NewInt(10)
bigZero = big.NewInt(0)
bigOne = big.NewInt(1)
bigThousand = big.NewInt(1000)
big1024 = big.NewInt(1024)
// Commonly needed inf.Dec values-- treat as read only!
decZero = inf.NewDec(0, 0)
decOne = inf.NewDec(1, 0)
decMinusOne = inf.NewDec(-1, 0)
decThousand = inf.NewDec(1000, 0)
dec1024 = inf.NewDec(1024, 0)
decMinus1024 = inf.NewDec(-1024, 0)
// Largest (in magnitude) number allowed.
maxAllowed = inf.NewDec((1<<63)-1, 0) // == max int64
// The maximum value we can represent milli-units for.
// Compare with the return value of Quantity.Value() to
// see if it's safe to use Quantity.MilliValue().
MaxMilliValue = int64(((1 << 63) - 1) / 1000)
)
// parseQuantityString is a fast scanner for quantity values.
func parseQuantityString(str string) (positive bool, value, num, denom, suffix string, err error) {
positive = true
pos := 0
end := len(str)
// handle leading sign
if pos < end {
switch str[0] {
case '-':
positive = false
pos++
case '+':
pos++
}
}
// strip leading zeros
Zeroes:
for i := pos; ; i++ {
if i >= end {
num = "0"
value = num
return
}
switch str[i] {
case '0':
pos++
default:
break Zeroes
}
}
// extract the numerator
Num:
for i := pos; ; i++ {
if i >= end {
num = str[pos:end]
value = str[0:end]
return
}
switch str[i] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
num = str[pos:i]
pos = i
break Num
}
}
// if we stripped all numerator positions, always return 0
if len(num) == 0 {
num = "0"
}
// handle a denominator
if pos < end && str[pos] == '.' {
pos++
Denom:
for i := pos; ; i++ {
if i >= end {
denom = str[pos:end]
value = str[0:end]
return
}
switch str[i] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
denom = str[pos:i]
pos = i
break Denom
}
}
// TODO: we currently allow 1.G, but we may not want to in the future.
// if len(denom) == 0 {
// err = ErrFormatWrong
// return
// }
}
value = str[0:pos]
// grab the elements of the suffix
suffixStart := pos
for i := pos; ; i++ {
if i >= end {
suffix = str[suffixStart:end]
return
}
if !strings.ContainsAny(str[i:i+1], "eEinumkKMGTP") {
pos = i
break
}
}
if pos < end {
switch str[pos] {
case '-', '+':
pos++
}
}
Suffix:
for i := pos; ; i++ {
if i >= end {
suffix = str[suffixStart:end]
return
}
switch str[i] {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
default:
pos = i
break Suffix
}
}
// we encountered a non decimal in the Suffix loop, but the last character
// was not a valid exponent
err = ErrFormatWrong
return
}
// ParseQuantity turns str into a Quantity, or returns an error.
func ParseQuantity(str string) (*Quantity, error) {
parts := splitRE.FindStringSubmatch(strings.TrimSpace(str))
// regexp returns are entire match, followed by an entry for each () section.
if len(parts) != 3 {
return nil, ErrFormatWrong
func ParseQuantity(str string) (Quantity, error) {
if len(str) == 0 {
return Quantity{}, ErrFormatWrong
}
if str == "0" {
return Quantity{Format: DecimalSI}, nil
}
positive, value, num, denom, suf, err := parseQuantityString(str)
if err != nil {
return Quantity{}, err
}
base, exponent, format, ok := quantitySuffixer.interpret(suffix(suf))
if !ok {
return Quantity{}, ErrSuffix
}
precision := int32(0)
scale := int32(0)
mantissa := int64(1)
switch format {
case DecimalExponent, DecimalSI:
scale = exponent
precision = maxInt64Factors - int32(len(num)+len(denom))
case BinarySI:
scale = 0
switch {
case exponent >= 0 && len(denom) == 0:
// only handle positive binary numbers with the fast path
mantissa = int64(int64(mantissa) << uint64(exponent))
// 1Mi (2^20) has ~6 digits of decimal precision, so exponent*3/10 -1 is roughly the precision
precision = 15 - int32(len(num)) - int32(float32(exponent)*3/10) - 1
default:
precision = -1
}
}
if precision >= 0 {
// if we have a denominator, shift the entire value to the left by the number of places in the
// denominator
scale -= int32(len(denom))
if scale >= int32(Nano) {
shifted := num + denom
var value int64
value, err := strconv.ParseInt(shifted, 10, 64)
if err != nil {
return Quantity{}, ErrNumeric
}
if result, ok := int64Multiply(value, int64(mantissa)); ok {
if !positive {
result = -result
}
return Quantity{i: int64Amount{value: result, scale: Scale(scale)}, Format: format}, nil
}
}
}
amount := new(inf.Dec)
if _, ok := amount.SetString(parts[1]); !ok {
return nil, ErrNumeric
}
base, exponent, format, ok := quantitySuffixer.interpret(suffix(parts[2]))
if !ok {
return nil, ErrSuffix
if _, ok := amount.SetString(value); !ok {
return Quantity{}, ErrNumeric
}
// So that no one but us has to think about suffixes, remove it.
@ -217,9 +359,11 @@ func ParseQuantity(str string) (*Quantity, error) {
}
// The max is just a simple cap.
if amount.Cmp(maxAllowed) > 0 {
amount.Set(maxAllowed)
// TODO: this prevents accumulating quantities greater than int64, for instance quota across a cluster
if format == BinarySI && amount.Cmp(maxAllowed.Dec) > 0 {
amount.Set(maxAllowed.Dec)
}
if format == BinarySI && amount.Cmp(decOne) < 0 && amount.Cmp(decZero) > 0 {
// This avoids rounding and hopefully confusion, too.
format = DecimalSI
@ -228,25 +372,7 @@ func ParseQuantity(str string) (*Quantity, error) {
amount.Neg(amount)
}
return &Quantity{amount, format}, nil
}
// removeFactors divides in a loop; the return values have the property that
// d == result * factor ^ times
// d may be modified in place.
// If d == 0, then the return values will be (0, 0)
func removeFactors(d, factor *big.Int) (result *big.Int, times int) {
q := big.NewInt(0)
m := big.NewInt(0)
for d.Cmp(bigZero) != 0 {
q.DivMod(d, factor, m)
if m.Cmp(bigZero) != 0 {
break
}
times++
d, q = q, d
}
return d, times
return Quantity{d: infDecAmount{amount}, Format: format}, nil
}
// Canonicalize returns the canonical form of q and its suffix (see comment on Quantity).
@ -256,27 +382,22 @@ func removeFactors(d, factor *big.Int) (result *big.Int, times int) {
// -1 and +1, it will be emitted as if q.Format were DecimalSI.
// * Otherwise, if q.Format is set to BinarySI, frational parts of q.Amount will be
// rounded up. (1.1i becomes 2i.)
func (q *Quantity) Canonicalize() (string, suffix) {
if q.Amount == nil {
return "0", ""
}
// zero is zero always
if q.Amount.Cmp(&inf.Dec{}) == 0 {
return "0", ""
func (q *Quantity) CanonicalizeBytes(out []byte) (result, suffix []byte) {
if q.IsZero() {
return zeroBytes, nil
}
var rounded CanonicalValue
format := q.Format
switch format {
case DecimalExponent, DecimalSI:
case BinarySI:
if q.Amount.Cmp(decMinus1024) > 0 && q.Amount.Cmp(dec1024) < 0 {
if q.CmpInt64(-1024) > 0 && q.CmpInt64(1024) < 0 {
// This avoids rounding and hopefully confusion, too.
format = DecimalSI
} else {
tmp := &inf.Dec{}
tmp.Round(q.Amount, 0, inf.RoundUp)
if tmp.Cmp(q.Amount) != 0 {
var exact bool
if rounded, exact = q.AsScale(0); !exact {
// Don't lose precision-- show as DecimalSI
format = DecimalSI
}
@ -289,125 +410,223 @@ func (q *Quantity) Canonicalize() (string, suffix) {
// one of the other formats.
switch format {
case DecimalExponent, DecimalSI:
mantissa := q.Amount.UnscaledBig()
exponent := int(-q.Amount.Scale())
amount := big.NewInt(0).Set(mantissa)
// move all factors of 10 into the exponent for easy reasoning
amount, times := removeFactors(amount, bigTen)
exponent += times
// make sure exponent is a multiple of 3
for exponent%3 != 0 {
amount.Mul(amount, bigTen)
exponent--
}
suffix, _ := quantitySuffixer.construct(10, exponent, format)
number := amount.String()
number, exponent := q.AsCanonicalBytes(out)
suffix, _ := quantitySuffixer.constructBytes(10, exponent, format)
return number, suffix
case BinarySI:
tmp := &inf.Dec{}
tmp.Round(q.Amount, 0, inf.RoundUp)
amount, exponent := removeFactors(tmp.UnscaledBig(), big1024)
suffix, _ := quantitySuffixer.construct(2, exponent*10, format)
number := amount.String()
default:
// format must be BinarySI
number, exponent := rounded.AsCanonicalBase1024Bytes(out)
suffix, _ := quantitySuffixer.constructBytes(2, exponent*10, format)
return number, suffix
}
return "0", ""
}
// AsInt64 returns a representation of the current value as an int64 if a fast conversion
// is possible. If false is returned, callers must use the inf.Dec form of this quantity.
func (q *Quantity) AsInt64() (int64, bool) {
if q.d.Dec != nil {
return 0, false
}
return q.i.AsInt64()
}
// ToDec promotes the quantity in place to use an inf.Dec representation and returns itself.
func (q *Quantity) ToDec() *Quantity {
if q.d.Dec == nil {
q.d.Dec = q.i.AsDec()
q.i = int64Amount{}
}
return q
}
// AsDec returns the quantity as represented by a scaled inf.Dec.
func (q *Quantity) AsDec() *inf.Dec {
if q.d.Dec != nil {
return q.d.Dec
}
q.d.Dec = q.i.AsDec()
q.i = int64Amount{}
return q.d.Dec
}
// AsCanonicalBytes returns the canonical byte representation of this quantity as a mantissa
// and base 10 exponent. The out byte slice may be passed to the method to avoid an extra
// allocation.
func (q *Quantity) AsCanonicalBytes(out []byte) (result []byte, exponent int32) {
if q.d.Dec != nil {
return q.d.AsCanonicalBytes(out)
}
return q.i.AsCanonicalBytes(out)
}
// IsZero returns true if the quantity is equal to zero.
func (q *Quantity) IsZero() bool {
if q.d.Dec != nil {
return q.d.Dec.Sign() == 0
}
return q.i.value == 0
}
// Sign returns 0 if the quantity is zero, -1 if the quantity is less than zero, or 1 if the
// quantity is greater than zero.
func (q *Quantity) Sign() int {
if q.d.Dec != nil {
return q.d.Dec.Sign()
}
return q.i.Sign()
}
// AsScaled returns the current value, rounded up to the provided scale, and returns
// false if the scale resulted in a loss of precision.
func (q *Quantity) AsScale(scale Scale) (CanonicalValue, bool) {
if q.d.Dec != nil {
return q.d.AsScale(scale)
}
return q.i.AsScale(scale)
}
// RoundUp updates the quantity to the provided scale, ensuring that the value is at
// least 1. False is returned if the rounding operation resulted in a loss of precision.
// Negative numbers are rounded away from zero (-9 scale 1 rounds to -10).
func (q *Quantity) RoundUp(scale Scale) bool {
if q.d.Dec != nil {
d, exact := q.d.AsScale(scale)
q.d = d
return exact
}
i, exact := q.i.AsScale(scale)
q.i = i
return exact
}
// Add adds the provide y quantity to the current value. If the current value is zero,
// the format of the quantity will be updated to the format of y.
func (q *Quantity) Add(y Quantity) {
q.s = nil
if q.d.Dec == nil && y.d.Dec == nil {
if q.i.value == 0 {
q.Format = y.Format
}
if q.i.Add(y.i) {
return
}
} else if q.IsZero() {
q.Format = y.Format
}
q.ToDec().d.Dec.Add(q.d.Dec, y.AsDec())
}
// Sub subtracts the provided quantity from the current value in place. If the current
// value is zero, the format of the quantity will be updated to the format of y.
func (q *Quantity) Sub(y Quantity) {
q.s = nil
if q.IsZero() {
q.Format = y.Format
}
if q.d.Dec == nil && y.d.Dec == nil && q.i.Sub(y.i) {
return
}
q.ToDec().d.Dec.Sub(q.d.Dec, y.AsDec())
}
// Cmp returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
// quantity is greater than y.
func (q *Quantity) Cmp(y Quantity) int {
if q.d.Dec == nil && y.d.Dec == nil {
return q.i.Cmp(y.i)
}
return q.AsDec().Cmp(y.AsDec())
}
// CmpInt64 returns 0 if the quantity is equal to y, -1 if the quantity is less than y, or 1 if the
// quantity is greater than y.
func (q *Quantity) CmpInt64(y int64) int {
if q.d.Dec != nil {
return q.d.Dec.Cmp(inf.NewDec(y, inf.Scale(0)))
}
return q.i.Cmp(int64Amount{value: y})
}
// Neg sets quantity to be the negative value of itself.
func (q *Quantity) Neg() {
q.s = nil
if q.d.Dec == nil {
q.i.value = -q.i.value
return
}
q.d.Dec.Neg(q.d.Dec)
}
// toBytes ensures q.s is set to a byte slice representing the canonical string form of this
// quantity and then returns the value. CanonicalizeBytes is an expensive operation, and caching
// this result significantly reduces the cost of normal parse / marshal operations on Quantity.
func (q *Quantity) toBytes() []byte {
if q.s == nil {
result := make([]byte, 0, int64QuantityExpectedBytes)
number, suffix := q.CanonicalizeBytes(result)
number = append(number, suffix...)
q.s = number
}
return q.s
}
// int64QuantityExpectedBytes is the expected width in bytes of the canonical string representation
// of most Quantity values.
const int64QuantityExpectedBytes = 18
// String formats the Quantity as a string.
func (q *Quantity) String() string {
number, suffix := q.Canonicalize()
return number + string(suffix)
}
// Cmp compares q and y and returns:
//
// -1 if q < y
// 0 if q == y
// +1 if q > y
//
func (q *Quantity) Cmp(y Quantity) int {
if q.Amount == nil {
if y.Amount == nil {
return 0
}
return -y.Amount.Sign()
}
if y.Amount == nil {
return q.Amount.Sign()
}
return q.Amount.Cmp(y.Amount)
}
func (q *Quantity) Add(y Quantity) error {
switch {
case y.Amount == nil:
// Adding 0: do nothing.
case q.Amount == nil:
q.Amount = &inf.Dec{}
return q.Add(y)
default:
// we want to preserve the format of the non-zero value
zero := &inf.Dec{}
if q.Amount.Cmp(zero) == 0 && y.Amount.Cmp(zero) != 0 {
q.Format = y.Format
}
q.Amount.Add(q.Amount, y.Amount)
}
return nil
}
func (q *Quantity) Sub(y Quantity) error {
switch {
case y.Amount == nil:
// Subtracting 0: do nothing.
case q.Amount == nil:
q.Amount = &inf.Dec{}
return q.Sub(y)
default:
// we want to preserve the format of the non-zero value
zero := &inf.Dec{}
if q.Amount.Cmp(zero) == 0 && y.Amount.Cmp(zero) != 0 {
q.Format = y.Format
}
q.Amount.Sub(q.Amount, y.Amount)
}
return nil
}
// Neg sets q to the negative value of y.
// It updates the format of q to match y.
func (q *Quantity) Neg(y Quantity) error {
switch {
case y.Amount == nil:
*q = y
case q.Amount == nil:
q.Amount = &inf.Dec{}
fallthrough
default:
q.Amount.Neg(y.Amount)
q.Format = y.Format
}
return nil
return string(q.toBytes())
}
// MarshalJSON implements the json.Marshaller interface.
func (q Quantity) MarshalJSON() ([]byte, error) {
return []byte(`"` + q.String() + `"`), nil
if q.s != nil {
out := make([]byte, len(q.s)+2)
out[0], out[len(out)-1] = '"', '"'
copy(out[1:], q.s)
return out, nil
}
result := make([]byte, int64QuantityExpectedBytes, int64QuantityExpectedBytes)
result[0] = '"'
number, suffix := q.CanonicalizeBytes(result[1:1])
// if the same slice was returned to us that we passed in, avoid another allocation by copying number into
// the source slice and returning that
if len(number) > 0 && &number[0] == &result[1] && (len(number)+len(suffix)+2) <= int64QuantityExpectedBytes {
number = append(number, suffix...)
number = append(number, '"')
return result[:1+len(number)], nil
}
// if CanonicalizeBytes needed more space than our slice provided, we may need to allocate again so use
// append
result = result[:1]
result = append(result, number...)
result = append(result, suffix...)
result = append(result, '"')
return result, nil
}
// UnmarshalJSON implements the json.Unmarshaller interface.
func (q *Quantity) UnmarshalJSON(value []byte) error {
str := string(value)
parsed, err := ParseQuantity(strings.Trim(str, `"`))
l := len(value)
if l == 4 && bytes.Equal(value, []byte("null")) {
q.d.Dec = nil
q.i = int64Amount{}
return nil
}
if l < 2 {
return ErrFormatWrong
}
if value[0] == '"' && value[l-1] == '"' {
value = value[1 : l-1]
}
parsed, err := ParseQuantity(string(value))
if err != nil {
return err
}
parsed.s = value
// This copy is safe because parsed will not be referred to again.
*q = *parsed
*q = parsed
return nil
}
@ -415,7 +634,7 @@ func (q *Quantity) UnmarshalJSON(value []byte) error {
// value in the given format.
func NewQuantity(value int64, format Format) *Quantity {
return &Quantity{
Amount: inf.NewDec(value, 0),
i: int64Amount{value: value},
Format: format,
}
}
@ -426,7 +645,7 @@ func NewQuantity(value int64, format Format) *Quantity {
// values x where (-1 < x < 1) && (x != 0).
func NewMilliQuantity(value int64, format Format) *Quantity {
return &Quantity{
Amount: inf.NewDec(value, 3),
i: int64Amount{value: value, scale: -3},
Format: format,
}
}
@ -435,7 +654,7 @@ func NewMilliQuantity(value int64, format Format) *Quantity {
// value * 10^scale in DecimalSI format.
func NewScaledQuantity(value int64, scale Scale) *Quantity {
return &Quantity{
Amount: inf.NewDec(value, scale.infScale()),
i: int64Amount{value: value, scale: scale},
Format: DecimalSI,
}
}
@ -454,10 +673,12 @@ func (q *Quantity) MilliValue() int64 {
// ScaledValue returns the value of ceil(q * 10^scale); this could overflow an int64.
// To detect overflow, call Value() first and verify the expected magnitude.
func (q *Quantity) ScaledValue(scale Scale) int64 {
if q.Amount == nil {
return 0
if q.d.Dec == nil {
i, _ := q.i.AsScaledInt64(scale)
return i
}
return scaledValue(q.Amount.UnscaledBig(), int(q.Amount.Scale()), int(scale.infScale()))
dec := q.d.Dec
return scaledValue(dec.UnscaledBig(), int(dec.Scale()), int(scale.infScale()))
}
// Set sets q's value to be value.
@ -472,22 +693,25 @@ func (q *Quantity) SetMilli(value int64) {
// SetScaled sets q's value to be value * 10^scale
func (q *Quantity) SetScaled(value int64, scale Scale) {
if q.Amount == nil {
q.Amount = &inf.Dec{}
}
q.Amount.SetUnscaled(value)
q.Amount.SetScale(scale.infScale())
q.s = nil
q.d.Dec = nil
q.i = int64Amount{value: value, scale: scale}
}
// Copy is a convenience function that makes a deep copy for you. Non-deep
// copies of quantities share pointers and you will regret that.
func (q *Quantity) Copy() *Quantity {
if q.Amount == nil {
return NewQuantity(0, q.Format)
if q.d.Dec == nil {
return &Quantity{
s: q.s,
i: q.i,
Format: q.Format,
}
}
tmp := &inf.Dec{}
return &Quantity{
Amount: tmp.Set(q.Amount),
s: q.s,
d: infDecAmount{tmp.Set(q.d.Dec)},
Format: q.Format,
}
}
@ -504,7 +728,7 @@ func (qf qFlag) Set(val string) error {
return err
}
// This copy is OK because q will not be referenced again.
*qf.dest = *q
*qf.dest = q
return nil
}
@ -531,8 +755,3 @@ func QuantityFlag(flagName, defaultValue, description string) *Quantity {
func NewQuantityFlagValue(q *Quantity) flag.Value {
return qFlag{q}
}
// infScale adapts a Scale value to an inf.Scale value.
func (s Scale) infScale() inf.Scale {
return inf.Scale(-s) // inf.Scale is upside-down
}

View File

@ -17,62 +17,268 @@ limitations under the License.
package resource
import (
"math/big"
"fmt"
"io"
inf "gopkg.in/inf.v0"
"github.com/gogo/protobuf/proto"
)
// QuantityProto is a struct that is equivalent to Quantity, but intended for
// protobuf marshalling/unmarshalling. It is generated into a serialization
// that matches Quantity. Do not use in Go structs.
//
// +protobuf=true
type QuantityProto struct {
// The format of the quantity
Format Format `protobuf:"bytes,1,opt,name=format,casttype=Format"`
// The scale dimension of the value
Scale int32 `protobuf:"varint,2,opt,name=scale"`
// Bigint is serialized as a raw bytes array
Bigint []byte `protobuf:"bytes,3,opt,name=bigint"`
var _ proto.Sizer = &Quantity{}
func (m *Quantity) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
if err != nil {
return nil, err
}
return data[:n], nil
}
// ProtoTime returns the Time as a new ProtoTime value.
func (q *Quantity) QuantityProto() *QuantityProto {
if q == nil {
return &QuantityProto{}
}
p := &QuantityProto{
Format: q.Format,
}
if q.Amount != nil {
p.Scale = int32(q.Amount.Scale())
p.Bigint = q.Amount.UnscaledBig().Bytes()
}
return p
// MarshalTo is a customized version of the generated Protobuf unmarshaler for a struct
// with a single string field.
func (m *Quantity) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
data[i] = 0xa
i++
// BEGIN CUSTOM MARSHAL
out := m.toBytes()
i = encodeVarintGenerated(data, i, uint64(len(out)))
i += copy(data[i:], out)
// END CUSTOM MARSHAL
return i, nil
}
// Size implements the protobuf marshalling interface.
func (q *Quantity) Size() (n int) { return q.QuantityProto().Size() }
func encodeVarintGenerated(data []byte, offset int, v uint64) int {
for v >= 1<<7 {
data[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
data[offset] = uint8(v)
return offset + 1
}
// Reset implements the protobuf marshalling interface.
func (q *Quantity) Unmarshal(data []byte) error {
p := QuantityProto{}
if err := p.Unmarshal(data); err != nil {
func (m *Quantity) Size() (n int) {
var l int
_ = l
// BEGIN CUSTOM SIZE
l = len(m.toBytes())
// END CUSTOM SIZE
n += 1 + l + sovGenerated(uint64(l))
return n
}
func sovGenerated(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
// Unmarshal is a customized version of the generated Protobuf unmarshaler for a struct
// with a single string field.
func (m *Quantity) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Quantity: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Quantity: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field String_", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
s := string(data[iNdEx:postIndex])
// BEGIN CUSTOM DECODE
p, err := ParseQuantity(s)
if err != nil {
return err
}
q.Format = p.Format
b := big.NewInt(0)
b.SetBytes(p.Bigint)
q.Amount = inf.NewDecBig(b, inf.Scale(p.Scale))
*m = p
// END CUSTOM DECODE
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(data[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
// Marshal implements the protobuf marshalling interface.
func (q *Quantity) Marshal() (data []byte, err error) {
return q.QuantityProto().Marshal()
func skipGenerated(data []byte) (n int, err error) {
l := len(data)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if data[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthGenerated
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenerated
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipGenerated(data[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
// MarshalTo implements the protobuf marshalling interface.
func (q *Quantity) MarshalTo(data []byte) (int, error) {
return q.QuantityProto().MarshalTo(data)
}
var (
ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow")
)

File diff suppressed because it is too large Load Diff

View File

@ -24,8 +24,9 @@ type suffix string
// suffixer can interpret and construct suffixes.
type suffixer interface {
interpret(suffix) (base, exponent int, fmt Format, ok bool)
construct(base, exponent int, fmt Format) (s suffix, ok bool)
interpret(suffix) (base, exponent int32, fmt Format, ok bool)
construct(base, exponent int32, fmt Format) (s suffix, ok bool)
constructBytes(base, exponent int32, fmt Format) (s []byte, ok bool)
}
// quantitySuffixer handles suffixes for all three formats that quantity
@ -33,12 +34,13 @@ type suffixer interface {
var quantitySuffixer = newSuffixer()
type bePair struct {
base, exponent int
base, exponent int32
}
type listSuffixer struct {
suffixToBE map[suffix]bePair
beToSuffix map[bePair]suffix
beToSuffixBytes map[bePair][]byte
}
func (ls *listSuffixer) addSuffix(s suffix, pair bePair) {
@ -48,11 +50,15 @@ func (ls *listSuffixer) addSuffix(s suffix, pair bePair) {
if ls.beToSuffix == nil {
ls.beToSuffix = map[bePair]suffix{}
}
if ls.beToSuffixBytes == nil {
ls.beToSuffixBytes = map[bePair][]byte{}
}
ls.suffixToBE[s] = pair
ls.beToSuffix[pair] = s
ls.beToSuffixBytes[pair] = []byte(s)
}
func (ls *listSuffixer) lookup(s suffix) (base, exponent int, ok bool) {
func (ls *listSuffixer) lookup(s suffix) (base, exponent int32, ok bool) {
pair, ok := ls.suffixToBE[s]
if !ok {
return 0, 0, false
@ -60,19 +66,50 @@ func (ls *listSuffixer) lookup(s suffix) (base, exponent int, ok bool) {
return pair.base, pair.exponent, true
}
func (ls *listSuffixer) construct(base, exponent int) (s suffix, ok bool) {
func (ls *listSuffixer) construct(base, exponent int32) (s suffix, ok bool) {
s, ok = ls.beToSuffix[bePair{base, exponent}]
return
}
func (ls *listSuffixer) constructBytes(base, exponent int32) (s []byte, ok bool) {
s, ok = ls.beToSuffixBytes[bePair{base, exponent}]
return
}
type suffixHandler struct {
decSuffixes listSuffixer
binSuffixes listSuffixer
}
type fastLookup struct {
*suffixHandler
}
func (l fastLookup) interpret(s suffix) (base, exponent int32, format Format, ok bool) {
switch s {
case "":
return 10, 0, DecimalSI, true
case "n":
return 10, -9, DecimalSI, true
case "u":
return 10, -6, DecimalSI, true
case "m":
return 10, -3, DecimalSI, true
case "k":
return 10, 3, DecimalSI, true
case "M":
return 10, 6, DecimalSI, true
case "G":
return 10, 9, DecimalSI, true
}
return l.suffixHandler.interpret(s)
}
func newSuffixer() suffixer {
sh := &suffixHandler{}
// IMPORTANT: if you change this section you must change fastLookup
sh.binSuffixes.addSuffix("Ki", bePair{2, 10})
sh.binSuffixes.addSuffix("Mi", bePair{2, 20})
sh.binSuffixes.addSuffix("Gi", bePair{2, 30})
@ -94,10 +131,10 @@ func newSuffixer() suffixer {
sh.decSuffixes.addSuffix("P", bePair{10, 15})
sh.decSuffixes.addSuffix("E", bePair{10, 18})
return sh
return fastLookup{sh}
}
func (sh *suffixHandler) construct(base, exponent int, fmt Format) (s suffix, ok bool) {
func (sh *suffixHandler) construct(base, exponent int32, fmt Format) (s suffix, ok bool) {
switch fmt {
case DecimalSI:
return sh.decSuffixes.construct(base, exponent)
@ -115,7 +152,32 @@ func (sh *suffixHandler) construct(base, exponent int, fmt Format) (s suffix, ok
return "", false
}
func (sh *suffixHandler) interpret(suffix suffix) (base, exponent int, fmt Format, ok bool) {
func (sh *suffixHandler) constructBytes(base, exponent int32, format Format) (s []byte, ok bool) {
switch format {
case DecimalSI:
return sh.decSuffixes.constructBytes(base, exponent)
case BinarySI:
return sh.binSuffixes.constructBytes(base, exponent)
case DecimalExponent:
if base != 10 {
return nil, false
}
if exponent == 0 {
return nil, true
}
result := make([]byte, 8, 8)
result[0] = 'e'
number := strconv.AppendInt(result[1:1], int64(exponent), 10)
if &result[1] == &number[0] {
return result[:1+len(number)], true
}
result = append(result[:1], number...)
return result, true
}
return nil, false
}
func (sh *suffixHandler) interpret(suffix suffix) (base, exponent int32, fmt Format, ok bool) {
// Try lookup tables first
if b, e, ok := sh.decSuffixes.lookup(suffix); ok {
return b, e, DecimalSI, true
@ -129,7 +191,7 @@ func (sh *suffixHandler) interpret(suffix suffix) (base, exponent int, fmt Forma
if err != nil {
return 0, 0, DecimalExponent, false
}
return 10, int(parsed), DecimalExponent, true
return 10, int32(parsed), DecimalExponent, true
}
return 0, 0, DecimalExponent, false

View File

@ -151,15 +151,17 @@ func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, li
for name, quantity := range container.Resources.Requests {
if value, ok := reqs[name]; !ok {
reqs[name] = *quantity.Copy()
} else if err = value.Add(quantity); err != nil {
return nil, nil, err
} else {
value.Add(quantity)
reqs[name] = value
}
}
for name, quantity := range container.Resources.Limits {
if value, ok := limits[name]; !ok {
limits[name] = *quantity.Copy()
} else if err = value.Add(quantity); err != nil {
return nil, nil, err
} else {
value.Add(quantity)
limits[name] = value
}
}
}

View File

@ -32,10 +32,10 @@ func TestResourceHelpers(t *testing.T) {
"kube.io/storage": memoryLimit,
},
}
if res := resourceSpec.Limits.Cpu(); *res != cpuLimit {
if res := resourceSpec.Limits.Cpu(); res.Cmp(cpuLimit) != 0 {
t.Errorf("expected cpulimit %v, got %v", cpuLimit, res)
}
if res := resourceSpec.Limits.Memory(); *res != memoryLimit {
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
}
resourceSpec = ResourceRequirements{
@ -47,7 +47,7 @@ func TestResourceHelpers(t *testing.T) {
if res := resourceSpec.Limits.Cpu(); res.Value() != 0 {
t.Errorf("expected cpulimit %v, got %v", 0, res)
}
if res := resourceSpec.Limits.Memory(); *res != memoryLimit {
if res := resourceSpec.Limits.Memory(); res.Cmp(memoryLimit) != 0 {
t.Errorf("expected memorylimit %v, got %v", memoryLimit, res)
}
}

View File

@ -25,14 +25,13 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg4_inf_v0 "gopkg.in/inf.v0"
pkg3_resource "k8s.io/kubernetes/pkg/api/resource"
pkg2_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg7_fields "k8s.io/kubernetes/pkg/fields"
pkg6_labels "k8s.io/kubernetes/pkg/labels"
pkg8_runtime "k8s.io/kubernetes/pkg/runtime"
pkg6_fields "k8s.io/kubernetes/pkg/fields"
pkg5_labels "k8s.io/kubernetes/pkg/labels"
pkg7_runtime "k8s.io/kubernetes/pkg/runtime"
pkg1_types "k8s.io/kubernetes/pkg/types"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg4_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -68,16 +67,15 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg4_inf_v0.Dec
var v1 pkg3_resource.Quantity
var v2 pkg2_unversioned.Time
var v3 pkg7_fields.Selector
var v4 pkg6_labels.Selector
var v5 pkg8_runtime.Object
var v6 pkg1_types.UID
var v7 pkg5_intstr.IntOrString
var v8 time.Time
_, _, _, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6, v7, v8
var v0 pkg3_resource.Quantity
var v1 pkg2_unversioned.Time
var v2 pkg6_fields.Selector
var v3 pkg5_labels.Selector
var v4 pkg7_runtime.Object
var v5 pkg1_types.UID
var v6 pkg4_intstr.IntOrString
var v7 time.Time
_, _, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6, v7
}
}
@ -16227,7 +16225,7 @@ func (x *HTTPGetAction) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
}
case "port":
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv5 := &x.Port
yym6 := z.DecBinary()
@ -16306,7 +16304,7 @@ func (x *HTTPGetAction) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv13 := &x.Port
yym14 := z.DecBinary()
@ -16542,7 +16540,7 @@ func (x *TCPSocketAction) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
switch yys3 {
case "port":
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv4 := &x.Port
yym5 := z.DecBinary()
@ -16581,7 +16579,7 @@ func (x *TCPSocketAction) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv7 := &x.Port
yym8 := z.DecBinary()
@ -31535,7 +31533,7 @@ func (x *ServicePort) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
}
case "targetPort":
if r.TryDecodeAsNil() {
x.TargetPort = pkg5_intstr.IntOrString{}
x.TargetPort = pkg4_intstr.IntOrString{}
} else {
yyv7 := &x.TargetPort
yym8 := z.DecBinary()
@ -31628,7 +31626,7 @@ func (x *ServicePort) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.TargetPort = pkg5_intstr.IntOrString{}
x.TargetPort = pkg4_intstr.IntOrString{}
} else {
yyv14 := &x.TargetPort
yym15 := z.DecBinary()
@ -45477,7 +45475,7 @@ func (x *List) CodecEncodeSelf(e *codec1978.Encoder) {
_ = yym9
if false {
} else {
h.encSliceruntime_Object(([]pkg8_runtime.Object)(x.Items), e)
h.encSliceruntime_Object(([]pkg7_runtime.Object)(x.Items), e)
}
}
} else {
@ -45491,7 +45489,7 @@ func (x *List) CodecEncodeSelf(e *codec1978.Encoder) {
_ = yym10
if false {
} else {
h.encSliceruntime_Object(([]pkg8_runtime.Object)(x.Items), e)
h.encSliceruntime_Object(([]pkg7_runtime.Object)(x.Items), e)
}
}
}
@ -45628,7 +45626,7 @@ func (x *List) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
_ = yym7
if false {
} else {
h.decSliceruntime_Object((*[]pkg8_runtime.Object)(yyv6), d)
h.decSliceruntime_Object((*[]pkg7_runtime.Object)(yyv6), d)
}
}
case "kind":
@ -45699,7 +45697,7 @@ func (x *List) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
_ = yym14
if false {
} else {
h.decSliceruntime_Object((*[]pkg8_runtime.Object)(yyv13), d)
h.decSliceruntime_Object((*[]pkg7_runtime.Object)(yyv13), d)
}
}
yyj10++
@ -56094,7 +56092,7 @@ func (x codecSelfer1234) decResourceList(v *ResourceList, d *codec1978.Decoder)
yyl1 := r.ReadMapStart()
yybh1 := z.DecBasicHandle()
if yyv1 == nil {
yyrl1, _ := z.DecInferLen(yyl1, yybh1.MaxInitLen, 40)
yyrl1, _ := z.DecInferLen(yyl1, yybh1.MaxInitLen, 80)
yyv1 = make(map[ResourceName]pkg3_resource.Quantity, yyrl1)
*v = yyv1
}
@ -56643,7 +56641,7 @@ func (x codecSelfer1234) decSliceEvent(v *[]Event, d *codec1978.Decoder) {
}
}
func (x codecSelfer1234) encSliceruntime_Object(v []pkg8_runtime.Object, e *codec1978.Encoder) {
func (x codecSelfer1234) encSliceruntime_Object(v []pkg7_runtime.Object, e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
@ -56665,7 +56663,7 @@ func (x codecSelfer1234) encSliceruntime_Object(v []pkg8_runtime.Object, e *code
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x codecSelfer1234) decSliceruntime_Object(v *[]pkg8_runtime.Object, d *codec1978.Decoder) {
func (x codecSelfer1234) decSliceruntime_Object(v *[]pkg7_runtime.Object, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
@ -56676,7 +56674,7 @@ func (x codecSelfer1234) decSliceruntime_Object(v *[]pkg8_runtime.Object, d *cod
_ = yyc1
if yyl1 == 0 {
if yyv1 == nil {
yyv1 = []pkg8_runtime.Object{}
yyv1 = []pkg7_runtime.Object{}
yyc1 = true
} else if len(yyv1) != 0 {
yyv1 = yyv1[:0]
@ -56696,10 +56694,10 @@ func (x codecSelfer1234) decSliceruntime_Object(v *[]pkg8_runtime.Object, d *cod
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
} else {
yyv1 = make([]pkg8_runtime.Object, yyrl1)
yyv1 = make([]pkg7_runtime.Object, yyrl1)
}
} else {
yyv1 = make([]pkg8_runtime.Object, yyrl1)
yyv1 = make([]pkg7_runtime.Object, yyrl1)
}
yyc1 = true
yyrr1 = len(yyv1)
@ -56752,7 +56750,7 @@ func (x codecSelfer1234) decSliceruntime_Object(v *[]pkg8_runtime.Object, d *cod
for ; !r.CheckBreak(); yyj1++ {
if yyj1 >= len(yyv1) {
yyv1 = append(yyv1, nil) // var yyz1 pkg8_runtime.Object
yyv1 = append(yyv1, nil) // var yyz1 pkg7_runtime.Object
yyc1 = true
}
yyh1.ElemContainerState(yyj1)
@ -56779,7 +56777,7 @@ func (x codecSelfer1234) decSliceruntime_Object(v *[]pkg8_runtime.Object, d *cod
yyv1 = yyv1[:yyj1]
yyc1 = true
} else if yyj1 == 0 && yyv1 == nil {
yyv1 = []pkg8_runtime.Object{}
yyv1 = []pkg7_runtime.Object{}
yyc1 = true
}
}

View File

@ -20,8 +20,6 @@ import (
"encoding/json"
"fmt"
inf "gopkg.in/inf.v0"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/conversion"
"k8s.io/kubernetes/pkg/runtime"
@ -670,8 +668,8 @@ func Convert_v1_ResourceList_To_api_ResourceList(in *ResourceList, out *api.Reso
// TODO(#18538): We round up resource values to milli scale to maintain API compatibility.
// In the future, we should instead reject values that need rounding.
const milliScale = 3
value.Amount.Round(value.Amount, milliScale, inf.RoundUp)
const milliScale = -3
value.RoundUp(milliScale)
converted[api.ResourceName(key)] = *value
}

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg4_inf_v0 "gopkg.in/inf.v0"
pkg3_resource "k8s.io/kubernetes/pkg/api/resource"
pkg2_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg6_runtime "k8s.io/kubernetes/pkg/runtime"
pkg5_runtime "k8s.io/kubernetes/pkg/runtime"
pkg1_types "k8s.io/kubernetes/pkg/types"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg4_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg4_inf_v0.Dec
var v1 pkg3_resource.Quantity
var v2 pkg2_unversioned.Time
var v3 pkg6_runtime.RawExtension
var v4 pkg1_types.UID
var v5 pkg5_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg3_resource.Quantity
var v1 pkg2_unversioned.Time
var v2 pkg5_runtime.RawExtension
var v3 pkg1_types.UID
var v4 pkg4_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}
@ -15844,7 +15842,7 @@ func (x *HTTPGetAction) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
}
case "port":
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv5 := &x.Port
yym6 := z.DecBinary()
@ -15923,7 +15921,7 @@ func (x *HTTPGetAction) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv13 := &x.Port
yym14 := z.DecBinary()
@ -16152,7 +16150,7 @@ func (x *TCPSocketAction) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
switch yys3 {
case "port":
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv4 := &x.Port
yym5 := z.DecBinary()
@ -16191,7 +16189,7 @@ func (x *TCPSocketAction) codecDecodeSelfFromArray(l int, d *codec1978.Decoder)
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.Port = pkg5_intstr.IntOrString{}
x.Port = pkg4_intstr.IntOrString{}
} else {
yyv7 := &x.Port
yym8 := z.DecBinary()
@ -31024,7 +31022,7 @@ func (x *ServicePort) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
}
case "targetPort":
if r.TryDecodeAsNil() {
x.TargetPort = pkg5_intstr.IntOrString{}
x.TargetPort = pkg4_intstr.IntOrString{}
} else {
yyv7 := &x.TargetPort
yym8 := z.DecBinary()
@ -31117,7 +31115,7 @@ func (x *ServicePort) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.TargetPort = pkg5_intstr.IntOrString{}
x.TargetPort = pkg4_intstr.IntOrString{}
} else {
yyv14 := &x.TargetPort
yym15 := z.DecBinary()
@ -45289,7 +45287,7 @@ func (x *List) CodecEncodeSelf(e *codec1978.Encoder) {
_ = yym9
if false {
} else {
h.encSliceruntime_RawExtension(([]pkg6_runtime.RawExtension)(x.Items), e)
h.encSliceruntime_RawExtension(([]pkg5_runtime.RawExtension)(x.Items), e)
}
}
} else {
@ -45303,7 +45301,7 @@ func (x *List) CodecEncodeSelf(e *codec1978.Encoder) {
_ = yym10
if false {
} else {
h.encSliceruntime_RawExtension(([]pkg6_runtime.RawExtension)(x.Items), e)
h.encSliceruntime_RawExtension(([]pkg5_runtime.RawExtension)(x.Items), e)
}
}
}
@ -45440,7 +45438,7 @@ func (x *List) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
_ = yym7
if false {
} else {
h.decSliceruntime_RawExtension((*[]pkg6_runtime.RawExtension)(yyv6), d)
h.decSliceruntime_RawExtension((*[]pkg5_runtime.RawExtension)(yyv6), d)
}
}
case "kind":
@ -45511,7 +45509,7 @@ func (x *List) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
_ = yym14
if false {
} else {
h.decSliceruntime_RawExtension((*[]pkg6_runtime.RawExtension)(yyv13), d)
h.decSliceruntime_RawExtension((*[]pkg5_runtime.RawExtension)(yyv13), d)
}
}
yyj10++
@ -56147,7 +56145,7 @@ func (x codecSelfer1234) decResourceList(v *ResourceList, d *codec1978.Decoder)
yyl1 := r.ReadMapStart()
yybh1 := z.DecBasicHandle()
if yyv1 == nil {
yyrl1, _ := z.DecInferLen(yyl1, yybh1.MaxInitLen, 40)
yyrl1, _ := z.DecInferLen(yyl1, yybh1.MaxInitLen, 80)
yyv1 = make(map[ResourceName]pkg3_resource.Quantity, yyrl1)
*v = yyv1
}
@ -56696,7 +56694,7 @@ func (x codecSelfer1234) decSliceEvent(v *[]Event, d *codec1978.Decoder) {
}
}
func (x codecSelfer1234) encSliceruntime_RawExtension(v []pkg6_runtime.RawExtension, e *codec1978.Encoder) {
func (x codecSelfer1234) encSliceruntime_RawExtension(v []pkg5_runtime.RawExtension, e *codec1978.Encoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperEncoder(e)
_, _, _ = h, z, r
@ -56717,7 +56715,7 @@ func (x codecSelfer1234) encSliceruntime_RawExtension(v []pkg6_runtime.RawExtens
z.EncSendContainerState(codecSelfer_containerArrayEnd1234)
}
func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg6_runtime.RawExtension, d *codec1978.Decoder) {
func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg5_runtime.RawExtension, d *codec1978.Decoder) {
var h codecSelfer1234
z, r := codec1978.GenHelperDecoder(d)
_, _, _ = h, z, r
@ -56728,7 +56726,7 @@ func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg6_runtime.RawExten
_ = yyc1
if yyl1 == 0 {
if yyv1 == nil {
yyv1 = []pkg6_runtime.RawExtension{}
yyv1 = []pkg5_runtime.RawExtension{}
yyc1 = true
} else if len(yyv1) != 0 {
yyv1 = yyv1[:0]
@ -56748,10 +56746,10 @@ func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg6_runtime.RawExten
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
} else {
yyv1 = make([]pkg6_runtime.RawExtension, yyrl1)
yyv1 = make([]pkg5_runtime.RawExtension, yyrl1)
}
} else {
yyv1 = make([]pkg6_runtime.RawExtension, yyrl1)
yyv1 = make([]pkg5_runtime.RawExtension, yyrl1)
}
yyc1 = true
yyrr1 = len(yyv1)
@ -56766,7 +56764,7 @@ func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg6_runtime.RawExten
for ; yyj1 < yyrr1; yyj1++ {
yyh1.ElemContainerState(yyj1)
if r.TryDecodeAsNil() {
yyv1[yyj1] = pkg6_runtime.RawExtension{}
yyv1[yyj1] = pkg5_runtime.RawExtension{}
} else {
yyv2 := &yyv1[yyj1]
yym3 := z.DecBinary()
@ -56783,10 +56781,10 @@ func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg6_runtime.RawExten
}
if yyrt1 {
for ; yyj1 < yyl1; yyj1++ {
yyv1 = append(yyv1, pkg6_runtime.RawExtension{})
yyv1 = append(yyv1, pkg5_runtime.RawExtension{})
yyh1.ElemContainerState(yyj1)
if r.TryDecodeAsNil() {
yyv1[yyj1] = pkg6_runtime.RawExtension{}
yyv1[yyj1] = pkg5_runtime.RawExtension{}
} else {
yyv4 := &yyv1[yyj1]
yym5 := z.DecBinary()
@ -56808,13 +56806,13 @@ func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg6_runtime.RawExten
for ; !r.CheckBreak(); yyj1++ {
if yyj1 >= len(yyv1) {
yyv1 = append(yyv1, pkg6_runtime.RawExtension{}) // var yyz1 pkg6_runtime.RawExtension
yyv1 = append(yyv1, pkg5_runtime.RawExtension{}) // var yyz1 pkg5_runtime.RawExtension
yyc1 = true
}
yyh1.ElemContainerState(yyj1)
if yyj1 < len(yyv1) {
if r.TryDecodeAsNil() {
yyv1[yyj1] = pkg6_runtime.RawExtension{}
yyv1[yyj1] = pkg5_runtime.RawExtension{}
} else {
yyv6 := &yyv1[yyj1]
yym7 := z.DecBinary()
@ -56837,7 +56835,7 @@ func (x codecSelfer1234) decSliceruntime_RawExtension(v *[]pkg6_runtime.RawExten
yyv1 = yyv1[:yyj1]
yyc1 = true
} else if yyj1 == 0 && yyv1 == nil {
yyv1 = []pkg6_runtime.RawExtension{}
yyv1 = []pkg5_runtime.RawExtension{}
yyc1 = true
}
}

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg5_inf_v0 "gopkg.in/inf.v0"
pkg2_api "k8s.io/kubernetes/pkg/api"
pkg4_resource "k8s.io/kubernetes/pkg/api/resource"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg3_types "k8s.io/kubernetes/pkg/types"
pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg5_inf_v0.Dec
var v1 pkg2_api.ObjectMeta
var v2 pkg4_resource.Quantity
var v3 pkg1_unversioned.TypeMeta
var v4 pkg3_types.UID
var v5 pkg6_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg2_api.ObjectMeta
var v1 pkg4_resource.Quantity
var v2 pkg1_unversioned.TypeMeta
var v3 pkg3_types.UID
var v4 pkg5_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg5_inf_v0 "gopkg.in/inf.v0"
pkg4_resource "k8s.io/kubernetes/pkg/api/resource"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg2_v1 "k8s.io/kubernetes/pkg/api/v1"
pkg3_types "k8s.io/kubernetes/pkg/types"
pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg5_inf_v0.Dec
var v1 pkg4_resource.Quantity
var v2 pkg1_unversioned.TypeMeta
var v3 pkg2_v1.ObjectMeta
var v4 pkg3_types.UID
var v5 pkg6_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg4_resource.Quantity
var v1 pkg1_unversioned.TypeMeta
var v2 pkg2_v1.ObjectMeta
var v3 pkg3_types.UID
var v4 pkg5_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg5_inf_v0 "gopkg.in/inf.v0"
pkg2_api "k8s.io/kubernetes/pkg/api"
pkg4_resource "k8s.io/kubernetes/pkg/api/resource"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg3_types "k8s.io/kubernetes/pkg/types"
pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg5_inf_v0.Dec
var v1 pkg2_api.ObjectMeta
var v2 pkg4_resource.Quantity
var v3 pkg1_unversioned.TypeMeta
var v4 pkg3_types.UID
var v5 pkg6_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg2_api.ObjectMeta
var v1 pkg4_resource.Quantity
var v2 pkg1_unversioned.TypeMeta
var v3 pkg3_types.UID
var v4 pkg5_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg5_inf_v0 "gopkg.in/inf.v0"
pkg4_resource "k8s.io/kubernetes/pkg/api/resource"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg2_v1 "k8s.io/kubernetes/pkg/api/v1"
pkg3_types "k8s.io/kubernetes/pkg/types"
pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg5_inf_v0.Dec
var v1 pkg4_resource.Quantity
var v2 pkg1_unversioned.TypeMeta
var v3 pkg2_v1.ObjectMeta
var v4 pkg3_types.UID
var v5 pkg6_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg4_resource.Quantity
var v1 pkg1_unversioned.TypeMeta
var v2 pkg2_v1.ObjectMeta
var v3 pkg3_types.UID
var v4 pkg5_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg5_inf_v0 "gopkg.in/inf.v0"
pkg4_resource "k8s.io/kubernetes/pkg/api/resource"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg2_v1 "k8s.io/kubernetes/pkg/api/v1"
pkg3_types "k8s.io/kubernetes/pkg/types"
pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg5_inf_v0.Dec
var v1 pkg4_resource.Quantity
var v2 pkg1_unversioned.TypeMeta
var v3 pkg2_v1.ObjectMeta
var v4 pkg3_types.UID
var v5 pkg6_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg4_resource.Quantity
var v1 pkg1_unversioned.TypeMeta
var v2 pkg2_v1.ObjectMeta
var v3 pkg3_types.UID
var v4 pkg5_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg5_inf_v0 "gopkg.in/inf.v0"
pkg2_api "k8s.io/kubernetes/pkg/api"
pkg4_resource "k8s.io/kubernetes/pkg/api/resource"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg3_types "k8s.io/kubernetes/pkg/types"
pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg5_inf_v0.Dec
var v1 pkg2_api.ObjectMeta
var v2 pkg4_resource.Quantity
var v3 pkg1_unversioned.LabelSelector
var v4 pkg3_types.UID
var v5 pkg6_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg2_api.ObjectMeta
var v1 pkg4_resource.Quantity
var v2 pkg1_unversioned.LabelSelector
var v3 pkg3_types.UID
var v4 pkg5_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}
@ -4916,7 +4914,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromMap(l int, d *codec1978.Dec
switch yys3 {
case "maxUnavailable":
if r.TryDecodeAsNil() {
x.MaxUnavailable = pkg6_intstr.IntOrString{}
x.MaxUnavailable = pkg5_intstr.IntOrString{}
} else {
yyv4 := &x.MaxUnavailable
yym5 := z.DecBinary()
@ -4931,7 +4929,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromMap(l int, d *codec1978.Dec
}
case "maxSurge":
if r.TryDecodeAsNil() {
x.MaxSurge = pkg6_intstr.IntOrString{}
x.MaxSurge = pkg5_intstr.IntOrString{}
} else {
yyv6 := &x.MaxSurge
yym7 := z.DecBinary()
@ -4970,7 +4968,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromArray(l int, d *codec1978.D
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.MaxUnavailable = pkg6_intstr.IntOrString{}
x.MaxUnavailable = pkg5_intstr.IntOrString{}
} else {
yyv9 := &x.MaxUnavailable
yym10 := z.DecBinary()
@ -4995,7 +4993,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromArray(l int, d *codec1978.D
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.MaxSurge = pkg6_intstr.IntOrString{}
x.MaxSurge = pkg5_intstr.IntOrString{}
} else {
yyv11 := &x.MaxSurge
yym12 := z.DecBinary()
@ -9593,7 +9591,7 @@ func (x *IngressBackend) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
}
case "servicePort":
if r.TryDecodeAsNil() {
x.ServicePort = pkg6_intstr.IntOrString{}
x.ServicePort = pkg5_intstr.IntOrString{}
} else {
yyv5 := &x.ServicePort
yym6 := z.DecBinary()
@ -9648,7 +9646,7 @@ func (x *IngressBackend) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.ServicePort = pkg6_intstr.IntOrString{}
x.ServicePort = pkg5_intstr.IntOrString{}
} else {
yyv9 := &x.ServicePort
yym10 := z.DecBinary()
@ -13849,7 +13847,7 @@ func (x codecSelfer1234) decSliceCustomMetricTarget(v *[]CustomMetricTarget, d *
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 80)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -13968,7 +13966,7 @@ func (x codecSelfer1234) decSliceCustomMetricCurrentStatus(v *[]CustomMetricCurr
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 80)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -25,12 +25,11 @@ import (
"errors"
"fmt"
codec1978 "github.com/ugorji/go/codec"
pkg5_inf_v0 "gopkg.in/inf.v0"
pkg4_resource "k8s.io/kubernetes/pkg/api/resource"
pkg1_unversioned "k8s.io/kubernetes/pkg/api/unversioned"
pkg2_v1 "k8s.io/kubernetes/pkg/api/v1"
pkg3_types "k8s.io/kubernetes/pkg/types"
pkg6_intstr "k8s.io/kubernetes/pkg/util/intstr"
pkg5_intstr "k8s.io/kubernetes/pkg/util/intstr"
"reflect"
"runtime"
time "time"
@ -66,14 +65,13 @@ func init() {
panic(err)
}
if false { // reference the types, but skip this branch at build/run time
var v0 pkg5_inf_v0.Dec
var v1 pkg4_resource.Quantity
var v2 pkg1_unversioned.TypeMeta
var v3 pkg2_v1.ObjectMeta
var v4 pkg3_types.UID
var v5 pkg6_intstr.IntOrString
var v6 time.Time
_, _, _, _, _, _, _ = v0, v1, v2, v3, v4, v5, v6
var v0 pkg4_resource.Quantity
var v1 pkg1_unversioned.TypeMeta
var v2 pkg2_v1.ObjectMeta
var v3 pkg3_types.UID
var v4 pkg5_intstr.IntOrString
var v5 time.Time
_, _, _, _, _, _ = v0, v1, v2, v3, v4, v5
}
}
@ -6923,7 +6921,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromMap(l int, d *codec1978.Dec
}
} else {
if x.MaxUnavailable == nil {
x.MaxUnavailable = new(pkg6_intstr.IntOrString)
x.MaxUnavailable = new(pkg5_intstr.IntOrString)
}
yym5 := z.DecBinary()
_ = yym5
@ -6942,7 +6940,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromMap(l int, d *codec1978.Dec
}
} else {
if x.MaxSurge == nil {
x.MaxSurge = new(pkg6_intstr.IntOrString)
x.MaxSurge = new(pkg5_intstr.IntOrString)
}
yym7 := z.DecBinary()
_ = yym7
@ -6985,7 +6983,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromArray(l int, d *codec1978.D
}
} else {
if x.MaxUnavailable == nil {
x.MaxUnavailable = new(pkg6_intstr.IntOrString)
x.MaxUnavailable = new(pkg5_intstr.IntOrString)
}
yym10 := z.DecBinary()
_ = yym10
@ -7014,7 +7012,7 @@ func (x *RollingUpdateDeployment) codecDecodeSelfFromArray(l int, d *codec1978.D
}
} else {
if x.MaxSurge == nil {
x.MaxSurge = new(pkg6_intstr.IntOrString)
x.MaxSurge = new(pkg5_intstr.IntOrString)
}
yym12 := z.DecBinary()
_ = yym12
@ -13794,7 +13792,7 @@ func (x *IngressBackend) codecDecodeSelfFromMap(l int, d *codec1978.Decoder) {
}
case "servicePort":
if r.TryDecodeAsNil() {
x.ServicePort = pkg6_intstr.IntOrString{}
x.ServicePort = pkg5_intstr.IntOrString{}
} else {
yyv5 := &x.ServicePort
yym6 := z.DecBinary()
@ -13849,7 +13847,7 @@ func (x *IngressBackend) codecDecodeSelfFromArray(l int, d *codec1978.Decoder) {
}
z.DecSendContainerState(codecSelfer_containerArrayElem1234)
if r.TryDecodeAsNil() {
x.ServicePort = pkg6_intstr.IntOrString{}
x.ServicePort = pkg5_intstr.IntOrString{}
} else {
yyv9 := &x.ServicePort
yym10 := z.DecBinary()
@ -19393,7 +19391,7 @@ func (x codecSelfer1234) decSliceCustomMetricTarget(v *[]CustomMetricTarget, d *
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 80)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]
@ -19512,7 +19510,7 @@ func (x codecSelfer1234) decSliceCustomMetricCurrentStatus(v *[]CustomMetricCurr
yyrg1 := len(yyv1) > 0
yyv21 := yyv1
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 40)
yyrl1, yyrt1 = z.DecInferLen(yyl1, z.DecBasicHandle().MaxInitLen, 80)
if yyrt1 {
if yyrl1 <= cap(yyv1) {
yyv1 = yyv1[:yyrl1]

View File

@ -44,10 +44,7 @@ func newPVC(name string) api.PersistentVolumeClaim {
Spec: api.PersistentVolumeClaimSpec{
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceStorage: resource.Quantity{
Amount: dec(1, 0),
Format: resource.BinarySI,
},
api.ResourceStorage: *resource.NewQuantity(1, resource.BinarySI),
},
},
},

View File

@ -237,7 +237,7 @@ func (a *HorizontalController) computeReplicasForCustomMetrics(hpa *autoscaling.
}
statusList.Items = append(statusList.Items, extensions.CustomMetricCurrentStatus{
Name: customMetricTarget.Name,
CurrentValue: *quantity,
CurrentValue: quantity,
})
}
byteStatusList, err := json.Marshal(statusList)

View File

@ -129,8 +129,7 @@ func (h *HeapsterMetricsClient) GetCpuConsumptionAndRequestInMillis(namespace st
podNames = append(podNames, pod.Name)
for _, container := range pod.Spec.Containers {
containerRequest := container.Resources.Requests[api.ResourceCPU]
if containerRequest.Amount != nil {
if containerRequest, ok := container.Resources.Requests[api.ResourceCPU]; ok {
requestSum += containerRequest.MilliValue()
} else {
missing = true

View File

@ -1841,15 +1841,17 @@ func getPodsTotalRequestsAndLimits(podList *api.PodList) (reqs map[api.ResourceN
for podReqName, podReqValue := range podReqs {
if value, ok := reqs[podReqName]; !ok {
reqs[podReqName] = *podReqValue.Copy()
} else if err = value.Add(podReqValue); err != nil {
return nil, nil, err
} else {
value.Add(podReqValue)
reqs[podReqName] = value
}
}
for podLimitName, podLimitValue := range podLimits {
if value, ok := limits[podLimitName]; !ok {
limits[podLimitName] = *podLimitValue.Copy()
} else if err = value.Add(podLimitValue); err != nil {
return nil, nil, err
} else {
value.Add(podLimitValue)
limits[podLimitName] = value
}
}
}

View File

@ -431,7 +431,7 @@ func TestGetPodsTotalRequests(t *testing.T) {
if err != nil {
t.Errorf("Unexpected error %v", err)
}
if !reflect.DeepEqual(reqs, testCase.expectedReqs) {
if !api.Semantic.DeepEqual(reqs, testCase.expectedReqs) {
t.Errorf("Expected %v, got %v", testCase.expectedReqs, reqs)
}
}

View File

@ -434,7 +434,7 @@ func populateResourceList(spec string) (api.ResourceList, error) {
if err != nil {
return nil, err
}
result[resourceName] = *resourceQuantity
result[resourceName] = resourceQuantity
}
return result, nil
}
@ -458,7 +458,7 @@ func populateV1ResourceList(spec string) (v1.ResourceList, error) {
if err != nil {
return nil, err
}
result[resourceName] = *resourceQuantity
result[resourceName] = resourceQuantity
}
return result, nil
}

View File

@ -378,10 +378,12 @@ func TestGenerate(t *testing.T) {
},
}
generator := BasicReplicationController{}
for _, test := range tests {
for i, test := range tests {
obj, err := generator.Generate(test.params)
t.Logf("%d: %#v", i, obj)
if !test.expectErr && err != nil {
t.Errorf("unexpected error: %v", err)
continue
}
if test.expectErr && err != nil {
continue

View File

@ -581,7 +581,7 @@ func (dm *DockerManager) runContainer(
// If request is not specified, but limit is, we want request to default to limit.
// API server does this for new containers, but we repeat this logic in Kubelet
// for containers running on existing Kubernetes clusters.
if cpuRequest.Amount == nil && cpuLimit.Amount != nil {
if cpuRequest.IsZero() && !cpuLimit.IsZero() {
cpuShares = milliCPUToShares(cpuLimit.MilliValue())
} else {
// if cpuRequest.Amount is nil, then milliCPUToShares will return the minimal number

View File

@ -148,7 +148,7 @@ func parseThresholdStatement(statement string) (Threshold, error) {
return Threshold{
Signal: signal,
Operator: operator,
Value: *quantity,
Value: &quantity,
}, nil
}
@ -213,14 +213,10 @@ func podUsage(podStats statsapi.PodStats) (api.ResourceList, error) {
// disk usage (if known)
// TODO: need to handle volumes
for _, fsStats := range []*statsapi.FsStats{container.Rootfs, container.Logs} {
if err := disk.Add(*diskUsage(fsStats)); err != nil {
return nil, err
}
disk.Add(*diskUsage(fsStats))
}
// memory usage (if known)
if err := memory.Add(*memoryUsage(container.Memory)); err != nil {
return nil, err
}
memory.Add(*memoryUsage(container.Memory))
}
return api.ResourceList{
api.ResourceMemory: memory,
@ -430,7 +426,7 @@ func makeSignalObservations(summaryProvider stats.SummaryProvider) (signalObserv
statsFunc := cachedStatsFunc(summary.Pods)
// build an evaluation context for current eviction signals
result := signalObservations{}
result[SignalMemoryAvailable] = *resource.NewQuantity(int64(*summary.Node.Memory.AvailableBytes), resource.BinarySI)
result[SignalMemoryAvailable] = resource.NewQuantity(int64(*summary.Node.Memory.AvailableBytes), resource.BinarySI)
return result, statsFunc, nil
}
@ -446,7 +442,7 @@ func thresholdsMet(thresholds []Threshold, observations signalObservations) []Th
}
// determine if we have met the specified threshold
thresholdMet := false
thresholdResult := threshold.Value.Cmp(observed)
thresholdResult := threshold.Value.Cmp(*observed)
switch threshold.Operator {
case OpLessThan:
thresholdMet = thresholdResult > 0
@ -538,7 +534,7 @@ func hasNodeCondition(inputs []api.NodeConditionType, item api.NodeConditionType
// hasThreshold returns true if the node condition is in the input list
func hasThreshold(inputs []Threshold, item Threshold) bool {
for _, input := range inputs {
if input.GracePeriod == item.GracePeriod && input.Operator == item.Operator && input.Signal == item.Signal && input.Value.Cmp(item.Value) == 0 {
if input.GracePeriod == item.GracePeriod && input.Operator == item.Operator && input.Signal == item.Signal && input.Value.Cmp(*item.Value) == 0 {
return true
}
}

View File

@ -30,6 +30,11 @@ import (
"k8s.io/kubernetes/pkg/types"
)
func quantityMustParse(value string) *resource.Quantity {
q := resource.MustParse(value)
return &q
}
func TestParseThresholdConfig(t *testing.T) {
gracePeriod, _ := time.ParseDuration("30s")
testCases := map[string]struct {
@ -55,12 +60,12 @@ func TestParseThresholdConfig(t *testing.T) {
{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: resource.MustParse("150Mi"),
Value: quantityMustParse("150Mi"),
},
{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: resource.MustParse("300Mi"),
Value: quantityMustParse("300Mi"),
GracePeriod: gracePeriod,
},
},
@ -145,7 +150,7 @@ func thresholdEqual(a Threshold, b Threshold) bool {
return a.GracePeriod == b.GracePeriod &&
a.Operator == b.Operator &&
a.Signal == b.Signal &&
a.Value.Cmp(b.Value) == 0
a.Value.Cmp(*b.Value) == 0
}
// TestOrderedByQoS ensures we order BestEffort < Burstable < Guaranteed
@ -348,7 +353,7 @@ func TestThresholdsMet(t *testing.T) {
hardThreshold := Threshold{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: resource.MustParse("1Gi"),
Value: quantityMustParse("1Gi"),
}
testCases := map[string]struct {
thresholds []Threshold
@ -363,14 +368,14 @@ func TestThresholdsMet(t *testing.T) {
"threshold-met": {
thresholds: []Threshold{hardThreshold},
observations: signalObservations{
SignalMemoryAvailable: resource.MustParse("500Mi"),
SignalMemoryAvailable: quantityMustParse("500Mi"),
},
result: []Threshold{hardThreshold},
},
"threshold-not-met": {
thresholds: []Threshold{hardThreshold},
observations: signalObservations{
SignalMemoryAvailable: resource.MustParse("2Gi"),
SignalMemoryAvailable: quantityMustParse("2Gi"),
},
result: []Threshold{},
},
@ -387,7 +392,7 @@ func TestThresholdsFirstObservedAt(t *testing.T) {
hardThreshold := Threshold{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: resource.MustParse("1Gi"),
Value: quantityMustParse("1Gi"),
}
now := unversioned.Now()
oldTime := unversioned.NewTime(now.Time.Add(-1 * time.Minute))
@ -435,12 +440,12 @@ func TestThresholdsMetGracePeriod(t *testing.T) {
hardThreshold := Threshold{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: resource.MustParse("1Gi"),
Value: quantityMustParse("1Gi"),
}
softThreshold := Threshold{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: resource.MustParse("2Gi"),
Value: quantityMustParse("2Gi"),
GracePeriod: 1 * time.Minute,
}
oldTime := unversioned.NewTime(now.Time.Add(-2 * time.Minute))

View File

@ -103,7 +103,7 @@ func TestMemoryPressure(t *testing.T) {
{
Signal: SignalMemoryAvailable,
Operator: OpLessThan,
Value: resource.MustParse("1Gi"),
Value: quantityMustParse("1Gi"),
},
},
}

View File

@ -55,7 +55,7 @@ type Threshold struct {
// Operator represents a relationship of a signal to a value.
Operator ThresholdOperator
// value is a quantity associated with the signal that is evaluated against the specified operator.
Value resource.Quantity
Value *resource.Quantity
// GracePeriod represents the amount of time that a threshold must be met before eviction is triggered.
GracePeriod time.Duration
}
@ -88,7 +88,7 @@ type statsFunc func(pod *api.Pod) (statsapi.PodStats, bool)
type rankFunc func(pods []*api.Pod, stats statsFunc)
// signalObservations maps a signal to an observed quantity
type signalObservations map[Signal]resource.Quantity
type signalObservations map[Signal]*resource.Quantity
// thresholdsObservedAt maps a threshold to a time that it was observed
type thresholdsObservedAt map[Threshold]time.Time

View File

@ -3051,7 +3051,7 @@ func (kl *Kubelet) setNodeStatusMachineInfo(node *api.Node) {
if kl.reservation.Kubernetes != nil {
value.Sub(kl.reservation.Kubernetes[k])
}
if value.Amount != nil && value.Amount.Sign() < 0 {
if value.Sign() < 0 {
// Negative Allocatable resources don't make sense.
value.Set(0)
}

View File

@ -3853,16 +3853,16 @@ func TestExtractBandwidthResources(t *testing.T) {
},
{
pod: testPod("10M", ""),
expectedIngress: ten,
expectedIngress: &ten,
},
{
pod: testPod("", "10M"),
expectedEgress: ten,
expectedEgress: &ten,
},
{
pod: testPod("4M", "20M"),
expectedIngress: four,
expectedEgress: twenty,
expectedIngress: &four,
expectedEgress: &twenty,
},
{
pod: testPod("foo", ""),

View File

@ -93,7 +93,7 @@ func Subtract(a api.ResourceList, b api.ResourceList) api.ResourceList {
for key, value := range b {
if _, found := result[key]; !found {
quantity := *value.Copy()
quantity.Neg(value)
quantity.Neg()
result[key] = quantity
}
}

View File

@ -38,18 +38,22 @@ func validateBandwidthIsReasonable(rsrc *resource.Quantity) error {
func ExtractPodBandwidthResources(podAnnotations map[string]string) (ingress, egress *resource.Quantity, err error) {
str, found := podAnnotations["kubernetes.io/ingress-bandwidth"]
if found {
if ingress, err = resource.ParseQuantity(str); err != nil {
ingressValue, err := resource.ParseQuantity(str)
if err != nil {
return nil, nil, err
}
ingress = &ingressValue
if err := validateBandwidthIsReasonable(ingress); err != nil {
return nil, nil, err
}
}
str, found = podAnnotations["kubernetes.io/egress-bandwidth"]
if found {
if egress, err = resource.ParseQuantity(str); err != nil {
egressValue, err := resource.ParseQuantity(str)
if err != nil {
return nil, nil, err
}
egress = &egressValue
if err := validateBandwidthIsReasonable(egress); err != nil {
return nil, nil, err
}

View File

@ -383,5 +383,5 @@ func FindEmptyDirectoryUsageOnTmpfs() (*resource.Quantity, error) {
return nil, fmt.Errorf("failed to parse 'du' output %s due to error %v", out, err)
}
used.Format = resource.BinarySI
return used, nil
return &used, nil
}

View File

@ -43,5 +43,5 @@ func Du(path string) (*resource.Quantity, error) {
return nil, fmt.Errorf("failed to parse 'du' output %s due to error %v", out, err)
}
used.Format = resource.BinarySI
return used, nil
return &used, nil
}

View File

@ -57,5 +57,5 @@ func Du(path string) (*resource.Quantity, error) {
return nil, fmt.Errorf("failed to parse 'du' output %s due to error %v", out, err)
}
used.Format = resource.BinarySI
return used, nil
return &used, nil
}

View File

@ -104,7 +104,7 @@ var _ = framework.KubeDescribe("LimitRange", func() {
})
func equalResourceRequirement(expected api.ResourceRequirements, actual api.ResourceRequirements) error {
framework.Logf("Verifying requests: expected %s with actual %s", expected.Requests, actual.Requests)
framework.Logf("Verifying requests: expected %v with actual %v", expected.Requests, actual.Requests)
err := equalResourceList(expected.Requests, actual.Requests)
if err != nil {
return err

View File

@ -314,10 +314,7 @@ func newPVC(name string) api.PersistentVolumeClaim {
},
Resources: api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceStorage: resource.Quantity{
Amount: dec(1, 0),
Format: resource.BinarySI,
},
api.ResourceStorage: *resource.NewQuantity(1, resource.BinarySI),
},
},
},

View File

@ -155,8 +155,8 @@ func NewResourceCPUIsolator(request, limit string) (*ResourceCPU, error) {
res := &ResourceCPU{
ResourceBase{
resourceValue{
Request: req,
Limit: lim,
Request: &req,
Limit: &lim,
},
},
}
@ -209,8 +209,8 @@ func NewResourceMemoryIsolator(request, limit string) (*ResourceMemory, error) {
res := &ResourceMemory{
ResourceBase{
resourceValue{
Request: req,
Limit: lim,
Request: &req,
Limit: &lim,
},
},
}