-
Notifications
You must be signed in to change notification settings - Fork 38.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make sure no op updates don't affect the resource version due to serverside apply #81673
Conversation
// Update the time in the managedFieldsEntry for this operation | ||
managed.Times[manager] = &metav1.Time{Time: time.Now().UTC()} | ||
// Update the time in the managedFieldsEntry for this operation if the fieldset changed | ||
if originalManagedFields == nil || !managed.Fields[manager].Set().Difference(originalManagedFields.Set()).Empty() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would mean that we only update the time on these entries when the field set changes, not when the values change of something which is already owned.
Also, we don't need to check the reverse difference because an updater's fieldset can only grow by doing an update operation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
an updater's fieldset can only grow by doing an update operation.
Can you elaborate on that? What if you remove an optional field?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing a field or list item is something I didn't think of. We can check both directions of the difference then. But I wasn't sure if this is even the direction we want to go for when to update the time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about it more, we could probably do this instead:
if c, err := liveObjTyped.Compare(newObjTyped); err == nil && !c.IsSame() {
/retest |
That's very important, thanks for doing it |
"metadata": { | ||
"name": "` + podName + `" | ||
}, | ||
"spec": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to have a more sophisticated object so that we know that maps, associative list and everything keep things in order?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can do that, but as it is, the ownership already looks like:
"fields": {
"f:spec": {
"f:containers": {
"k:{\"name\":\"test-container\"}": {
"f:image": {},
"f:imagePullPolicy": {},
"f:name": {},
"f:resources": {},
"f:terminationMessagePath": {},
"f:terminationMessagePolicy": {},
".": {}
}
},
"f:dnsPolicy": {},
"f:enableServiceLinks": {},
"f:restartPolicy": {},
"f:schedulerName": {},
"f:securityContext": {},
"f:terminationGracePeriodSeconds": {}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, multiple containers does help
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
multiple containers and a few labels should cover most of the interesting features
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, I would like to see if the comparison is expensive
// Update the time in the managedFieldsEntry for this operation | ||
managed.Times[manager] = &metav1.Time{Time: time.Now().UTC()} | ||
// Update the time in the managedFieldsEntry for this operation if the object changed | ||
if same, err := f.isSame(liveObjTyped, newObjTyped); err == nil && !same { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should run before/after benchmarks to see if that's fine
"metadata": { | ||
"name": "` + podName + `" | ||
}, | ||
"spec": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, multiple containers does help
1ac9b12
to
bc63b7e
Compare
|
I'm guessing mostly because compare is still allocating a merged object which we throw away |
Yeah, that's what I was expecting too ... |
And the other benchmarks:
|
a1591b1
to
5524043
Compare
Okay, without the comparison, the new benchcmp is much better:
|
8e5b6e6
to
46bddb7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If i don't look at the failing . tests, it looks good :-)
// operations from the same manager if the object changed | ||
if f, ok := managed.Fields["self"]; ok { | ||
if old, ok := managed.Fields[manager]; ok { | ||
f = fieldpath.NewVersionedSet(f.Set().Union(old.Set()), f.APIVersion(), f.Applied()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting how we could remove that union from smd now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we could do that and simplify things, just need to make sure that people don't give the same manager name to smd as any existing manager for updates (maybe return an error?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine. As long as we never send the same manager, the union is always going to be a no-op?
7af95df
to
572d2dc
Compare
572d2dc
to
aa1f01e
Compare
@apelisse the tests are passing now |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: apelisse, jennybuckley The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What type of PR is this?
/kind bug
/priority important-soon
/sig api-machinery
/wg apply
/cc @apelisse
What this PR does / why we need it:
Adds a test to make sure no op updates don't affect the resource version due to serverside apply, and fixes a bug where this wasn't true
Does this PR introduce a user-facing change?: