Siegfried Gevatter has proposed merging lp:~zeitgeist/zeitgeist/dbfails into 
lp:zeitgeist.

Requested reviews:
  Zeitgeist Framework Team (zeitgeist)
Related bugs:
  Bug #743857 in Zeitgeist Framework: "zeitgeist-daemon crashed with 
DatabaseError in execute(): database disk image is malformed"
  https://bugs.launchpad.net/zeitgeist/+bug/743857

For more details, see:
https://code.launchpad.net/~zeitgeist/zeitgeist/dbfails/+merge/87195
-- 
https://code.launchpad.net/~zeitgeist/zeitgeist/dbfails/+merge/87195
Your team Zeitgeist Framework Team is requested to review the proposed merge of 
lp:~zeitgeist/zeitgeist/dbfails into lp:zeitgeist.
=== modified file 'doc/zeitgeist-daemon.1'
--- doc/zeitgeist-daemon.1	2011-11-01 19:38:11 +0000
+++ doc/zeitgeist-daemon.1	2011-12-31 15:59:23 +0000
@@ -81,6 +81,12 @@
 .TP
 .B 10
 There is already a running Zeitgeist instance.
+.TP
+.B 21
+Could not access the database file.
+.TP
+.B 22
+The database file is locked.
 
 .SH SEE ALSO
 \fBzeitgeist-datahub\fR, \fBgnome-activity-journal\fR

=== modified file 'src/errors.vala'
--- src/errors.vala	2011-10-20 13:32:51 +0000
+++ src/errors.vala	2011-12-31 15:59:23 +0000
@@ -23,10 +23,14 @@
     [DBus (name = "org.gnome.zeitgeist.EngineError")]
     public errordomain EngineError
     {
+        BACKUP_FAILED,
+        DATABASE_BUSY,
+        DATABASE_CANTOPEN,
+        DATABASE_CORRUPT,
         DATABASE_ERROR,
+        DATABASE_RETIRE_FAILED,
         INVALID_ARGUMENT,
         INVALID_KEY,
-        BACKUP_FAILED,
     }
 
     // vala doesn't include proper headers, this fixes it

=== modified file 'src/sql-schema.vala'
--- src/sql-schema.vala	2011-10-31 15:28:09 +0000
+++ src/sql-schema.vala	2011-12-31 15:59:23 +0000
@@ -413,8 +413,8 @@
         }
 
         /**
-         * Execute the given SQL. If the query doesn't succeed, log a
-         * critical warning (potentially aborting the program).
+         * Execute the given SQL. If the query doesn't succeed, throw
+         * an error.
          *
          * @param database the database on which to run the query
          * @param sql the SQL query to run
@@ -425,10 +425,17 @@
             int rc = database.exec (sql);
             if (rc != Sqlite.OK)
             {
-                const string fmt_str = "Can't create database: %d, %s\n\n" +
-                    "Unable to execute SQL:\n%s";
-                var err_msg = fmt_str.printf (rc, database.errmsg (), sql);
-                throw new EngineError.DATABASE_ERROR (err_msg);
+                if (rc == Sqlite.CORRUPT)
+                {
+                    throw new EngineError.DATABASE_CORRUPT (database.errmsg ());
+                }
+                else
+                {
+                    const string fmt_str = "Can't create database: %d, %s\n\n" +
+                        "Unable to execute SQL:\n%s";
+                    var err_msg = fmt_str.printf (rc, database.errmsg (), sql);
+                    throw new EngineError.DATABASE_ERROR (err_msg);
+                }
             }
         }
 

=== modified file 'src/sql.vala'
--- src/sql.vala	2011-12-28 23:36:27 +0000
+++ src/sql.vala	2011-12-31 15:59:23 +0000
@@ -67,12 +67,7 @@
 
         public ZeitgeistDatabase () throws EngineError
         {
-            int rc = Sqlite.Database.open_v2 (
-                Utils.get_database_file_path (),
-                out database);
-            assert_query_success (rc, "Can't open database");
-
-            DatabaseSchema.ensure_schema (database);
+            open_database (true);
 
             prepare_queries ();
 
@@ -81,6 +76,74 @@
             database.update_hook (update_callback);
         }
 
+        private void open_database (bool retry)
+            throws EngineError
+        {
+            int rc = Sqlite.Database.open_v2 (
+                Utils.get_database_file_path (),
+                out database);
+            
+            if (rc == Sqlite.OK)
+            {
+                try
+                {
+                    // Error (like a malformed database) may not be exposed
+                    // until we try to operate on the database.
+                    DatabaseSchema.ensure_schema (database);
+                }
+                catch (EngineError err)
+                {
+                    if (err is EngineError.DATABASE_CORRUPT && retry)
+                        rc = Sqlite.CORRUPT;
+                    else if (err is EngineError.DATABASE_CANTOPEN)
+                        rc = Sqlite.CANTOPEN;
+                    else if (err is EngineError.DATABASE_BUSY)
+                        rc = Sqlite.BUSY;
+                    else
+                        throw err;
+                }
+            }
+            
+            if (rc != Sqlite.OK)
+            {
+                if (rc == Sqlite.CORRUPT && retry)
+                {
+                    // The database disk image is malformed
+                    warning ("It looks like your database is corrupt. " +
+                        "It will be renamed and a new one will be created.");
+                    try
+                    {
+                        Utils.retire_database ();
+                    }
+                    catch (Error err)
+                    {
+                        string message =
+                            "Could not rename database: %s".printf (
+                                err.message);
+                        throw new EngineError.DATABASE_RETIRE_FAILED (message);
+                    }
+                    open_database (false);
+                }
+                else if (rc == Sqlite.PERM || rc == Sqlite.CANTOPEN)
+                {
+                    // Access permission denied / Unable to open database file
+                    throw new EngineError.DATABASE_CANTOPEN (
+                        database.errmsg ());
+                }
+                else if (rc == Sqlite.BUSY)
+                {
+                    // The database file is locked
+                    throw new EngineError.DATABASE_BUSY (database.errmsg ());
+                }
+                else
+                {
+                    string message = "Can't open database: %d, %s".printf(rc,
+                        database.errmsg ());
+                    throw new EngineError.DATABASE_ERROR (message);
+                }
+            }
+        }
+
         public uint32 get_last_id () throws EngineError
         {
             int last_id = -1;

=== modified file 'src/utils.vala'
--- src/utils.vala	2011-10-31 15:28:09 +0000
+++ src/utils.vala	2011-12-31 15:59:23 +0000
@@ -31,7 +31,8 @@
         private static string DATABASE_FILE_BACKUP_PATH;
         private static string LOCAL_EXTENSIONS_PATH;
 
-        public const string ZEITGEIST_DATA_FOLDER = "zeitgeist";
+        public const string DATA_FOLDER = "zeitgeist";
+        public const string DATABASE_BASENAME = "activity.sqlite";
         public const string USER_EXTENSION_PATH = "";
 
         // D-Bus
@@ -48,7 +49,7 @@
 
             DATA_PATH = Environment.get_variable ("ZEITGEIST_DATA_PATH") ??
                 Path.build_filename (Environment.get_user_data_dir (),
-                    ZEITGEIST_DATA_FOLDER);
+                    DATA_FOLDER);
 
             if (!FileUtils.test (DATA_PATH, FileTest.IS_DIR))
             {
@@ -66,7 +67,7 @@
 
             DATABASE_FILE_PATH =
                 Environment.get_variable ("ZEITGEIST_DATABASE_PATH") ??
-                Path.build_filename (get_data_path (), "activity.sqlite");
+                Path.build_filename (get_data_path (), DATABASE_BASENAME);
 
             debug ("DATABASE_FILE_PATH = %s", DATABASE_FILE_PATH);
 
@@ -80,13 +81,20 @@
 
             DATABASE_FILE_BACKUP_PATH =
                 Environment.get_variable ("ZEITGEIST_DATABASE_BACKUP_PATH") ??
-                Path.build_filename (get_data_path (), "activity.sqlite.bck");
+                Path.build_filename (get_data_path (),
+                    DATABASE_BASENAME + ".bck");
 
             debug ("DATABASE_FILE_BACKUP_PATH = %s", DATABASE_FILE_BACKUP_PATH);
 
             return DATABASE_FILE_BACKUP_PATH;
         }
 
+        public string get_database_file_retire_name ()
+        {
+            return DATABASE_BASENAME + ".%s.bck".printf (
+                new DateTime.now_local ().format ("%Y%m%d-%H%M%S"));
+        }
+
         public unowned string get_local_extensions_path ()
         {
             if (LOCAL_EXTENSIONS_PATH != null) return LOCAL_EXTENSIONS_PATH;
@@ -113,6 +121,12 @@
 
             original.copy (destination, FileCopyFlags.OVERWRITE, null, null);
         }
+
+        public void retire_database () throws Error
+        {
+            File dbfile = File.new_for_path (get_database_file_path ());
+            dbfile.set_display_name (get_database_file_retire_name ());
+        }
     }
 }
 

=== modified file 'src/zeitgeist-daemon.vala'
--- src/zeitgeist-daemon.vala	2011-10-20 14:20:17 +0000
+++ src/zeitgeist-daemon.vala	2011-12-31 15:59:23 +0000
@@ -370,8 +370,25 @@
             }
             catch (Error err)
             {
-                critical ("%s", err.message);
-                return;
+                if (err is EngineError.DATABASE_CANTOPEN)
+                {
+                    warning ("Could not access the database file.\n" +
+                        "Please check the permissions of file %s.",
+                        Utils.get_database_file_path ());
+                    Posix.exit(21);
+                }
+                else if (err is EngineError.DATABASE_BUSY)
+                {
+                    warning ("It looks like another Zeitgeist instance " +
+                        "is already running (the database is locked). " +
+                        "If you want to start a new instance, use --replace.");
+                    Posix.exit(22);
+                }
+                else
+                {
+                    critical ("%s", err.message);
+                    return;
+                }
             }
 
             uint owner_id = Bus.own_name_on_connection (connection,
@@ -442,6 +459,7 @@
             catch (Error err)
             {
                 warning ("%s", err.message);
+                return 1;
             }
 
             return 0;

_______________________________________________
Mailing list: https://launchpad.net/~zeitgeist
Post to     : zeitgeist@lists.launchpad.net
Unsubscribe : https://launchpad.net/~zeitgeist
More help   : https://help.launchpad.net/ListHelp

Reply via email to