Add RemainingItemCount to ListMeta

Kubernetes-commit: 58c18309a84f9e0fe05b92c202616e4ecf8062f7
This commit is contained in:
Chao Xu 2019-04-01 14:44:19 -07:00 committed by Kubernetes Publisher
parent d16c4716d3
commit 034ed25bbe
6 changed files with 38 additions and 22 deletions

View File

@ -604,7 +604,7 @@ func (c *Cacher) GetToList(ctx context.Context, key string, resourceVersion stri
} }
} }
if c.versioner != nil { if c.versioner != nil {
if err := c.versioner.UpdateList(listObj, readResourceVersion, ""); err != nil { if err := c.versioner.UpdateList(listObj, readResourceVersion, "", 0); err != nil {
return err return err
} }
} }
@ -679,7 +679,7 @@ func (c *Cacher) List(ctx context.Context, key string, resourceVersion string, p
} }
trace.Step(fmt.Sprintf("Filtered %d items", listVal.Len())) trace.Step(fmt.Sprintf("Filtered %d items", listVal.Len()))
if c.versioner != nil { if c.versioner != nil {
if err := c.versioner.UpdateList(listObj, readResourceVersion, ""); err != nil { if err := c.versioner.UpdateList(listObj, readResourceVersion, "", 0); err != nil {
return err return err
} }
} }

View File

@ -217,13 +217,14 @@ type testVersioner struct{}
func (testVersioner) UpdateObject(obj runtime.Object, resourceVersion uint64) error { func (testVersioner) UpdateObject(obj runtime.Object, resourceVersion uint64) error {
return meta.NewAccessor().SetResourceVersion(obj, strconv.FormatUint(resourceVersion, 10)) return meta.NewAccessor().SetResourceVersion(obj, strconv.FormatUint(resourceVersion, 10))
} }
func (testVersioner) UpdateList(obj runtime.Object, resourceVersion uint64, continueValue string) error { func (testVersioner) UpdateList(obj runtime.Object, resourceVersion uint64, continueValue string, count int64) error {
listAccessor, err := meta.ListAccessor(obj) listAccessor, err := meta.ListAccessor(obj)
if err != nil || listAccessor == nil { if err != nil || listAccessor == nil {
return err return err
} }
listAccessor.SetResourceVersion(strconv.FormatUint(resourceVersion, 10)) listAccessor.SetResourceVersion(strconv.FormatUint(resourceVersion, 10))
listAccessor.SetContinue(continueValue) listAccessor.SetContinue(continueValue)
listAccessor.SetRemainingItemCount(count)
return nil return nil
} }
func (testVersioner) PrepareObjectForStorage(obj runtime.Object) error { func (testVersioner) PrepareObjectForStorage(obj runtime.Object) error {

View File

@ -44,7 +44,7 @@ func (a APIObjectVersioner) UpdateObject(obj runtime.Object, resourceVersion uin
} }
// UpdateList implements Versioner // UpdateList implements Versioner
func (a APIObjectVersioner) UpdateList(obj runtime.Object, resourceVersion uint64, nextKey string) error { func (a APIObjectVersioner) UpdateList(obj runtime.Object, resourceVersion uint64, nextKey string, count int64) error {
listAccessor, err := meta.ListAccessor(obj) listAccessor, err := meta.ListAccessor(obj)
if err != nil || listAccessor == nil { if err != nil || listAccessor == nil {
return err return err
@ -55,6 +55,7 @@ func (a APIObjectVersioner) UpdateList(obj runtime.Object, resourceVersion uint6
} }
listAccessor.SetResourceVersion(versionString) listAccessor.SetResourceVersion(versionString)
listAccessor.SetContinue(nextKey) listAccessor.SetContinue(nextKey)
listAccessor.SetRemainingItemCount(count)
return nil return nil
} }

View File

@ -413,7 +413,7 @@ func (s *store) GetToList(ctx context.Context, key string, resourceVersion strin
} }
} }
// update version with cluster level revision // update version with cluster level revision
return s.versioner.UpdateList(listObj, uint64(getResp.Header.Revision), "") return s.versioner.UpdateList(listObj, uint64(getResp.Header.Revision), "", 0)
} }
func (s *store) Count(key string) (int64, error) { func (s *store) Count(key string) (int64, error) {
@ -576,9 +576,10 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
// loop until we have filled the requested limit from etcd or there are no more results // loop until we have filled the requested limit from etcd or there are no more results
var lastKey []byte var lastKey []byte
var hasMore bool var hasMore bool
var getResp *clientv3.GetResponse
for { for {
startTime := time.Now() startTime := time.Now()
getResp, err := s.client.KV.Get(ctx, key, options...) getResp, err = s.client.KV.Get(ctx, key, options...)
metrics.RecordEtcdRequestLatency("list", getTypeName(listPtr), startTime) metrics.RecordEtcdRequestLatency("list", getTypeName(listPtr), startTime)
if err != nil { if err != nil {
return interpretListError(err, len(pred.Continue) > 0, continueKey, keyPrefix) return interpretListError(err, len(pred.Continue) > 0, continueKey, keyPrefix)
@ -639,11 +640,17 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
if err != nil { if err != nil {
return err return err
} }
return s.versioner.UpdateList(listObj, uint64(returnedRV), next) remainingItemCount := getResp.Count - pred.Limit
// getResp.Count counts in objects that do not match the pred.
// Instead of returning inaccurate count, return 0.
if !pred.Empty() {
remainingItemCount = 0
}
return s.versioner.UpdateList(listObj, uint64(returnedRV), next, remainingItemCount)
} }
// no continuation // no continuation
return s.versioner.UpdateList(listObj, uint64(returnedRV), "") return s.versioner.UpdateList(listObj, uint64(returnedRV), "", 0)
} }
// growSlice takes a slice value and grows its capacity up // growSlice takes a slice value and grows its capacity up

View File

@ -825,14 +825,15 @@ func TestList(t *testing.T) {
} }
tests := []struct { tests := []struct {
name string name string
disablePaging bool disablePaging bool
rv string rv string
prefix string prefix string
pred storage.SelectionPredicate pred storage.SelectionPredicate
expectedOut []*example.Pod expectedOut []*example.Pod
expectContinue bool expectContinue bool
expectError bool expectedRemainingItemCount int64
expectError bool
}{ }{
{ {
name: "rejects invalid resource version", name: "rejects invalid resource version",
@ -882,8 +883,9 @@ func TestList(t *testing.T) {
Field: fields.Everything(), Field: fields.Everything(),
Limit: 1, Limit: 1,
}, },
expectedOut: []*example.Pod{preset[1].storedObj}, expectedOut: []*example.Pod{preset[1].storedObj},
expectContinue: true, expectContinue: true,
expectedRemainingItemCount: 1,
}, },
{ {
name: "test List with limit when paging disabled", name: "test List with limit when paging disabled",
@ -1061,6 +1063,9 @@ func TestList(t *testing.T) {
t.Errorf("(%s): length of list want=%d, got=%d", tt.name, len(tt.expectedOut), len(out.Items)) t.Errorf("(%s): length of list want=%d, got=%d", tt.name, len(tt.expectedOut), len(out.Items))
continue continue
} }
if e, a := tt.expectedRemainingItemCount, out.ListMeta.RemainingItemCount; e != a {
t.Errorf("(%s): remainingItemCount want=%d, got=%d", tt.name, e, a)
}
for j, wantPod := range tt.expectedOut { for j, wantPod := range tt.expectedOut {
getPod := &out.Items[j] getPod := &out.Items[j]
if !reflect.DeepEqual(wantPod, getPod) { if !reflect.DeepEqual(wantPod, getPod) {

View File

@ -40,10 +40,12 @@ type Versioner interface {
// from database. // from database.
UpdateObject(obj runtime.Object, resourceVersion uint64) error UpdateObject(obj runtime.Object, resourceVersion uint64) error
// UpdateList sets the resource version into an API list object. Returns an error if the object // UpdateList sets the resource version into an API list object. Returns an error if the object
// cannot be updated correctly. May return nil if the requested object does not need metadata // cannot be updated correctly. May return nil if the requested object does not need metadata from
// from database. continueValue is optional and indicates that more results are available if // database. continueValue is optional and indicates that more results are available if the client
// the client passes that value to the server in a subsequent call. // passes that value to the server in a subsequent call. remainingItemCount indicates the number
UpdateList(obj runtime.Object, resourceVersion uint64, continueValue string) error // of remaining objects if the list is partial. The remainingItemCount field is omitted during
// serialization if it is set to 0.
UpdateList(obj runtime.Object, resourceVersion uint64, continueValue string, remainingItemCount int64) error
// PrepareObjectForStorage should set SelfLink and ResourceVersion to the empty value. Should // PrepareObjectForStorage should set SelfLink and ResourceVersion to the empty value. Should
// return an error if the specified object cannot be updated. // return an error if the specified object cannot be updated.
PrepareObjectForStorage(obj runtime.Object) error PrepareObjectForStorage(obj runtime.Object) error