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

create a metadata envelope for nodes #369

Merged
merged 17 commits into from
Oct 14, 2016
Merged

Conversation

BrianHicks
Copy link
Contributor

These changes are enable future expansion in the following:

  • better errors (keep metadata for location and include it)
  • letting preparers know their names

Points of interest in this PR:

  • add a metadata wrapper for future expansion (graph/node/node.go)
  • graph.Get return value changes from interface{} to (meta *node.Node, ok bool). This is basically removing Get in favor of MaybeGet and
    renaming/reworking everything to use the new return value.
  • graph.GetParent return value changes from interface{} to (meta *node.Node, ok bool) in the same way.
  • walking functions change from interface{} to *node.Node

This PR changes a whole lot of stuff, but it's all in service of the changes
above. This might cause some integration headaches but should improve failure
detection, since call sites now have to explicitly handle missing nodes (they
didn't before, oops)

@rebeccaskinner rebeccaskinner self-assigned this Oct 12, 2016
Copy link
Contributor

@rebeccaskinner rebeccaskinner left a comment

Choose a reason for hiding this comment

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

Not requesting changes because I think they are more open design questions about if/when we should do some things.

@@ -68,7 +69,14 @@ func execPipeline(ctx context.Context, in *graph.Graph, pipelineF MkPipelineF, r
notify.Transform(func(id string, out *graph.Graph) error {
renderingPlant.Graph = out
pipeline := pipelineF(out, id)
val, pipelineError := pipeline.Exec(out.Get(id))
Copy link
Contributor

Choose a reason for hiding this comment

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

Since we are using the ID inside of the pipeline, does it make sense to actually go ahead and pass the entire node into the pipeline instead of extracting it, then pull the ID from the node rather than putting it into the pipeline?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What would that look like? I'm having a hard time understanding what you're saying here.

Copy link
Contributor

Choose a reason for hiding this comment

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

inside of apply/pipeline we have:

type pipelineGen struct {
    Graph          *graph.Graph
    ID             string
    RenderingPlant *render.Factory
}

and

func Pipeline(g *graph.Graph, id string, factory *render.Factory) executor.Pipeline {
    gen := &pipelineGen{Graph: g, RenderingPlant: factory, ID: id}

since the ID is now going to be part of the element we could remove the ID from pipelineGen and the call to Pipeline. It's not necessarily hurting anything to have it as it is, but it does get us down to a single source-of-truth for the ID.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm, that seems like it would be a good future addition. One of the optimizations we've been talking about, yeah?

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah that's fair 👍

pipeline := Pipeline(out, id, renderingPlant)
val, pipelineErr := pipeline.Exec(out.Get(id))
Copy link
Contributor

Choose a reason for hiding this comment

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

As with apply- does it make sense to pass the entire node in here and handle it correctly inside the pipeline?

}

// New creates a new node
func New(id string, value interface{}) *Node {
Copy link
Contributor

Choose a reason for hiding this comment

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

I've noticed that we have a general pattern of at each phase in the processing pipeline (load,render,plan,and apply) we create a new *Node, with the ID and value. That works for now but it does require that we have knowlege that the id and value are the only relevant fields in the node, and that nothing earlier in the pipeline has added useful metadata.

Would it make sense to have a func (n *Node) SetValue(newValue interface{}) { that would set the value, or else a func (n *Node) Transform(func (interface{}) (interface{}, error) ) (*Node, error) that transforms the value inside of the node, so that later phases of the processing pipeline can update the inner value without losing accumulated metadata information?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, we need to not lose accumulated metadata… SetValue works but it means we're mutating the nodes. We could copy them, of course, but that essentially means throwing away an entire graph at every stage. I'm not sure what the right solution is. Since our processing only goes forward and never forks, mutating might make sense. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I prefer the idea of copying because it doesn't feel like the size of the graph is going to be large enough that it's going to introduce enormous overhead; we already replace the node at each stage so we'd only be introducing the addition of copying the metadata which doesn't seem like it should be all that much extra?

Also in the absence of a compelling reason to mutate I'd say that we're better to prefer copying just to avoid bugs related to parallel execution- I don't really have any specific case in mind where that would happen but it does just seem like the sort of thing.

@BrianHicks BrianHicks mentioned this pull request Oct 12, 2016
@BrianHicks BrianHicks added this to the 0.3.0 milestone Oct 13, 2016
@rebeccaskinner
Copy link
Contributor

LGTM on green

@BrianHicks BrianHicks merged commit acaf875 into master Oct 14, 2016
@BrianHicks BrianHicks deleted the feature/metadata-envelope branch October 14, 2016 18:09
BrianHicks added a commit that referenced this pull request Dec 22, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants