Proposed Backup Strategy for GnuCash
====================================
Goals
-----
GnuCash's method for backing up its database files should protect
against three kinds of failures:
1. A crash during the operation of GnuCash that doesn't affect the
database file, but which prevents newly-entered data from being saved.
2. An error during the writing of a GnuCash database file that
prevents the file being written correctly, resulting in an obviously
incorrect file. This could be caused by, e.g., a power or hardware failure,
running out of disk space, the user hitting ctrl-c or killing the
process in some other way, or a bug in the GnuCash file i/o code.
3. The creation of a GnuCash database file that is a readable but
incorrect in a non-obvious way. Such a problem may not be discovered
for some time. Such a problem could be caused by a bug in GnuCash or
by the user accidentally entering wrong data or performing an operation
that was later determined to be undesirable (like deleting an account).
Current Status
--------------
GnuCash only writes the main database file when requested by the user.
Currently, when saving, GnuCash writes the main database file and then
writes a time-stamped duplicate of that file. Thus, the user will have
a 'save history' of database files that record the state of the database
at each point the user requested a save. This 'save history' will
protect against failure #3, as you can revert to an earlier, correct
version of the database.
GnuCash also creates an ascii log file which records changes made to
GnuCash entities during operation. Currently, this log file can be
used to manually recover from failure #1, but there is no automated
way to do so, or any other support for protecting against this kind
of error.
Problems
--------
+ Recovering manually from a log is tedious and thus failure #1 is a
real pain.
+ None of the current backup methods will protect against failure #2.
Proposed Solution
-----------------
+ To better handle failure #1, GnuCash should create 'autosave' files
periodically. The length of the period should be configurable by the
user. An autosave file would be a complete database that records the
state when the autosave happens. Subsequent autosaves will overwrite
any existing autosave file.
When GnuCash starts, it should check for the presence of an autosave
file and, if it exists and has a later modification time than the
main file, GnuCash should prompt the user to load the autosave file
instead.
+ GnuCash should continue creating log files as a secondary mechanism
for handling failure #1.
+ To handle failure #2, GnuCash should change the way it saves the main
database file. Saving should be done by:
1. Writing the new database to a temporary file.
2. Moving or copying the old database to a backup file,
overwriting any existing backup file.
3. Moving the temporary file to the main database file.
Thus, after successful completion of a save, the original database will
be saved in a backup file.
If there is a writing failure during step 1, the original database is
untouched.
+ GnuCash should continue creating 'save history' backups to handle
failure #3.
Pseudo-Code Implementation
--------------------------
Autosaving: every autosave_period() time units {
if (database_has_changed()) {
save_database_to_file("<original name>.autosave");
if (error)
report_error_to_gui();
}
}
Explicit Saving: save_database_to_file("<original name>.tmp");
if (error) {
report_error_to_gui();
return;
}
rename("<original name>", "<original name>~");
if (error) {
report_error_to_gui();
/* At this point, the current database file was
* written, but there was an error creating the
* backup file. Should we ask the user whether
* to proceed with overwriting the original, or
* should we just tell them where the temporary
* file was written and return? */
return;
}
rename("<original name>.tmp", "<original name>");
if (error) {
report_error_to_gui();
/* We should tell the user that the current database
* was saved to the temporary file, so they know where
* to find it. */
return;
}
save_timestamp_file();
if (error)
report_error_to_gui();
I would appreciate any comments you have.
thanks,
dave
--
Gnucash Developer's List
To unsubscribe send empty email to: [EMAIL PROTECTED]