Optimize selector for single-matching items
This commit is contained in:
		| @@ -1032,7 +1032,16 @@ func (e *Store) Watch(ctx genericapirequest.Context, options *metainternalversio | |||||||
| func (e *Store) WatchPredicate(ctx genericapirequest.Context, p storage.SelectionPredicate, resourceVersion string) (watch.Interface, error) { | func (e *Store) WatchPredicate(ctx genericapirequest.Context, p storage.SelectionPredicate, resourceVersion string) (watch.Interface, error) { | ||||||
| 	if name, ok := p.MatchesSingle(); ok { | 	if name, ok := p.MatchesSingle(); ok { | ||||||
| 		if key, err := e.KeyFunc(ctx, name); err == nil { | 		if key, err := e.KeyFunc(ctx, name); err == nil { | ||||||
| 			w, err := e.Storage.Watch(ctx, key, resourceVersion, p) | 			// For performance reasons, we can optimize the further computations of | ||||||
|  | 			// selector, by removing then "matches-single" fields, because they are | ||||||
|  | 			// already satisfied by choosing appropriate key. | ||||||
|  | 			sp, err := p.RemoveMatchesSingleRequirements() | ||||||
|  | 			if err != nil { | ||||||
|  | 				glog.Warningf("Couldn't remove matches-single requirements: %v", err) | ||||||
|  | 				// Since we couldn't optimize selector, reset to the original one. | ||||||
|  | 				sp = p | ||||||
|  | 			} | ||||||
|  | 			w, err := e.Storage.Watch(ctx, key, resourceVersion, sp) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return nil, err | 				return nil, err | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -65,16 +65,41 @@ func (s *SelectionPredicate) MatchesLabelsAndFields(l labels.Set, f fields.Set) | |||||||
| 	return matched | 	return matched | ||||||
| } | } | ||||||
|  |  | ||||||
|  | const matchesSingleField = "metadata.name" | ||||||
|  |  | ||||||
|  | func removeMatchesSingleField(field, value string) (string, string, error) { | ||||||
|  | 	if field == matchesSingleField { | ||||||
|  | 		return "", "", nil | ||||||
|  | 	} | ||||||
|  | 	return field, value, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // MatchesSingle will return (name, true) if and only if s.Field matches on the object's | // MatchesSingle will return (name, true) if and only if s.Field matches on the object's | ||||||
| // name. | // name. | ||||||
| func (s *SelectionPredicate) MatchesSingle() (string, bool) { | func (s *SelectionPredicate) MatchesSingle() (string, bool) { | ||||||
| 	// TODO: should be namespace.name | 	if name, ok := s.Field.RequiresExactMatch(matchesSingleField); ok { | ||||||
| 	if name, ok := s.Field.RequiresExactMatch("metadata.name"); ok { |  | ||||||
| 		return name, true | 		return name, true | ||||||
| 	} | 	} | ||||||
| 	return "", false | 	return "", false | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func (s *SelectionPredicate) RemoveMatchesSingleRequirements() (SelectionPredicate, error) { | ||||||
|  | 	var fieldsSelector fields.Selector | ||||||
|  | 	if s.Field != nil { | ||||||
|  | 		var err error | ||||||
|  | 		fieldsSelector, err = s.Field.Transform(removeMatchesSingleField) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return SelectionPredicate{}, err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return SelectionPredicate{ | ||||||
|  | 		Label:       s.Label, | ||||||
|  | 		Field:       fieldsSelector, | ||||||
|  | 		GetAttrs:    s.GetAttrs, | ||||||
|  | 		IndexFields: s.IndexFields, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| // For any index defined by IndexFields, if a matcher can match only (a subset) | // For any index defined by IndexFields, if a matcher can match only (a subset) | ||||||
| // of objects that return <value> for a given index, a pair (<index name>, <value>) | // of objects that return <value> for a given index, a pair (<index name>, <value>) | ||||||
| // wil be returned. | // wil be returned. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Wojciech Tyczynski
					Wojciech Tyczynski