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

IPEP 15: autosave the notebook #3158

Merged
merged 24 commits into from May 2, 2013
Merged

IPEP 15: autosave the notebook #3158

merged 24 commits into from May 2, 2013

Conversation

minrk
Copy link
Member

@minrk minrk commented Apr 10, 2013

See IPEP 15 for details of the proposal.

This is not quite complete, the most glaring omission is, of course, the autosave timer itself, but that's pretty trivial. The checkpointing machinery is fairly complete, and ready to discuss / review.

The gist: autosave will do a real save periodically. To address the undesirable effects of true autosave, user-initiated saves create checkpoints, which can be restored. In this preliminary implementation, the file-based notebook manager only supports one checkpoint.

@minrk
Copy link
Member Author

minrk commented Apr 11, 2013

Okay, this actually autosaves now. The timer follows the following logic:

  • autosave will never happen more frequently than every 30 seconds
  • if saves take more than 3 seconds, autosave will fire every 10x the duration of a save (i.e. if save takes 6 seconds, it will be every 60 seconds, etc.)

@minrk
Copy link
Member Author

minrk commented Apr 15, 2013

For linking, this will close #1378 and #3153.

@drevicko
Copy link
Contributor

I think I get the logic behind firing every 10x the duration of the save (if it takes more than 3s), but feel it could do with a moments discussion... It might be good to put an upper limit on the time between saves - perhaps 5 minutes??

If for some bizarre reason, a particular save takes, say, 20s, then it'll be 3 mins 20secs before the next one. This can happen for example when the users client computer has a process that temporarily fills up it's memory, or perhaps the connection gets clogged by a flatmate downloading something huge or a cafe enforcing a rate limit.

In such cases, it makes sense to reduce the load of autosaves on resources. However the flipside is that the user may be surprised that the notebook wasn't saved. The 20s -> 3mins20secs is perhaps ok, but what if a save takes a reallly long time, say 3 minutes?

The situations in which I can imagine a save taking a long time:

  • very laggy connection
  • huge notebook
  • very laggy client computer
  • very laggy server

@minrk
Copy link
Member Author

minrk commented Apr 24, 2013

It's a tricky choice. I would say that it's the right decision in an extremely low bandwidth case to have quite infrequent saves - even as infrequent as half an hour, if it really does take three minutes (most likely on a weak cellular connection or similar). The user is informed when the autosave frequency changes, so they will see "autosaving every 1800s" in the notification area if a save takes three minutes, and the 'last saved' area still has the last saved time stamp, etc.

@drevicko
Copy link
Contributor

Yep, fair enough. And the user can always elect to manually save if they see that auto-saves are far apart. Does it detect how long the most recent save took? Or is it the most recent auto-save? My thinking is a situation where a save is unusually slow for a temporary reason - if the user does a manual save a little later that is quick, perhaps the autosave machinery should notice.

As a matter of interest, is the notebook sent to the server as some sort of diff or as full text? I'm guessing full text. (I guess I'm thinking of google docs again - I believe they have a clever engine for that - I wonder if it can be borrowed?)

@ellisonbg
Copy link
Member

Right now we send the entire notebook each time. In the future we plan on sending just the diffs, but that is going to take quite a bit more work.

@@ -104,7 +105,11 @@
_kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
_kernel_action_regex = r"(?P<action>restart|interrupt)"
_notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
<<<<<<< HEAD
Copy link
Member

Choose a reason for hiding this comment

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

Opps...

Copy link
Member

Choose a reason for hiding this comment

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

Conflict markers got committed.

@ellisonbg
Copy link
Member

Done reviewing the server side of things. Overall the code is really clean and nice. I really like this design and its server side implementation a lot. Great work! Now onto the frontend side...

@ellisonbg
Copy link
Member

The save button in the main toolbar still has a hover help text of "Save". This should be "Checkpoint" and maybe we should change the icon?

@ellisonbg
Copy link
Member

Ahh, I see that "Save" still exists in the UI. I think this will confuse users. What do you think about only having "Checkpoint" be visible to the users. IOW, make save an internal detail...?

@ellisonbg
Copy link
Member

Hmm, I am not seeing the behavior I was expecting in the UI. Not sure if it is broken or I just had false expectations of how it would work.


@line_magic
def autosave(self, arg_s):
"""Set the lower-limit for the autosave frequency in the notebook (in seconds).
Copy link
Member

Choose a reason for hiding this comment

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

Do you mean upper limit here?

Copy link
Member

Choose a reason for hiding this comment

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

I actually think we should say "Set the autosave interval in the notebook (in seconds)." here.

Copy link
Member Author

Choose a reason for hiding this comment

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

done.

@fperez
Copy link
Member

fperez commented Apr 27, 2013

In case anyone really cares, we had an extensive discussion of this during a public Google hangout. We'll do more of those, open to anyone for participation, for issues that require high-bandwidth communication.

@ellisonbg
Copy link
Member

Right now, the user invoked actions in the UI are for "Save and Checkpoint". But the "Last saved" date/time in the page header is for the last autosaved time. This is a bit confusing. In some cases, I think that users will want to see the time of last checkpoint instead. Thoughts?

@minrk
Copy link
Member Author

minrk commented Apr 29, 2013

I can change it to the last checkpoint easily enough. Do we want to keep UI for the last autosave as well?

@minrk
Copy link
Member Author

minrk commented Apr 29, 2013

Also, do we want a visual indication of the 'dirty' flag?

@ellisonbg
Copy link
Member

While Google Docs uses a very different model of autosave than we have here, I feel like their messages about the save status are quite useful. You quickly see the save status of the document. I do think it would be useful to tell the user that there are unsaved changes, and tell them when the autosave has been done. That will put peoples mind at ease. Nto sure how to present all of that information though.

console.log("restore dialog, but no checkpoint to restore to!");
return;
}
var dialog = $('<div/>').append(
Copy link
Member

Choose a reason for hiding this comment

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

I think I would make these different paragraphs a single one, or put spaces between them. Otherwise it just looks like poorly justified text.

minrk added 19 commits May 1, 2013 17:32
instead of "please don't leave!"
autosave interval is tuned based on the duration of saves.
Autosave will never happen more frequently than every 30 seconds,
and if saves take more than 3 seconds, autosave will fire every 10x the duration of the save (i.e. if save takes 6 seconds, it will be every 60 seconds, etc.)
use IPythonHandler, avoid self.application
autosave is also there, but once the dirty flag is an event,
this should stop having the date, and just become 'autosaved / unsaved changes'
also cleanup a few log messages
minor styling update to the restore dialog as well
@fperez
Copy link
Member

fperez commented May 2, 2013

My only concern at this point is purely cosmetic: with so much infromation printed about the checkpoint/save times, it doesn't take a very long notebook title before all that rolls over in a pretty ugly way:

image

But improving this would really require rethinking the layout of the UI deeper. I think we'll need to do that, but I don't think it's wise to hold this important and complex PR any further just on that. Thoughts?

@minrk
Copy link
Member Author

minrk commented May 2, 2013

It will be shorter when the dirty event is introduced, at which point the 'autosaved: DATE' will simply be autosaved or unsaved changes, depending on whether the current view of the file is in sync with the autosaved version, but not short enough to really alleviate the problem. It won't solve the real issue of the fact that the save widget as it is now is just much too wide (and this PR makes it wider). I think revisiting how the save widget looks is definitely something we have to do, but I think it can be separate.

@fperez
Copy link
Member

fperez commented May 2, 2013

Sounds good. Merging now, then! This was a long and painful one, kudos for a fantastic job, and I'm glad we suffered through the long and detailed discussion period. While in the end the chosen implementation isn't anything fancy or complex, I like that we took the time to dig at length into all the caveats and possible problems. Thanks!!

fperez added a commit that referenced this pull request May 2, 2013
Add autosaving to the notebook, while retaining manual checkpoint creation.

Autosave will perodically save the notebook, with a default interval of two minutes. This interval is configurable, and the system will automatically back off the frequency if it detects that the save operation takes too long. This can be the case if working remotely over a slow link, so this will automatically conserve bandwidth.

The manual save operation remains available and bound to the same keys, but now it causes the creation of a separate checkpoint, which is stored in a hidden directory called `.ipynb_checkpoints`.  This provides users a poor-man's version control with a single revert point and the ability to safely experiment with potentially destructive changes to a notebook without concern that the autosave operation may clobber their file on disk.

See [IPEP 15](https://github.com/ipython/ipython/wiki/IPEP-15%3A-Autosaving-the-IPython-Notebook) for details of the proposal.
@fperez fperez merged commit b69eb67 into ipython:master May 2, 2013
@minrk minrk deleted the autosave branch May 2, 2013 01:06
@minrk minrk restored the autosave branch May 2, 2013 01:06
@minrk minrk deleted the autosave branch March 31, 2014 23:36
mattvonrocketstein pushed a commit to mattvonrocketstein/ipython that referenced this pull request Nov 3, 2014
Add autosaving to the notebook, while retaining manual checkpoint creation.

Autosave will perodically save the notebook, with a default interval of two minutes. This interval is configurable, and the system will automatically back off the frequency if it detects that the save operation takes too long. This can be the case if working remotely over a slow link, so this will automatically conserve bandwidth.

The manual save operation remains available and bound to the same keys, but now it causes the creation of a separate checkpoint, which is stored in a hidden directory called `.ipynb_checkpoints`.  This provides users a poor-man's version control with a single revert point and the ability to safely experiment with potentially destructive changes to a notebook without concern that the autosave operation may clobber their file on disk.

See [IPEP 15](https://github.com/ipython/ipython/wiki/IPEP-15%3A-Autosaving-the-IPython-Notebook) for details of the proposal.
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.

None yet

4 participants