Database threading + WorkerThread, v0
- From: Ruben Vermeersch <ruben Lambda1 be>
- To: f-spot-list gnome org
- Subject: Database threading + WorkerThread, v0
- Date: Fri, 07 Apr 2006 19:35:02 +0200
Hi all,
I've just completed a rather large patch, which rewrites the database
layer almost completely and adds a background thread to do long running
& heavy tasks.
I started this because I was annoyed with the way XMP metadata is
written to files, it blocks the UI. Therefor I added a background
thread, which can be used to do all sorts of background tasks (I'm
thinking of stuff like automatically syncing tags with flickr).
In the process, I had to make the database code thread-aware, as sqlite
doesn't handle threads very well. With the help of Abock, this has been
implemented, largely based on banshee's database code (which has been
known to work ;-)).
Anyway, I'm going to post this in the bugzilla in a couple of days, but
I'd like to ask for some feedback/reviews here first.
Here's how to test it:
* Start f-spot without the patch, enable XMP metadata writing, add a
tag to 70+ pictures. You'll notice the UI hangs quite a long time (with
loads of console output).
* Now try the same with the patch applied. Tagging should be a lot
faster. Metadata is written in the background. As a side-effect, f-spot
is now threading-capable, so we can think about doing more things
outside of the GTK mainloop (thus less blocking of the UI).
Any feedback would be greatly appreciated!
Kind regards,
Ruben
--
Ruben Vermeersch (rubenv)
http://www.Lambda1.be/
WorkerThread + Database threading.
ChangeLog | 21 +++
src/Core.cs | 9 +
src/Db.cs | 333 +++++++++++++++++++++++++++++++++++++++++-----------
src/ImportStore.cs | 53 +-------
src/MainWindow.cs | 109 +++++++----------
src/Makefile.am | 1
src/MetaStore.cs | 69 ++--------
src/PhotoStore.cs | 255 ++++++++++++---------------------------
src/TagStore.cs | 54 ++------
src/Updater.cs | 40 +-----
src/WorkerThread.cs | 183 ++++++++++++++++++++++++++++
11 files changed, 662 insertions(+), 465 deletions(-)
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/ChangeLog f-spot/ChangeLog
--- f-spot-clean/ChangeLog 2006-03-25 07:51:24.000000000 +0100
+++ f-spot/ChangeLog 2006-04-07 19:12:36.000000000 +0200
@@ -1,3 +1,24 @@
+2006-04-07 Ruben Vermeersch <ruben Lambda1 be>
+
+ * src/Core.cs: Integrate WorkerThread.
+
+ * src/Db.cs: Rewrite Db to make the whole thing threaded. Based on
+ Aaron Bockover's QueuedSQLiteDatabase used in banshee (with
+ permission).
+
+ * src/MainWindow.cs: Make Metadata writing a WorkerThread task,
+ accidental formatting cleanup.
+
+ * src/Makefile.am: Add WorkerThread.cs
+
+ * src/ImportStore.cs
+ * src/MetaStore.cs
+ * src/PhotoStore.cs
+ * src/TagStore.cs
+ * src/Updater.cs: Adapt to new Db API.
+
+ * src/WorkerThread.cs: New worker thread system.
+
2006-03-25 Larry Ewing <lewing novell com>
* icons/Makefile.am (noinst_DATA): remove f-spot-find and
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/Core.cs f-spot/src/Core.cs
--- f-spot-clean/src/Core.cs 2006-03-23 21:11:26.000000000 +0100
+++ f-spot/src/Core.cs 2006-04-07 11:56:12.000000000 +0200
@@ -22,9 +22,14 @@ namespace FSpot {
{
MainWindow organizer;
private static Db db;
+ private static WorkerThread worker;
static DBus.Connection connection;
System.Collections.ArrayList toplevels;
+ public static WorkerThread Worker {
+ get { return worker; }
+ }
+
public Core ()
{
toplevels = new System.Collections.ArrayList ();
@@ -106,6 +111,9 @@ namespace FSpot {
public override void Organize ()
{
MainWindow.Window.Present ();
+
+ worker = new WorkerThread(db);
+ GLib.Idle.Add (new GLib.IdleHandler (worker.Install));
}
public override void View (string list)
@@ -227,6 +235,7 @@ namespace FSpot {
public override void Shutdown ()
{
+ worker.Shutdown();
System.Environment.Exit (0);
}
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/Db.cs f-spot/src/Db.cs
--- f-spot-clean/src/Db.cs 2006-03-09 06:20:46.000000000 +0100
+++ f-spot/src/Db.cs 2006-04-07 18:40:39.000000000 +0200
@@ -1,5 +1,6 @@
using Mono.Data.SqliteClient;
using System.Collections;
+using System.Threading;
using System.IO;
using System;
@@ -126,20 +127,20 @@ public abstract class DbStore {
// Sqlite stuff.
- SqliteConnection connection;
- protected SqliteConnection Connection {
+ Db database;
+ protected Db Database {
get {
- return connection;
+ return database;
}
}
// Constructor.
- public DbStore (SqliteConnection connection,
+ public DbStore (Db database,
bool cache_is_immortal)
{
- this.connection = connection;
+ this.database = database;
this.cache_is_immortal = cache_is_immortal;
item_cache = new Hashtable ();
@@ -163,27 +164,15 @@ public abstract class DbStore {
}
public void BeginTransaction () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = "BEGIN TRANSACTION";
- command.ExecuteScalar ();
- command.Dispose ();
+ Database.BeginTransaction ();
}
public void CommitTransaction () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = "COMMIT TRANSACTION";
- command.ExecuteScalar ();
- command.Dispose ();
+ Database.CommitTransaction ();
}
public void RollbackTransaction () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = "ROLLBACK";
- command.ExecuteScalar ();
- command.Dispose ();
+ Database.RollbackTransaction ();
}
}
@@ -191,13 +180,23 @@ public abstract class DbStore {
// The Database puts the stores together.
-public class Db : IDisposable {
+public class Db : IDisposable
+{
+ private ArrayList command_queue = new ArrayList();
+ private ArrayList non_transaction_command_queue = new ArrayList();
+ private SqliteConnection connection;
+ private Thread queue_thread;
+ private bool dispose_requested = false;
+ private bool processing_queue = false;
+ private bool empty;
+
+ private Thread current_transaction = null;
TagStore tag_store;
PhotoStore photo_store;
ImportStore import_store;
MetaStore meta_store;
- bool empty;
+ WorkerThreadStore jobs_store;
public TagStore Tags {
get { return tag_store; }
@@ -215,45 +214,80 @@ public class Db : IDisposable {
get { return meta_store; }
}
- // This affects how often the database writes data back to disk, and
- // therefore how likely corruption is in the event of power loss.
- public bool Sync {
- set {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = sqlite_connection;
- command.CommandText = "PRAGMA synchronous = " + (value ? "ON" : "OFF");
- command.ExecuteScalar ();
- command.Dispose ();
- }
+ public WorkerThreadStore Jobs {
+ get { return jobs_store; }
}
- public void BeginTransaction () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = sqlite_connection;
- command.CommandText = "BEGIN TRANSACTION";
- command.ExecuteScalar ();
- command.Dispose ();
- }
-
- public void CommitTransaction () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = sqlite_connection;
- command.CommandText = "COMMIT TRANSACTION";
- command.ExecuteScalar ();
- command.Dispose ();
+ public void Dispose()
+ {
+ dispose_requested = true;
+ while(processing_queue);
}
-
- public void RollbackTransaction () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = sqlite_connection;
- command.CommandText = "ROLLBACK";
- command.ExecuteScalar ();
- command.Dispose ();
+
+ private void QueueCommand(QueuedSqliteCommand command)
+ {
+ if (current_transaction != null && current_transaction != Thread.CurrentThread) {
+ lock(non_transaction_command_queue.SyncRoot) {
+ non_transaction_command_queue.Add(command);
+ }
+ } else {
+ lock(command_queue.SyncRoot) {
+ command_queue.Add(command);
+ }
+ }
}
- SqliteConnection sqlite_connection;
- public SqliteConnection Connection {
- get { return sqlite_connection; }
+ /*
+ * Performs query and returns the selected data (use for SELECT)
+ */
+ public SqliteDataReader Query(object query)
+ {
+ QueuedSqliteCommand command = new QueuedSqliteCommand(connection,
+ query.ToString(), DbCommandType.Reader);
+ QueueCommand(command);
+ return command.WaitForResult() as SqliteDataReader;
+ }
+
+ /*
+ * Performs query and returns a single result
+ */
+ public object QuerySingle(object query)
+ {
+ QueuedSqliteCommand command = new QueuedSqliteCommand(connection,
+ query.ToString(), DbCommandType.Scalar);
+ QueueCommand(command);
+ return command.WaitForResult();
+ }
+
+ /*
+ * Performs query and returns the insert ID (if any)
+ */
+ public uint Execute(object query)
+ {
+ QueuedSqliteCommand command = new QueuedSqliteCommand(connection,
+ query.ToString(), DbCommandType.Execute);
+ QueueCommand(command);
+ command.WaitForResult();
+ return command.InsertID;
+ }
+
+ /*
+ * Performs a query and doesn't wait for a result
+ */
+ public void ExecuteNoWait(object query)
+ {
+ QueuedSqliteCommand command = new QueuedSqliteCommand(connection,
+ query.ToString(), DbCommandType.ExecuteNoWait);
+ QueueCommand(command);
+ }
+
+ public bool TableExists(string table)
+ {
+ return Convert.ToInt32(QuerySingle(String.Format(@"
+ SELECT COUNT(*)
+ FROM sqlite_master
+ WHERE Type='table' AND Name='{0}'",
+ table))) > 0;
}
private static int GetFileVersion (string path)
@@ -284,7 +318,7 @@ public class Db : IDisposable {
throw new Exception (path + ": File not found");
if (! new_db) {
- int version = Db.GetFileVersion (path);
+ int version = GetFileVersion (path);
// FIXME: we should probably display and error dialog if the version
// is anything other than the one we were built with, but for now at least
// use the right version.
@@ -298,20 +332,25 @@ public class Db : IDisposable {
version_string += ",encoding=UTF-8";
}
- sqlite_connection = new SqliteConnection ();
- sqlite_connection.ConnectionString = "URI=file:" + path + version_string;
+ connection = new SqliteConnection ();
+ connection.ConnectionString = "URI=file:" + path + version_string;
- sqlite_connection.Open ();
+ connection.Open ();
+
+ queue_thread = new Thread(ProcessQueue);
+ queue_thread.IsBackground = true;
+ queue_thread.Start();
// Load or create the meta table
- meta_store = new MetaStore (sqlite_connection, new_db);
+ meta_store = new MetaStore (this, new_db);
// Update the database schema if necessary
FSpot.Database.Updater.Run (this);
- tag_store = new TagStore (sqlite_connection, new_db);
- import_store = new ImportStore (sqlite_connection, new_db);
- photo_store = new PhotoStore (sqlite_connection, new_db, tag_store);
+ tag_store = new TagStore (this, new_db);
+ import_store = new ImportStore (this, new_db);
+ photo_store = new PhotoStore (this, new_db, tag_store);
+ jobs_store = new WorkerThreadStore (this, new_db);
empty = new_db;
}
@@ -322,9 +361,173 @@ public class Db : IDisposable {
}
}
- public void Dispose () {}
+ private void ProcessQueue()
+ {
+ processing_queue = true;
+ bool in_dispose_transaction = false;
+
+ int sleep_time = 10;
+ bool queries = false;
+
+ while(true) {
+ queries = false;
+ while(command_queue.Count > 0) {
+ queries = true;
+ if(dispose_requested && current_transaction == null && !in_dispose_transaction) {
+ (new SqliteCommand("BEGIN", connection)).ExecuteNonQuery();
+ in_dispose_transaction = true;
+ }
+
+ QueuedSqliteCommand command = command_queue[0] as QueuedSqliteCommand;
+ command.Execute();
+
+ // TODO: optimize (RemoveAt?)
+ lock(command_queue.SyncRoot) {
+ command_queue.Remove(command);
+ }
+ }
+
+ if(dispose_requested && current_transaction == null) {
+ if(in_dispose_transaction) {
+ (new SqliteCommand("COMMIT", connection)).ExecuteNonQuery();
+ }
+ connection.Close();
+ processing_queue = false;
+ return;
+ }
+
+ if (!queries && sleep_time < 20) {
+ sleep_time++;
+ } else if (queries && sleep_time > 1) {
+ sleep_time--;
+ }
+
+ Thread.Sleep(sleep_time);
+ }
+ }
+
+ // This affects how often the database writes data back to disk, and
+ // therefore how likely corruption is in the event of power loss.
+ public bool Sync {
+ set {
+ Execute("PRAGMA synchronous = " + (value ? "ON" : "OFF"));
+ }
+ }
+
+ public void BeginTransaction() {
+ while (current_transaction != null);
+ current_transaction = Thread.CurrentThread;
+ Execute("BEGIN TRANSACTION");
+ }
+
+ public void CommitTransaction () {
+ if (current_transaction != Thread.CurrentThread) {
+ throw new ApplicationException("Can't commit when not in a transaction!");
+ }
+ Execute("COMMIT TRANSACTION");
+ current_transaction = null;
+ PushNonTransactionQueue();
+ }
+
+ public void RollbackTransaction () {
+ if (current_transaction != Thread.CurrentThread) {
+ throw new ApplicationException("Can't rollback when not in a transaction!");
+ }
+ Execute("ROLLBACK");
+ current_transaction = null;
+ PushNonTransactionQueue();
+ }
+
+ // Pull out everything that was sent in during the transaction
+ private void PushNonTransactionQueue() {
+ while (non_transaction_command_queue.Count > 0) {
+ // FIXME: better check we are really really sure this can never
+ // cause deadlocks!
+ lock(command_queue.SyncRoot) {
+ lock (non_transaction_command_queue.SyncRoot) {
+ QueuedSqliteCommand command = non_transaction_command_queue[0] as QueuedSqliteCommand;
+ command_queue.Add(command);
+ non_transaction_command_queue.Remove(command);
+ }
+ }
+ }
+ }
+}
+
+internal enum DbCommandType {
+ Reader,
+ Scalar,
+ Execute,
+ ExecuteNoWait
}
+internal class QueuedSqliteCommand : SqliteCommand
+{
+ private DbCommandType command_type;
+ private object result;
+ private uint insert_id;
+ private Exception execution_exception;
+ private bool finished = false;
+
+ public QueuedSqliteCommand(SqliteConnection connection, string command, DbCommandType commandType)
+ : base(command, connection)
+ {
+ this.command_type = commandType;
+ }
+
+ public void Execute()
+ {
+ if(result != null) {
+ throw new ApplicationException("Command has alread been executed");
+ }
+
+ try {
+ switch(command_type) {
+ case DbCommandType.Reader:
+ result = ExecuteReader();
+ break;
+ case DbCommandType.Scalar:
+ result = ExecuteScalar();
+ break;
+ case DbCommandType.Execute:
+ case DbCommandType.ExecuteNoWait:
+ default:
+ result = ExecuteNonQuery();
+ insert_id = (uint) LastInsertRowID();
+ break;
+ }
+ } catch(Exception e) {
+ execution_exception = e;
+
+ // Throw exception anyway, else it will go by unnoticed.
+ if (command_type == DbCommandType.ExecuteNoWait) {
+ throw e;
+ }
+ }
+
+ finished = true;
+ }
+
+ public object WaitForResult()
+ {
+ while(!finished);
+
+ if(execution_exception != null) {
+ throw execution_exception;
+ }
+
+ return result;
+ }
+
+ public object Result {
+ get { return result; }
+ internal set { result = value; }
+ }
+
+ public uint InsertID {
+ get { return insert_id; }
+ }
+}
public class DbUtils {
public static DateTime DateTimeFromUnixTime (long unix_time)
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/ImportStore.cs f-spot/src/ImportStore.cs
--- f-spot-clean/src/ImportStore.cs 2006-01-22 23:43:53.000000000 +0100
+++ f-spot/src/ImportStore.cs 2006-04-07 18:41:39.000000000 +0200
@@ -30,38 +30,25 @@ public class ImportStore : DbStore {
// Constructor
- public ImportStore (SqliteConnection connection, bool is_new)
- : base (connection, false)
+ public ImportStore (Db database, bool is_new)
+ : base (database, false)
{
- if (! is_new)
+ bool exists = database.TableExists("imports");
+ if (!is_new || exists)
return;
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText =
+ Database.QuerySingle(
"CREATE TABLE imports ( " +
" id INTEGER PRIMARY KEY NOT NULL, " +
" time INTEGER " +
- ")";
-
- command.ExecuteNonQuery ();
- command.Dispose ();
+ ")");
}
public Import Create (DateTime time_in_utc)
{
long unix_time = DbUtils.UnixTimeFromDateTime (time_in_utc);
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("INSERT INTO import (time) VALUES ({0}) ",
- unix_time);
- command.ExecuteScalar ();
- command.Dispose ();
-
- uint id = (uint) Connection.LastInsertRowId;
+ uint id = Database.Execute(String.Format ("INSERT INTO import (time) VALUES ({0}) ", unix_time));
Import import = new Import (id, unix_time);
AddToCache (import);
@@ -74,19 +61,14 @@ public class ImportStore : DbStore {
if (import != null)
return import;
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("SELECT time FROM imports WHERE id = {0}", id);
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = String.Format ("SELECT time FROM imports WHERE id = {0}", id);
+ SqliteDataReader reader = Database.Query(query);
if (reader.Read ()) {
import = new Import (id, Convert.ToUInt32 (reader [0]));
AddToCache (import);
}
- command.Dispose ();
-
return import;
}
@@ -94,13 +76,8 @@ public class ImportStore : DbStore {
{
RemoveFromCache (item);
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("DELETE FROM imports WHERE id = {0}", item.Id);
- command.ExecuteNonQuery ();
-
- command.Dispose ();
+ string query = String.Format ("DELETE FROM imports WHERE id = {0}", item.Id);
+ Database.ExecuteNoWait (query);
}
public override void Commit (DbItem item)
@@ -113,11 +90,7 @@ public class ImportStore : DbStore {
{
ArrayList list = new ArrayList ();
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = "SELECT id, time FROM imports";
- SqliteDataReader reader = command.ExecuteReader ();
+ SqliteDataReader reader = Database.Query ("SELECT id, time FROM imports");
while (reader.Read ()) {
// Note that we get both time and ID from the database, but we have to see
@@ -135,8 +108,6 @@ public class ImportStore : DbStore {
list.Add (import);
}
- command.Dispose ();
-
list.Sort (new ImportComparerByDate ());
return list;
}
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/MainWindow.cs f-spot/src/MainWindow.cs
--- f-spot-clean/src/MainWindow.cs 2006-03-23 01:39:28.000000000 +0100
+++ f-spot/src/MainWindow.cs 2006-04-07 18:08:13.000000000 +0200
@@ -18,7 +18,7 @@ using LibGPhoto2;
public class MainWindow {
- public static MainWindow Toplevel;
+ public static MainWindow Toplevel;
Db db;
@@ -442,15 +442,8 @@ public class MainWindow {
private void HandleDbItemsChanged (object sender, DbItemEventArgs args)
{
- foreach (DbItem item in args.Items) {
- Photo p = item as Photo;
- if (p == null)
- continue;
-
- if (write_metadata)
- p.WriteMetadataToImage ();
-
- }
+ if (write_metadata)
+ Core.Worker.ScheduleMetaDataWrites(args.Items);
if (args is TimeChangedEventArgs)
query.RequestReload ();
@@ -2638,59 +2631,59 @@ public class MainWindow {
return;
}
- // Add any new tags to the selected photos
- Category default_category = null;
- Tag [] selection = tag_selection_widget.TagHighlight;
- if (selection.Length > 0) {
- if (selection [0] is Category)
- default_category = (Category) selection [0];
- else
- default_category = selection [0].Category;
- }
+ // Add any new tags to the selected photos
+ Category default_category = null;
+ Tag [] selection = tag_selection_widget.TagHighlight;
+ if (selection.Length > 0) {
+ if (selection [0] is Category)
+ default_category = (Category) selection [0];
+ else
+ default_category = selection [0].Category;
+ }
db.BeginTransaction ();
- for (int i = 0; i < tagnames.Length; i ++) {
- if (tagnames [i].Length == 0)
- continue;
-
- Tag t = db.Tags.GetTagByName (tagnames [i]);
-
- if (t == null) {
- t = db.Tags.CreateCategory (default_category, tagnames [i]) as Tag;
- db.Tags.Commit (t);
- }
-
- // Correct for capitalization differences
- tagnames [i] = t.Name;
-
- Tag [] tags = new Tag [1];
- tags [0] = t;
-
- foreach (int num in selected_photos)
- AddTagExtended (num, tags);
- }
+ for (int i = 0; i < tagnames.Length; i ++) {
+ if (tagnames [i].Length == 0)
+ continue;
+
+ Tag t = db.Tags.GetTagByName (tagnames [i]);
+
+ if (t == null) {
+ t = db.Tags.CreateCategory (default_category, tagnames [i]) as Tag;
+ db.Tags.Commit (t);
+ }
+
+ // Correct for capitalization differences
+ tagnames [i] = t.Name;
+
+ Tag [] tags = new Tag [1];
+ tags [0] = t;
+
+ foreach (int num in selected_photos)
+ AddTagExtended (num, tags);
+ }
db.CommitTransaction ();
-
- // Remove any removed tags from the selected photos
- foreach (string tagname in selected_photos_tagnames) {
- if (! IsTagInList (tagnames, tagname)) {
+
+ // Remove any removed tags from the selected photos
+ foreach (string tagname in selected_photos_tagnames) {
+ if (! IsTagInList (tagnames, tagname)) {
- Tag tag = db.Tags.GetTagByName (tagname);
+ Tag tag = db.Tags.GetTagByName (tagname);
- foreach (int num in selected_photos) {
- query.Photos [num].RemoveTag (tag);
- query.Commit (num);
- }
- }
- }
-
- if (view_mode == ModeType.IconView) {
- icon_view.QueueDraw ();
- icon_view.GrabFocus ();
- } else {
- photo_view.QueueDraw ();
- photo_view.View.GrabFocus ();
- }
+ foreach (int num in selected_photos) {
+ query.Photos [num].RemoveTag (tag);
+ query.Commit (num);
+ }
+ }
+ }
+
+ if (view_mode == ModeType.IconView) {
+ icon_view.QueueDraw ();
+ icon_view.GrabFocus ();
+ } else {
+ photo_view.QueueDraw ();
+ photo_view.View.GrabFocus ();
+ }
}
private void HideTagbar ()
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/Makefile.am f-spot/src/Makefile.am
--- f-spot-clean/src/Makefile.am 2006-02-26 23:37:08.000000000 +0100
+++ f-spot/src/Makefile.am 2006-04-06 18:34:47.000000000 +0200
@@ -115,6 +115,7 @@ F_SPOT_CSDISTFILES = \
$(srcdir)/CameraSelectionDialog.cs \
$(srcdir)/CameraFileSelectionDialog.cs \
$(srcdir)/TagSelectionDialog.cs \
+ $(srcdir)/WorkerThread.cs \
$(srcdir)/X3fFile.cs \
$(srcdir)/XmpFile.cs \
$(srcdir)/main.cs
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/MetaStore.cs f-spot/src/MetaStore.cs
--- f-spot-clean/src/MetaStore.cs 2006-03-02 04:17:23.000000000 +0100
+++ f-spot/src/MetaStore.cs 2006-04-07 17:10:40.000000000 +0200
@@ -60,18 +60,12 @@ public class MetaStore : DbStore {
private void CreateTable ()
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText =
+ Database.Execute(
@"CREATE TABLE meta (
id INTEGER PRIMARY KEY NOT NULL,
name TEXT UNIQUE NOT NULL,
data TEXT
- )";
-
- command.ExecuteNonQuery ();
- command.Dispose ();
+ )");
}
private void CreateDefaultItems (bool is_new)
@@ -80,29 +74,19 @@ public class MetaStore : DbStore {
Create (db_version, (is_new) ? FSpot.Database.Updater.LatestVersion.ToString () : "0");
// Get the hidden tag id, if it exists
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = "SELECT id FROM tags WHERE name = 'Hidden'";
-
try {
- SqliteDataReader reader = command.ExecuteReader ();
+ SqliteDataReader reader = Database.Query("SELECT id FROM tags WHERE name = 'Hidden'");
if (reader.Read ())
Create (hidden, reader [0].ToString ());
reader.Close ();
} catch (Exception e) {}
-
- command.Dispose ();
}
private void LoadAllItems ()
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = "SELECT id, name, data FROM meta";
- SqliteDataReader reader = command.ExecuteReader ();
+ SqliteDataReader reader = Database.Query("SELECT id, name, data FROM meta");
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader [0]);
@@ -119,7 +103,6 @@ public class MetaStore : DbStore {
}
reader.Close ();
- command.Dispose ();
if (FSpotVersion.Value != FSpot.Defines.VERSION) {
FSpotVersion.Value = FSpot.Defines.VERSION;
@@ -129,16 +112,11 @@ public class MetaStore : DbStore {
private MetaItem Create (string name, string data)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("INSERT INTO meta (name, data) VALUES ('{0}', {1})",
+ string query = String.Format ("INSERT INTO meta (name, data) VALUES ('{0}', {1})",
name, (data == null) ? "NULL" : "'" + data + "'");
- MetaItem item = new MetaItem ((uint) Connection.LastInsertRowId, name, data);
-
- command.ExecuteScalar ();
- command.Dispose ();
+ uint insert_id = Database.Execute(query);
+ MetaItem item = new MetaItem (insert_id, name, data);
AddToCache (item);
EmitAdded (item);
@@ -150,13 +128,8 @@ public class MetaStore : DbStore {
{
MetaItem item = dbitem as MetaItem;
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("UPDATE meta SET data = '{1}' WHERE name = '{0}'", item.Name, item.Value);
-
- command.ExecuteNonQuery ();
- command.Dispose ();
+ string query = String.Format ("UPDATE meta SET data = '{1}' WHERE name = '{0}'", item.Name, item.Value);
+ Database.Execute(query);
EmitChanged (item);
}
@@ -170,33 +143,19 @@ public class MetaStore : DbStore {
{
RemoveFromCache (item);
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
+ string query = String.Format ("DELETE FROM meta WHERE id = {0}", item.Id);
+ Database.Execute(query);
- command.CommandText = String.Format ("DELETE FROM meta WHERE id = {0}", item.Id);
- command.ExecuteNonQuery ();
-
- command.Dispose ();
EmitRemoved (item);
}
// Constructor
- public MetaStore (SqliteConnection connection, bool is_new)
- : base (connection, true)
+ public MetaStore (Db database, bool is_new)
+ : base (database, true)
{
// Ensure the table exists
- bool exists = true;
- try {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = connection;
- command.CommandText = "UPDATE meta SET id = 1 WHERE 1 = 2";
- command.ExecuteScalar ();
- command.Dispose ();
- } catch (Exception e) {
- // Table doesn't exist, so create it
- exists = false;
- }
+ bool exists = Database.TableExists("meta");
if (is_new || !exists) {
CreateTable ();
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/PhotoStore.cs f-spot/src/PhotoStore.cs
--- f-spot-clean/src/PhotoStore.cs 2006-03-23 04:17:30.000000000 +0100
+++ f-spot/src/PhotoStore.cs 2006-04-07 18:13:31.000000000 +0200
@@ -644,19 +644,16 @@ public class PhotoStore : DbStore {
// Constructor
- public PhotoStore (SqliteConnection connection, bool is_new, TagStore tag_store)
- : base (connection, false)
+ public PhotoStore (Db database, bool is_new, TagStore tag_store)
+ : base (database, false)
{
this.tag_store = tag_store;
EnsureThumbnailDirectory ();
if (! is_new)
return;
-
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText =
+ Database.Execute(
"CREATE TABLE photos ( " +
" id INTEGER PRIMARY KEY NOT NULL, " +
" time INTEGER NOT NULL, " +
@@ -664,39 +661,20 @@ public class PhotoStore : DbStore {
" name STRING NOT NULL, " +
" description TEXT NOT NULL, " +
" default_version_id INTEGER NOT NULL " +
- ")";
-
- command.ExecuteNonQuery ();
- command.Dispose ();
-
- // FIXME: No need to do Dispose here?
-
- command = new SqliteCommand ();
- command.Connection = Connection;
+ ")");
- command.CommandText =
+ Database.Execute(
"CREATE TABLE photo_tags ( " +
" photo_id INTEGER, " +
" tag_id INTEGER " +
- ")";
-
- command.ExecuteNonQuery ();
- command.Dispose ();
-
- // FIXME: No need to do Dispose here?
-
- command = new SqliteCommand ();
- command.Connection = Connection;
+ ")");
- command.CommandText =
+ Database.Execute(
"CREATE TABLE photo_versions ( " +
" photo_id INTEGER, " +
" version_id INTEGER, " +
" name STRING " +
- ")";
-
- command.ExecuteNonQuery ();
- command.Dispose ();
+ ")");
}
@@ -710,22 +688,17 @@ public class PhotoStore : DbStore {
FSpot.ImageFile img = FSpot.ImageFile.Create (origPath);
long unix_time = DbUtils.UnixTimeFromDateTime (img.Date);
string description = img.Description != null ? img.Description.Split ('\0') [0] : "";
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("INSERT INTO photos (time, " +
- "directory_path, name, description, default_version_id) " +
- " VALUES ({0}, '{1}', '{2}', '{3}', {4})",
- unix_time,
- SqlString (System.IO.Path.GetDirectoryName (newPath)),
- SqlString (System.IO.Path.GetFileName (newPath)),
- SqlString (description),
- Photo.OriginalVersionId);
- command.ExecuteScalar ();
- command.Dispose ();
+ string query = String.Format ("INSERT INTO photos (time, " +
+ "directory_path, name, description, default_version_id) " +
+ " VALUES ({0}, '{1}', '{2}', '{3}', {4})",
+ unix_time,
+ SqlString (System.IO.Path.GetDirectoryName (newPath)),
+ SqlString (System.IO.Path.GetFileName (newPath)),
+ SqlString (description),
+ Photo.OriginalVersionId);
+ uint id = Database.Execute(query);
- uint id = (uint) Connection.LastInsertRowId;
Photo photo = new Photo (id, unix_time, newPath);
AddToCache (photo);
photo.Loaded = true;
@@ -739,43 +712,30 @@ public class PhotoStore : DbStore {
private void GetVersions (Photo photo)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("SELECT version_id, name FROM photo_versions WHERE photo_id = {0}", photo.Id);
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = String.Format ("SELECT version_id, name FROM photo_versions WHERE photo_id = {0}", photo.Id);
+ SqliteDataReader reader = Database.Query(query);
while (reader.Read ()) {
uint version_id = Convert.ToUInt32 (reader [0]);
string name = reader[1].ToString ();
photo.AddVersionUnsafely (version_id, name);
}
-
- command.Dispose ();
}
private void GetTags (Photo photo)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("SELECT tag_id FROM photo_tags WHERE photo_id = {0}", photo.Id);
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = String.Format ("SELECT tag_id FROM photo_tags WHERE photo_id = {0}", photo.Id);
+ SqliteDataReader reader = Database.Query(query);
while (reader.Read ()) {
uint tag_id = Convert.ToUInt32 (reader [0]);
Tag tag = tag_store.Get (tag_id) as Tag;
photo.AddTagUnsafely (tag);
}
-
- command.Dispose ();
}
private void GetAllVersions () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("SELECT photo_id, version_id, name " +
- "FROM photo_versions ");
-
- SqliteDataReader reader = command.ExecuteReader ();
+ SqliteDataReader reader = Database.Query("SELECT photo_id, version_id, name FROM photo_versions");
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader [0]);
@@ -810,12 +770,7 @@ public class PhotoStore : DbStore {
}
private void GetAllTags () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("SELECT photo_id, tag_id " +
- "FROM photo_tags ");
-
- SqliteDataReader reader = command.ExecuteReader ();
+ SqliteDataReader reader = Database.Query("SELECT photo_id, tag_id FROM photo_tags");
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader [0]);
@@ -840,13 +795,9 @@ public class PhotoStore : DbStore {
}
private void GetAllData () {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("SELECT photo_tags.photo_id, tag_id, version_id, name " +
- "FROM photo_tags, photo_versions " +
- "WHERE photo_tags.photo_id = photo_versions.photo_id");
-
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = "SELECT photo_tags.photo_id, tag_id, version_id, name " +
+ "FROM photo_tags, photo_versions WHERE photo_tags.photo_id = photo_versions.photo_id";
+ SqliteDataReader reader = Database.Query(query);
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader [0]);
@@ -878,14 +829,11 @@ public class PhotoStore : DbStore {
private void GetData (Photo photo)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("SELECT tag_id, version_id, name " +
- " FROM photo_tags, photo_versions " +
- " WHERE photo_tags.photo_id = photo_versions.photo_id " +
- " AND photo_tags.photo_id = {0}", photo.Id);
-
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = String.Format ("SELECT tag_id, version_id, name " +
+ " FROM photo_tags, photo_versions " +
+ " WHERE photo_tags.photo_id = photo_versions.photo_id " +
+ " AND photo_tags.photo_id = {0}", photo.Id);
+ SqliteDataReader reader = Database.Query(query);
while (reader.Read ()) {
if (reader [0] != null) {
@@ -908,17 +856,15 @@ public class PhotoStore : DbStore {
if (photo != null)
return photo;
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("SELECT time, " +
- " directory_path, " +
- " name, " +
- " description, " +
- " default_version_id " +
- " FROM photos " +
- " WHERE id = {0} ",
- id);
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = String.Format ("SELECT time, " +
+ " directory_path, " +
+ " name, " +
+ " description, " +
+ " default_version_id " +
+ " FROM photos " +
+ " WHERE id = {0} ",
+ id);
+ SqliteDataReader reader = Database.Query(query);
if (reader.Read ()) {
photo = new Photo (id,
@@ -931,8 +877,6 @@ public class PhotoStore : DbStore {
AddToCache (photo);
}
- command.Dispose ();
-
if (photo == null)
return null;
@@ -948,23 +892,20 @@ public class PhotoStore : DbStore {
// this is only used for DND
Photo photo = null;
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
string directory_path = System.IO.Path.GetDirectoryName (path);
string filename = System.IO.Path.GetFileName (path);
- command.CommandText = String.Format ("SELECT id, " +
- " time, " +
- " description, " +
- " default_version_id " +
- " FROM photos " +
- " WHERE directory_path = \"{0}\" " +
- " AND name = \"{1}\" ",
- directory_path,
- filename);
-
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = String.Format ("SELECT id, " +
+ " time, " +
+ " description, " +
+ " default_version_id " +
+ " FROM photos " +
+ " WHERE directory_path = \"{0}\" " +
+ " AND name = \"{1}\" ",
+ directory_path,
+ filename);
+ SqliteDataReader reader = Database.Query(query);
if (reader.Read ()) {
photo = new Photo (Convert.ToUInt32 (reader [0]),
@@ -977,8 +918,6 @@ public class PhotoStore : DbStore {
AddToCache (photo);
}
- command.Dispose ();
-
if (photo == null)
return null;
@@ -1019,29 +958,14 @@ public class PhotoStore : DbStore {
RemoveFromCache (items[i]);
}
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("DELETE FROM photos WHERE {0}", query_builder.ToString ());
- command.ExecuteNonQuery ();
-
- command.Dispose ();
-
- command = new SqliteCommand ();
- command.Connection = Connection;
+ string query = String.Format ("DELETE FROM photos WHERE {0}", query_builder.ToString ());
+ Database.ExecuteNoWait(query);
- command.CommandText = String.Format ("DELETE FROM photo_tags WHERE {0}", tv_query_builder.ToString ());
- command.ExecuteNonQuery ();
+ query = String.Format ("DELETE FROM photo_tags WHERE {0}", tv_query_builder.ToString ());
+ Database.ExecuteNoWait(query);
- command.Dispose ();
-
- command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("DELETE FROM photo_versions WHERE {0}", tv_query_builder.ToString ());
- command.ExecuteNonQuery ();
-
- command.Dispose ();
+ query = String.Format ("DELETE FROM photo_versions WHERE {0}", tv_query_builder.ToString ());
+ Database.ExecuteNoWait(query);
}
public override void Remove (DbItem item)
@@ -1071,45 +995,30 @@ public class PhotoStore : DbStore {
private void Update (Photo photo) {
// Update photo.
-
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("UPDATE photos SET description = '{0}', " +
- " default_version_id = {1}, " +
- " time = {2} " +
- " WHERE id = {3}",
- SqlString (photo.Description),
- photo.DefaultVersionId,
- DbUtils.UnixTimeFromDateTime (photo.Time),
- photo.Id);
- command.ExecuteNonQuery ();
- command.Dispose ();
+ string query = String.Format ("UPDATE photos SET description = '{0}', " +
+ " default_version_id = {1}, " +
+ " time = {2} " +
+ " WHERE id = {3}",
+ SqlString (photo.Description),
+ photo.DefaultVersionId,
+ DbUtils.UnixTimeFromDateTime (photo.Time),
+ photo.Id);
+ Database.ExecuteNoWait(query);
// Update tags.
-
- command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("DELETE FROM photo_tags WHERE photo_id = {0}", photo.Id);
- command.ExecuteNonQuery ();
- command.Dispose ();
+ query = String.Format ("DELETE FROM photo_tags WHERE photo_id = {0}", photo.Id);
+ Database.Execute(query);
foreach (Tag tag in photo.Tags) {
- command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("INSERT INTO photo_tags (photo_id, tag_id) " +
- " VALUES ({0}, {1})",
- photo.Id, tag.Id);
- command.ExecuteNonQuery ();
- command.Dispose ();
+ query = String.Format ("INSERT INTO photo_tags (photo_id, tag_id) " +
+ " VALUES ({0}, {1})",
+ photo.Id, tag.Id);
+ Database.ExecuteNoWait(query);
}
// Update versions.
-
- command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("DELETE FROM photo_versions WHERE photo_id = {0}", photo.Id);
- command.ExecuteNonQuery ();
- command.Dispose ();
+ query = String.Format ("DELETE FROM photo_versions WHERE photo_id = {0}", photo.Id);
+ Database.Execute(query);
foreach (uint version_id in photo.VersionIds) {
if (version_id == Photo.OriginalVersionId)
@@ -1117,13 +1026,10 @@ public class PhotoStore : DbStore {
string version_name = photo.GetVersionName (version_id);
- command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("INSERT INTO photo_versions (photo_id, version_id, name) " +
- " VALUES ({0}, {1}, '{2}')",
- photo.Id, version_id, SqlString (version_name));
- command.ExecuteNonQuery ();
- command.Dispose ();
+ query = String.Format ("INSERT INTO photo_versions (photo_id, version_id, name) " +
+ " VALUES ({0}, {1}, '{2}')",
+ photo.Id, version_id, SqlString (version_name));
+ Database.ExecuteNoWait(query);
}
}
@@ -1162,10 +1068,7 @@ public class PhotoStore : DbStore {
public Photo [] Query (string query)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = query;
- SqliteDataReader reader = command.ExecuteReader ();
+ SqliteDataReader reader = Database.Query(query);
ArrayList version_list = new ArrayList ();
ArrayList id_list = new ArrayList ();
@@ -1204,8 +1107,6 @@ public class PhotoStore : DbStore {
//Console.WriteLine ("Skipped Loading Data");
}
- command.Dispose ();
-
return id_list.ToArray (typeof (Photo)) as Photo [];
}
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/TagStore.cs f-spot/src/TagStore.cs
--- f-spot-clean/src/TagStore.cs 2006-02-17 13:11:21.000000000 +0100
+++ f-spot/src/TagStore.cs 2006-04-07 18:12:14.000000000 +0200
@@ -303,13 +303,10 @@ public class TagStore : DbStore {
// base class.
private void LoadAllTags ()
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
// Pass 1, get all the tags.
- command.CommandText = "SELECT id, name, is_category, sort_priority, icon FROM tags";
- SqliteDataReader reader = command.ExecuteReader ();
+ string query = "SELECT id, name, is_category, sort_priority, icon FROM tags";
+ SqliteDataReader reader = Database.Query(query);
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader [0]);
@@ -330,12 +327,11 @@ public class TagStore : DbStore {
}
reader.Close ();
- command.Dispose ();
// Pass 2, set the parents.
- command.CommandText = "SELECT id, category_id FROM tags";
- reader = command.ExecuteReader ();
+ query = "SELECT id, category_id FROM tags";
+ reader = Database.Query(query);
while (reader.Read ()) {
uint id = Convert.ToUInt32 (reader [0]);
@@ -354,7 +350,6 @@ public class TagStore : DbStore {
}
reader.Close ();
- command.Dispose ();
if (FSpot.Core.Database.Meta.HiddenTagId.Value != null)
hidden = LookupInCache ((uint) FSpot.Core.Database.Meta.HiddenTagId.ValueAsInt) as Tag;
@@ -363,10 +358,7 @@ public class TagStore : DbStore {
private void CreateTable ()
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText =
+ string query =
"CREATE TABLE tags ( " +
" id INTEGER PRIMARY KEY NOT NULL," +
" name TEXT UNIQUE, " +
@@ -375,9 +367,7 @@ public class TagStore : DbStore {
" sort_priority INTEGER, " +
" icon TEXT " +
")";
-
- command.ExecuteNonQuery ();
- command.Dispose ();
+ Database.Execute(query);
}
@@ -415,8 +405,8 @@ public class TagStore : DbStore {
// Constructor
- public TagStore (SqliteConnection connection, bool is_new)
- : base (connection, true)
+ public TagStore (Db database, bool is_new)
+ : base (database, true)
{
// The label for the root category is used in new and edit tag dialogs
root_category = new Category (null, 0, Mono.Posix.Catalog.GetString ("(None)"));
@@ -431,22 +421,15 @@ public class TagStore : DbStore {
private uint InsertTagIntoTable (Category parent_category, string name, bool is_category)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
uint parent_category_id = parent_category.Id;
- command.CommandText = String.Format
+ string query = String.Format
("INSERT INTO tags (name, category_id, is_category, sort_priority) " +
" VALUES ('{0}', {1}, {2}, 0) ",
SqlString (name),
parent_category_id,
is_category ? 1 : 0);
-
- command.ExecuteScalar ();
- command.Dispose ();
-
- return (uint) Connection.LastInsertRowId;
+ return Database.Execute(query);
}
public Tag CreateTag (Category category, string name)
@@ -498,14 +481,10 @@ public class TagStore : DbStore {
RemoveFromCache (item);
((Tag)item).Category = null;
-
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
- command.CommandText = String.Format ("DELETE FROM tags WHERE id = {0}", item.Id);
- command.ExecuteNonQuery ();
+ string query = String.Format ("DELETE FROM tags WHERE id = {0}", item.Id);
+ Database.ExecuteNoWait(query);
- command.Dispose ();
EmitRemoved (item);
}
@@ -525,10 +504,7 @@ public class TagStore : DbStore {
{
Tag tag = item as Tag;
- SqliteCommand command = new SqliteCommand ();
- command.Connection = Connection;
-
- command.CommandText = String.Format ("UPDATE tags SET " +
+ string query = String.Format ("UPDATE tags SET " +
" name = '{0}', " +
" category_id = {1}, " +
" is_category = {2}, " +
@@ -541,10 +517,8 @@ public class TagStore : DbStore {
tag.SortPriority,
SqlString (GetIconString (tag)),
tag.Id);
- command.ExecuteNonQuery ();
+ Database.ExecuteNoWait(query);
- command.Dispose ();
-
EmitChanged (tag);
}
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/Updater.cs f-spot/src/Updater.cs
--- f-spot-clean/src/Updater.cs 2006-02-13 08:27:36.000000000 +0100
+++ f-spot/src/Updater.cs 2006-04-07 17:35:53.000000000 +0200
@@ -19,7 +19,7 @@ namespace FSpot.Database {
// The order these are added is important as they will be run sequentially
// Update from version 0 to 1: Remove empty Other tags
- AddUpdate (delegate (SqliteConnection connection) {
+ AddUpdate (delegate (Db db) {
string other_id = SelectSingleString ("SELECT id FROM tags WHERE name = 'Other'");
if (other_id == null)
@@ -44,26 +44,26 @@ namespace FSpot.Database {
});
// Update from version 1 to 2: Restore Other tags that were removed leaving dangling child tags
- AddUpdate (delegate (SqliteConnection connection) {
+ AddUpdate (delegate (Db db) {
string tag_count = SelectSingleString ("SELECT COUNT(*) FROM tags WHERE category_id != 0 AND category_id NOT IN (SELECT id FROM tags)");
// If there are no dangling tags, then don't do anything
if (tag_count == null || System.Int32.Parse (tag_count) == 0)
return;
- ExecuteScalar ("INSERT INTO tags (name, category_id, is_category, icon) VALUES ('Other', 0, 1, 'stock_icon:f-spot-other.png')");
+ uint id = ExecuteScalar ("INSERT INTO tags (name, category_id, is_category, icon) VALUES ('Other', 0, 1, 'stock_icon:f-spot-other.png')");
ExecuteNonQuery (String.Format (
@"UPDATE tags SET category_id = {0} WHERE id IN
(SELECT id FROM tags WHERE category_id != 0 AND category_id
NOT IN (SELECT id FROM tags))",
- connection.LastInsertRowId));
+ id));
System.Console.WriteLine ("Other tag restored. Sorry about that!");
});
// Update from version 2 to 3
- //AddUpdate (delegate (SqliteConnection connection) {
+ //AddUpdate (delegate (Db db) {
// do update here
//});
}
@@ -157,24 +157,12 @@ namespace FSpot.Database {
private static void ExecuteNonQuery (string statement)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = db.Connection;
-
- command.CommandText = statement;
-
- command.ExecuteNonQuery ();
- command.Dispose ();
+ db.Execute(statement);
}
- private static void ExecuteScalar (string statement)
+ private static uint ExecuteScalar (string statement)
{
- SqliteCommand command = new SqliteCommand ();
- command.Connection = db.Connection;
-
- command.CommandText = statement;
-
- command.ExecuteScalar ();
- command.Dispose ();
+ return db.Execute(statement);
}
private static string SelectSingleString (string statement)
@@ -182,18 +170,12 @@ namespace FSpot.Database {
string result = null;
try {
- SqliteCommand command = new SqliteCommand ();
- command.Connection = db.Connection;
-
- command.CommandText = statement;
-
- SqliteDataReader reader = command.ExecuteReader ();
+ SqliteDataReader reader = db.Query(statement);
if (reader.Read ())
result = reader [0].ToString ();
reader.Close ();
- command.Dispose ();
} catch (Exception e) {}
return result;
@@ -218,7 +200,7 @@ namespace FSpot.Database {
return temp_name;
}
- private delegate void UpdateCode (SqliteConnection connection);
+ private delegate void UpdateCode (Db db);
private class Update {
public int Version;
@@ -240,7 +222,7 @@ namespace FSpot.Database {
public void Execute (Db db, MetaItem db_version)
{
- code (db.Connection);
+ code (db);
Console.WriteLine ("Updated database from version {0} to {1}",
db_version.ValueAsInt,
diff -uprN -x CVS -x Makefile -x '*.m4' -x configure -x autom4te.cache -x 'config.*' -x 'Makefile.in*' -x install-sh -x 'intltool-*' -x '*-marshal.*' -x ltmain.sh -x missing -x mkinstalldirs f-spot-clean/src/WorkerThread.cs f-spot/src/WorkerThread.cs
--- f-spot-clean/src/WorkerThread.cs 1970-01-01 01:00:00.000000000 +0100
+++ f-spot/src/WorkerThread.cs 2006-04-07 19:16:16.000000000 +0200
@@ -0,0 +1,183 @@
+/*
+ * WorkerThread - Executes background jobs.
+ *
+ * This thread runs in the background, performing long duration tasks without
+ * blocking the main UI. All jobs are stored in the jobs table, with a Command
+ * column to distinguish the kind of job. Job parameters are serialized in the
+ * Options string, it's up to the job execution method to deserialize this
+ * data. Scheduled jobs gracefully survive F-Spot restarts.
+ */
+
+using Mono.Data.SqliteClient;
+using System;
+using System.Threading;
+
+public class WorkerThread {
+ private bool looping = false;
+ private int ticks = 0;
+ private Db db;
+ private Thread worker = null;
+
+ public WorkerThread(Db db) {
+ this.db = db;
+ }
+
+ /*
+ * Installs the worker thread, this is called by the Organize() method
+ * in Core, when f-spot is idle. Will obviously be called only once.
+ */
+ public bool Install() {
+ if (!looping) {
+ looping = true;
+ worker = new Thread(new ThreadStart(Execute));
+ worker.Priority = ThreadPriority.Lowest;
+ worker.Start();
+ }
+ return false;
+ }
+
+ /*
+ * Execution tick of the worker thread.
+ *
+ * First 15 seconds are slept through, when a user has just started f-spot,
+ * he'll probably want to use it, so we wait for a while to start doing
+ * background work. Also, f-spot is preloading images during the first
+ * 10 seconds on my system.
+ */
+ public void Execute() {
+ Thread.Sleep(15000);
+ while (looping) {
+ WorkerThreadItem job = null;
+ while (looping && (job = (WorkerThreadItem)db.Jobs.GetJob()) != null) {
+ bool quick_command = false;
+ if (job.Command == "WriteMetaData") {
+ WriteMetaData(job);
+ } else {
+ Console.WriteLine("Unknown command: {0}, ignoring");
+ quick_command = true;
+ }
+ db.Jobs.Remove(job);
+
+ // Sleep a while after each command, unless it's trivial
+ if (!quick_command)
+ Thread.Sleep(10);
+ }
+
+ Thread.Sleep(10000);
+ }
+ }
+
+ public void Shutdown()
+ {
+ looping = false; // signal any running worker to stop
+ worker.Join(); // Wait for any running jobs
+ }
+
+ public void ScheduleMetaDataWrites(DbItem [] items)
+ {
+ foreach (DbItem item in items) {
+ Photo p = item as Photo;
+ if (p != null)
+ db.Jobs.Create("WriteMetaData", String.Format("{0}", p.Id));
+ }
+ }
+
+ private void WriteMetaData(WorkerThreadItem job)
+ {
+ uint id = Convert.ToUInt32(job.Options);
+ Photo p = db.Photos.Get(id) as Photo;
+ p.WriteMetadataToImage();
+ }
+}
+
+public class WorkerThreadItem : DbItem {
+ private string command;
+ public string Command {
+ get { return command; }
+ set { command = value; }
+ }
+
+ private string options;
+ public string Options {
+ get { return options; }
+ set { options = value; }
+ }
+
+ public WorkerThreadItem (uint id, string command, string options) : base (id)
+ {
+ this.command = command;
+ this.options = options;
+ }
+}
+
+public class WorkerThreadStore : DbStore {
+ private bool has_jobs = true;
+
+ public WorkerThreadStore (Db database, bool is_new)
+ : base (database, true)
+ {
+ // Ensure the table exists
+ bool exists = Database.TableExists("jobs");
+
+ if (is_new || !exists)
+ CreateTable ();
+ }
+
+ private void CreateTable ()
+ {
+ Database.Execute(
+ @"CREATE TABLE jobs (
+ id INTEGER PRIMARY KEY NOT NULL,
+ command TEXT NOT NULL,
+ options TEXT,
+ time INTEGER
+ )");
+ }
+
+ public override DbItem Get (uint id)
+ {
+ return null; // FIXME: do we need this?
+ }
+
+ public override void Remove (DbItem item)
+ {
+ string query = String.Format ("DELETE FROM jobs WHERE id = {0}", item.Id);
+ Database.ExecuteNoWait(query);
+ }
+
+ public override void Commit (DbItem dbitem)
+ {
+ // FIXME: implement, if needed
+ }
+
+ public void Create (string jobcommand, string options) {
+ string query = String.Format ("INSERT INTO jobs "
+ + "(command, options, time) VALUES (\"{0}\", \"{1}\", \"{2}\")",
+ jobcommand, options, DateTime.Now.Ticks);
+ Database.ExecuteNoWait(query);
+ has_jobs = true;
+ }
+
+ /*
+ * Return a job, if available, otherwise returns null.
+ */
+ public DbItem GetJob() {
+ if (!has_jobs)
+ return null;
+
+ WorkerThreadItem job = null;
+ string query = "SELECT id, command, options "
+ + "FROM jobs ORDER BY time ASC LIMIT 1";
+ SqliteDataReader reader = Database.Query(query);
+
+ if (reader.Read ()) {
+ job = new WorkerThreadItem (Convert.ToUInt32(reader[0]),
+ reader[1].ToString(),
+ reader[2].ToString());
+ }
+
+ if (job == null)
+ has_jobs = false;
+ return job;
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]