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

workspace: recover from missing operation #2905

Merged
merged 3 commits into from
Feb 9, 2024
Merged

workspace: recover from missing operation #2905

merged 3 commits into from
Feb 9, 2024

Conversation

jonathantanmy
Copy link
Contributor

In the commit message, I've added a discussion of alternate ways of how we can handle this situation, with my rationale for how I ended up doing it in the commit. If there are other (and maybe better) ways of handling this, feel free to let us know.

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added tests to cover my changes

@jonathantanmy jonathantanmy force-pushed the jt/missingop branch 3 times, most recently from 2098893 to af8b6d1 Compare January 31, 2024 23:40
cli/src/cli_util.rs Outdated Show resolved Hide resolved
cli/src/cli_util.rs Outdated Show resolved Hide resolved
cli/src/cli_util.rs Outdated Show resolved Hide resolved
cli/src/cli_util.rs Outdated Show resolved Hide resolved
cli/src/cli_util.rs Outdated Show resolved Hide resolved
@jonathantanmy jonathantanmy force-pushed the jt/missingop branch 2 times, most recently from 1e405be to 8344a76 Compare February 2, 2024 21:52
@jonathantanmy
Copy link
Contributor Author

After some internal investigation at work, I've updated the code to also be more resilient when the current tree of the working copy is also missing (so, not only the operation). I've addressed all the comments (hopefully) except for the ones that involve some refactoring (moving create_and_check_out_recovery_commit() and some associated functions to the caller, and inlining is_stale()) - I'll continue to work on those.

lib/src/working_copy.rs Show resolved Hide resolved
cli/src/commands/workspace.rs Show resolved Hide resolved
cli/src/commands/workspace.rs Outdated Show resolved Hide resolved
cli/src/commands/workspace.rs Outdated Show resolved Hide resolved
cli/src/commands/workspace.rs Outdated Show resolved Hide resolved
cli/src/commands/workspace.rs Outdated Show resolved Hide resolved
lib/src/working_copy.rs Show resolved Hide resolved
lib/src/local_working_copy.rs Show resolved Hide resolved
cli/src/commands/workspace.rs Show resolved Hide resolved
@jonathantanmy jonathantanmy force-pushed the jt/missingop branch 3 times, most recently from d08d1b8 to 9ebcb89 Compare February 9, 2024 00:46
Move this function from cli_util.rs, since workspace.rs is the only
caller. This function will be enlarged in a subsequent commit.
A subsequent commit will need to handle the return value of
check_stale_working_copy() in 3 different ways, so a boolean will soon
not be sufficient. In preparation for that, inline is_stale() into its
caller, converting it into a "match".
@jonathantanmy jonathantanmy force-pushed the jt/missingop branch 2 times, most recently from 537e1f1 to 6b4cec1 Compare February 9, 2024 01:33
@martinvonz
Copy link
Member

LGTM, but I'll let Yuya give the final approval. Thanks, both of you!

Copy link
Contributor

@yuja yuja left a comment

Choose a reason for hiding this comment

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

Thanks!

cli/src/cli_util.rs Outdated Show resolved Hide resolved
cli/src/cli_util.rs Outdated Show resolved Hide resolved
cli/src/commands/workspace.rs Outdated Show resolved Hide resolved
cli/src/commands/workspace.rs Outdated Show resolved Hide resolved
cli/src/commands/workspace.rs Show resolved Hide resolved
@jonathantanmy jonathantanmy self-assigned this Feb 9, 2024
If the operation corresponding to a workspace is missing for some reason
(the specific situation in the test in this commit is that an operation
was abandoned and garbage-collected from another workspace), currently,
jj fails with a 255 error code. Teach jj a way to recover from this
situation.

When jj detects such a situation, it prints a message and stops
operation, similar to when a workspace is stale. The message tells the
user what command to run.

When that command is run, jj loads the repo at the @ operation (instead
of the operation of the workspace), creates a new commit on the @
commit with an empty tree, and then proceeds as usual - in particular,
including the auto-snapshotting of the working tree, which creates
another commit that obsoletes the newly created commit.

There are several design points I considered.

1) Whether the recovery should be automatic, or (as in this commit)
manual in that the user should be prompted to run a command. The user
might prefer to recover in another way (e.g. by simply deleting the
workspace) and this situation is (hopefully) rare enough that I think
it's better to prompt the user.

2) Which command the user should be prompted to run (and thus, which
command should be taught to perform the recovery). I chose "workspace
update-stale" because the circumstances are very similar to it: it's
symptom is that the regular jj operation is blocked somewhere at the
beginning, and "workspace update-stale" already does some special work
before the blockage (this commit adds more of such special work). But it
might be better for something more explicitly named, or even a sequence
of commands (e.g. "create a new operation that becomes @ that no
workspace points to", "low-level command that makes a workspace point to
the operation @") but I can see how this can be unnecessarily confusing
for the user.

3) How we recover. I can think of several ways:
a) Always create a commit, and allow the automatic snapshotting to
create another commit that obsoletes this commit.
b) Create a commit but somehow teach the automatic snapshotting to
replace the created commit in-place (so it has no predecessor, as viewed
in "obslog").
c) Do either a) or b), with the added improvement that if there is no
diff between the newly created commit and the former @, to behave as if
no new commit was created (@ remains as the former @).
I chose a) since it was the simplest and most easily reasoned about,
which I think is the best way to go when recovering from a rare
situation.
@jonathantanmy
Copy link
Contributor Author

Thanks everyone. I'll go ahead and merge this PR.

@jonathantanmy jonathantanmy merged commit 33f3a42 into main Feb 9, 2024
15 checks passed
@jonathantanmy jonathantanmy deleted the jt/missingop branch February 9, 2024 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants