views:

254

answers:

6

I have been hacking on the code for Xournal in order to add auto-save functionality. My initial implementation was very dumb: every 60 or so seconds, do a save. The feature ostensibly works.

However, after testing it out for a while, I've noticed that when auto-save runs, the application temporarily freezes up, which is quite annoying if you're in the middle of a pen stroke. I'm trying to figure out how to fix this.

One possibility I've thought up of is for autosave to check whether or not the pen is touching the screen before autosaving; if it is touched, attach a one time only callback scheduled for a second after the pen is lifted. (if the same thing happens, repeat). Another possibility would be to optimize the save function sufficiently such that there is no gap (seems unlikely).

Anyone have any suggestions about this? Xournal uses the Gnome/GTK toolkit, and is written in C.

Update: I implemented the anti-clobber logic, and I'm very happy with the resulting autosave granularity and performance. One of those times threads are (thankfully) not necessary! Thanks all for your suggestions.

A: 

Can you push the autosave functionality to a separate thread? By running on a second thread you would be able to run the save in parallel with the gui and would avoid the freezing window.

I've got very little experience with c, but I would think this site could help.

chills42
+2  A: 

If the UI freezes for any noticeable period of time, a separate thread is probably the way to go. If the only reason you're noticing the UI freeze is because you happen to be writing at the time and the interruption is only very brief, then your method might work. Your fix is probably way easier than creating another thread, so try that first.

If you do end up using threads, go with g_threads instead of pthreads since you're using GTK+. They'll be more portable.

Evan Shaw
A: 

While I would agree using threads is a "correct" textbox answer, it's not always the way you have to do things. Multithreading tends to bring up tons of issues if you're not careful -- the main one here probably being locking access to the data during the autosave. Then if the main thread enters a wait to access the data, you're right back where you started. So then you create a queue of pending changes or something, and you lose track of what's going on. Depending on how complex the underlying data structures are, making a copy could also freeze the main thread.

Anyways point being, I would try your first option. It's quick, simple, and to the point, and I don't see why it wouldn't work.

(Note: I haven't looked under the hood of Xournal so take this with a grain of salt. Or a salt shaker. Or something)

zildjohn01
I wonder if I can make it so that there wouldn't be any contention issues. As far as I can tell, the data structure is entirely linked lists. This might be an issue for another question.
Edward Z. Yang
A: 

I've had a similar situation in the past and here's the way I solved it (.Net):

  1. Background timer ticks at x second intervals
  2. On the tick, disable the timer and handle the appropriate event.
  3. In the event handler, save and enable the timer.

The only flaw we've seen actually happen was someone killing the app before the event handler is called and losing 1 minute's worth of work.

Austin Salonen
That seems to be what I have already? I'm not sure I understand your answer.
Edward Z. Yang
A: 

How about this?

Use the callback idea but have it run every 10 inputs in addition to every 60 seconds. With a time-based autosave, there's a problem that the amount of stuff that gets lost is proportional to how fast the user can work.

If you want to go a step further, have it save a partial undo log to disk after every change in addition to the full save. That way, the worst thing that can happen from a crash is losing the last input stroke.

Ant P.
Those are both interesting ideas, and also seem to match with what is implemented in environments were doing full backups is not feasible (databases). I will need to figure out whether or the input events are easily serializable or not.
Edward Z. Yang
A: 

My focus is to use an hipervisor thread comparing via some hash algorithm the file contents every N secs on change event then notify to the parent thread and callback the autosave function.

Jorge Niedbalski R.