zeitgeist team mailing list archive
-
zeitgeist team
-
Mailing list archive
-
Message #04569
[Branch ~zeitgeist/zeitgeist/bluebird] Rev 372: Automatically recover from corrupt database and be more clear
Merge authors:
Siegfried Gevatter (rainct)
------------------------------------------------------------
revno: 372 [merge]
committer: Siegfried-Angel Gevatter Pujals <siegfried@xxxxxxxxxxxx>
branch nick: zeitgeist
timestamp: Wed 2012-01-25 14:24:34 +0100
message:
Automatically recover from corrupt database and be more clear
on some other errors.
modified:
doc/zeitgeist-daemon.1
src/errors.vala
src/sql-schema.vala
src/sql.vala
src/utils.vala
src/zeitgeist-daemon.vala
--
lp:zeitgeist
https://code.launchpad.net/~zeitgeist/zeitgeist/bluebird
Your team Zeitgeist Framework Team is subscribed to branch lp:zeitgeist.
To unsubscribe from this branch go to https://code.launchpad.net/~zeitgeist/zeitgeist/bluebird/+edit-subscription
=== modified file 'doc/zeitgeist-daemon.1'
--- doc/zeitgeist-daemon.1 2012-01-02 19:31:15 +0000
+++ doc/zeitgeist-daemon.1 2012-01-25 13:24:34 +0000
@@ -87,6 +87,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 2012-01-25 10:36:27 +0000
@@ -23,10 +23,15 @@
[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,
+ EXISTING_INSTANCE,
}
// vala doesn't include proper headers, this fixes it
=== modified file 'src/sql-schema.vala'
--- src/sql-schema.vala 2012-01-25 12:28:24 +0000
+++ src/sql-schema.vala 2012-01-25 13:24:34 +0000
@@ -417,8 +417,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
@@ -429,10 +429,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 2012-01-02 19:30:51 +0000
+++ src/sql.vala 2012-01-25 13:24:34 +0000
@@ -67,13 +67,7 @@
public ZeitgeistDatabase () throws EngineError
{
- message ("Opening DB from %s", Utils.get_database_file_path ());
- 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 ();
@@ -82,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:57:15 +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 2012-01-02 19:30:51 +0000
+++ src/zeitgeist-daemon.vala 2012-01-25 13:24:34 +0000
@@ -329,6 +329,7 @@
}
static void run ()
+ throws Error
{
DBusConnection connection;
bool name_owned;
@@ -342,8 +343,7 @@
}
catch (IOError err)
{
- critical ("%s", err.message);
- return;
+ throw err;
}
if (name_owned)
{
@@ -353,9 +353,10 @@
}
else
{
- critical ("An existing instance was found. Please use " +
+ warning ("An existing instance was found. Please use " +
"--replace to stop it and start a new instance.");
- Posix.exit (10);
+ throw new EngineError.EXISTING_INSTANCE (
+ "Zeitgeist is running already.");
}
}
@@ -370,8 +371,19 @@
}
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 ());
+ }
+ 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.");
+ }
+ throw err;
}
uint owner_id = Bus.own_name_on_connection (connection,
@@ -474,7 +486,15 @@
}
catch (Error err)
{
+ if (err is EngineError.EXISTING_INSTANCE)
+ return 10;
+ if (err is EngineError.DATABASE_CANTOPEN)
+ return 21;
+ if (err is EngineError.DATABASE_BUSY)
+ return 22;
+
warning ("%s", err.message);
+ return 1;
}
return 0;