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]


Reply via email to