Skip to content
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

Introduce ExtendedObjectMetadata, holding Writes #87

Merged
merged 3 commits into from
Feb 13, 2020

Conversation

MikeSpreitzer
Copy link
Owner

@MikeSpreitzer MikeSpreitzer commented Feb 8, 2020

Introduced an additional metadata section to Subnet and
NetworkEndpoint, holding a server-side timestamped record of the
latest write to each section of the object. The timestamps are full
precision, NOT truncated to a whole number of seconds.

Updated ipam and connection agent to use those write stamps instead of
the truncated creation timestamp in the relevant histograms. Also
introduced a histogram of latency from (a) setting of status by local
connection agent to (b) creation of remote ifc by remote connection
agent.

This may be viewed as a preview of the "managed fields" metadata that is coming along with server-side apply, to become pervasive in Kubernetes release 1.18. We are not ready to advance to release 1.18 yet; when we do, we may replace this with a use of the managed fields metadata.

Copy link
Collaborator

@matte21 matte21 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to pause the review and I'm not done yet, but there's already some stuff.

newSubnet := obj.(*network.Subnet)
newSubnet.ExtendedObjectMeta = oldSubnet.ExtendedObjectMeta
now := network.Now()
if newSubnet.Spec != oldSubnet.Spec {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is unneeded.
Currently spec is immutable for subnets (see *subnetStragey::ValidateUpdate), and *subnetStragey::PrepareForUpdate executes only for real updates, not for deletes followed by re-creates.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right.

newNA := obj.(*network.NetworkAttachment)
newNA.ExtendedObjectMeta = oldNA.ExtendedObjectMeta
now := network.Now()
if oldNA.Spec.Node != newNA.Spec.Node || oldNA.Spec.Subnet != newNA.Spec.Subnet || !SliceOfStringEqual(oldNA.Spec.PostCreateExec, newNA.Spec.PostCreateExec) || !SliceOfStringEqual(oldNA.Spec.PostDeleteExec, newNA.Spec.PostDeleteExec) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the checks on the spec fields but the one on postDeleteExec are unneeded.
Currently all spec fields but postDeleteExec are immutable for NetworkAttachments (see networkAttachmentStrategy::ValidateUpdate), and networkAttachmentStrategy::PrepareForUpdate executes only for real updates, not for deletes followed by re-creates.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the CA "samples" the postDeleteExec of an attachment when it creates a network interface for the attachment, and always ignores postDeleteExec thereafter. We could therefore drop the check on NetworkAttachment's spec altogether.

Copy link
Owner Author

@MikeSpreitzer MikeSpreitzer Feb 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, less to check is better.
I do not see why the cited behavior means the PostDelectExec field does not need to be examined for changes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not see why the cited behavior means the PostDelectExec field does not need to be examined for changes.

You mean examined for changes in networkAttachmentStragey::PrepareForUpdate?
Actually, you're right.


// GetWrite returns the write to the given section, or zero if there
// was none.
func (writes WriteSet) GetWrite(section string) ObjectWrite {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a nit, but how about this function returns a got bool field as well, which is set to false when no write is found? The same change would also happen in the internal API version types file.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea


// UnionLeft produces the union of the receiver and the other writes
// that do not overlap with the receiver
func (writes WriteSet) UnionLeft(others WriteSet) WriteSet {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method and the other Union methods are never used (same observation for internal API version types). Do you plan other commits where they are used?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I have some vague plans that use various of these.

func (writes WriteSet) UnionMin(others WriteSet) WriteSet {
ans := others.Diff(writes)
for _, wr := range writes {
owr := others.GetWrite(wr.Section)
Copy link
Collaborator

@matte21 matte21 Feb 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If others does not contain a write for the given section, GetWrite returns an empty ObjectWrite, which will be added to ans with an empty Section field. How about adding owr.Section = wr.Section?
Same applies to WriteSet::UnionMax and the equivalent functions in the internal API types file.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this logic is wrong for Min. For Max, it is guaranteed that the other will not be taken if it is the zero value.

Copy link
Collaborator

@matte21 matte21 Feb 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For Max, it is guaranteed that the other will not be taken if it is the zero value

Mmm... how is that guaranteed? AFAIU both UnionMin and UnionMax set ServerTime even if owr is the zero value, but Section could be left unset.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expectation is that real server times are positive, so will win over zero in Max.
But I am rewriting both to use the extra bool.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expectation is that real server times are positive, so will win over zero in Max.

But this affects in no way handling of Section.

}
}

func SliceOfStringEqual(x, y []string) bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is duplicated with the one in subnet strategy. Also, it is the negation of differ, one of the two could be therefore removed (I vote for differ). We should place this function in the util package (not necessarily now, even in the future).

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed differ. We can think about the right place to put a utitlity like SliceOfStringEqual. In k/k, there is a lot of careful factoring of sources.

Copy link
Collaborator

@matte21 matte21 Feb 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, let's do that on another occasion though. I would also expect k/k to already have a function like this in some util pkg.

newNA := obj.(*network.NetworkAttachment)
newNA.ExtendedObjectMeta = oldNA.ExtendedObjectMeta
now := network.Now()
if oldNA.Spec.Node != newNA.Spec.Node || oldNA.Spec.Subnet != newNA.Spec.Subnet || !SliceOfStringEqual(oldNA.Spec.PostCreateExec, newNA.Spec.PostCreateExec) || !SliceOfStringEqual(oldNA.Spec.PostDeleteExec, newNA.Spec.PostDeleteExec) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the CA "samples" the postDeleteExec of an attachment when it creates a network interface for the attachment, and always ignores postDeleteExec thereafter. We could therefore drop the check on NetworkAttachment's spec altogether.

@@ -1057,7 +1070,7 @@ func (ca *ConnectionAgent) updateLocalAttachmentStatus(att *netv1a1.NetworkAttac
updatedAtt.Status.PostCreateExecReport)

if att.Status.HostIP == "" {
ca.attachmentCreateToStatusHistogram.Observe(tAfterUpdate.Truncate(time.Second).Sub(att.CreationTimestamp.Time).Seconds())
ca.attachmentCreateToStatusHistogram.Observe(updatedAtt.Writes.GetServerWriteTime(netv1a1.NASectionAddr).Sub(att.Writes.GetServerWriteTime(netv1a1.NASectionSpec)).Seconds())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't s/netv1a1.NASectionAddr/netv1a1.NASectionImpl/?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right

Introduced an additional metadata section to Subnet and
NetworkEndpoint, holding a server-side timestamped record of the
latest write to each section of the object.  The timestamps are full
precision, NOT truncated to a whole number of seconds.

Updated ipam and connection agent to use those write stamps instead of
the truncated creation timestamp in the relevant histograms.  Also
introduced a histogram of latency from (a) setting of status by local
connection agent to (b) creation of remote ifc by remote connection
agent.
@MikeSpreitzer
Copy link
Owner Author

The force-push to 3edb973 is a rebase onto add-kos.

@@ -83,7 +84,7 @@ func (writes WriteSet) SetWrite(section string, serverTime Timestamp) WriteSet {
func (writes WriteSet) Diff(others WriteSet) WriteSet {
ans := make(WriteSet, 0, len(writes))
for _, wr := range writes {
owr := others.GetWrite(wr.Section)
owr, _ := others.GetWrite(wr.Section)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other nit, but the following check could use the bool variable.

@MikeSpreitzer
Copy link
Owner Author

MikeSpreitzer commented Feb 10, 2020

BTW, I am starting to get the idea that server-side apply is intended to have comprehensive coverage regardless of operation. That is being worked in master right now. I have not yet been able to get a successful test of that.

@MikeSpreitzer
Copy link
Owner Author

There is also this: kubernetes/community#4218 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants