-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
state: more robust handling of state Serial #15424
Conversation
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! This is exactly what I was thinking, and should better align with the expectations of TFE. I'll review again once we sort out the test failures.
} else if s == nil || other == nil { | ||
return false | ||
} | ||
|
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.
not a big deal, but do you want to short-circuit marshaling by comparing serial/lineage first?
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.
There isn't really a great reason to call this without those matching, so I didn't see a reason to optimize for the edge case here... the only current practical use for this is to compare two states that have the same serial and lineage, to detect any other updates.
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.
true, it's just the endless optimizer in me coming out in the wrong place 👍
367996b
to
4f528e2
Compare
Previously we relied on a constellation of coincidences for everything to work out correctly with state serials. In particular, callers needed to be very careful about mutating states (or not) because many different bits of code shared pointers to the same objects. Here we move to a model where all of the state managers always use distinct instances of state, copied when WriteState is called. This means that they are truly a snapshot of the state as it was at that call, even if the caller goes on mutating the state that was passed. We also adjust the handling of serials so that the state managers ignore any serials in incoming states and instead just treat each Persist as the next version after what was most recently Refreshed. (An exception exists for when nothing has been refreshed, e.g. because we are writing a state to a location for the first time. In that case we _do_ trust the caller, since the given state is either a new state or it's a copy of something we're migrating from elsewhere with its state and lineage intact.) The intent here is to allow the rest of Terraform to not worry about serials and state identity, and instead just treat the state as a mutable structure. We'll just snapshot it occasionally, when WriteState is called, and deal with serials _only_ at persist time. This is intended as a more robust version of #15423, which was a quick hotfix to an issue that resulted from our previous slopping handling of state serials but arguably makes the problem worse by depending on an additional coincidental behavior of the local backend's apply implementation.
4f528e2
to
4d53eaa
Compare
In practice, States must all implement the full interface, so checking for each method set only leaves gaps where tests could be skipped. Change the helper to only accept a full state.State implementation. Add some Lineage, Version, and TFVersion checks to TestState to avoid regressions. Compare the copy test against the immediate State returnedm rather than our previous "current" state. Check that the states round-trip and still marhsal identically via MarshalEqual.
The state returned from the testState helper shouldn't rely on any mutations caused by WriteState. The Init function (which is analogous to NewState) shoudl set any required fields.
We have a helper function that we hardly ever use. TODO: convert the rest of the manual ReadState calls eventually.
fca3e82
to
fb39706
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.
LGTM!
I added a couple more minor tests (plus some mechanical refactoring), and things still pass. Feeling better about this already 👍
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. |
Previously we relied on a constellation of coincidences for everything to work out correctly with state serials. In particular, callers needed to be very careful about mutating states (or not) because many different bits of code shared pointers to the same objects.
Here we move to a model where all of the state managers always use distinct instances of state, copied when
WriteState
is called. This means that they are truly a snapshot of the state as it was at that call, even if the caller goes on mutating the state that was passed.We also adjust the handling of serials so that the state managers ignore any serials in incoming states and instead just treat each Persist as the next version after what was most recently Refreshed.
(An exception exists for when nothing has been refreshed, e.g. because we are writing a state to a location for the first time. In that case we do trust the caller, since the given state is either a new state or it's a copy of something we're migrating from elsewhere with its state and lineage intact.)
The intent here is to allow the rest of Terraform to not worry about serials and state identity, and instead just treat the state as a mutable structure. We'll just snapshot it occasionally, when
WriteState
is called,and deal with serials only at persist time.
This is intended as a more robust version of #15423, which was a quick hotfix to an issue that resulted from our previous slopping handling of state serials but arguably makes the problem worse by depending on an additional coincidental behavior of the local backend's apply
implementation.