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

Avoid (second) copy when combining layers #499

Open
flotter opened this issue Sep 16, 2024 · 3 comments
Open

Avoid (second) copy when combining layers #499

flotter opened this issue Sep 16, 2024 · 3 comments
Labels
25.04 Planned for the 25.04 cycle Simple Nice for a quick look on a minute or two

Comments

@flotter
Copy link
Contributor

flotter commented Sep 16, 2024

By my evaluation of the code, the plan library is implemented with very specific handling of the layers. The content of layers come from the original layers directory load, and can then be further modified through HTTP API append and combine calls.

However, when performing any combine of layers, deep copies of layer contents must be used to prevent reference / pointer types backed by memory inside the layer struct from getting mutated during the lifetime of the process. Allowing this will corrupt future combine attempts of the original layers stack.

At the top level we seem to also copy the contents that may originate from the combined layer, which already can only contain copied content, as it always starts empty.

Although this does not hurt, with plan extensions support, it may be a good idea to have the code as accurate as possible, as this will typically be copy/pasted as reference code when implementing an extension.

In the code snippet below, do we really want to copy the already combined service, which itself is a copy?

CombineLayers:

    combined := &Layer{
        Services:   make(map[string]*Service),
        Checks:     make(map[string]*Check),
        LogTargets: make(map[string]*LogTarget),
        Sections:   make(map[string]Section),
    }
    :
    combined.Summary = last.Summary
    combined.Description = last.Description
    for _, layer := range layers {
        for name, service := range layer.Services {
            switch service.Override {
            case MergeOverride:
                if old, ok := combined.Services[name]; ok {
                    copied := old.Copy()    <<<============================== ?
                    copied.Merge(service)
                    combined.Services[name] = copied
                    break
                }
                fallthrough
            case ReplaceOverride:
                combined.Services[name] = service.Copy()
            case UnknownOverride:
                return nil, &FormatError{
                    Message: fmt.Sprintf(`layer %q must define "override" for service %q`,
                        layer.Label, service.Name),
                }
            default:
                return nil, &FormatError{
                    Message: fmt.Sprintf(`layer %q has invalid "override" value for service %q`,
                        layer.Label, service.Name),
                }
            }
        }
        :    
@flotter
Copy link
Contributor Author

flotter commented Sep 16, 2024

@benhoyt @hpidcock If you could share some wisdom here that would be very much appreciated! This is not urgent.

@benhoyt
Copy link
Contributor

benhoyt commented Sep 16, 2024

Yeah, I think you're right. Feel free to put up a PR to fix (there's probably already test coverage of these cases -- but worth double-checking). I've also never liked that fallthrough, as I just find it confusing. What about this:

			switch service.Override {
			case MergeOverride:
				if previous, ok := combined.Services[name]; ok {
					previous.Merge(service)
				} else {
					combined.Services[name] = service.Copy()
				}
			case ReplaceOverride:
				combined.Services[name] = service.Copy()
			...
			}

@benhoyt benhoyt changed the title Question regarding plan deep copy on combine Avoid (second) copy when combining layers Sep 24, 2024
@benhoyt benhoyt added Simple Nice for a quick look on a minute or two 25.04 Planned for the 25.04 cycle labels Nov 28, 2024
@benhoyt
Copy link
Contributor

benhoyt commented Nov 28, 2024

Hiya @flotter, any update on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
25.04 Planned for the 25.04 cycle Simple Nice for a quick look on a minute or two
Projects
None yet
Development

No branches or pull requests

2 participants