banshee r3963 - in trunk/banshee: . src/Core/Banshee.Core src/Core/Banshee.Core/Banshee.Kernel src/Core/Banshee.Services/Banshee.Database src/Extensions/Banshee.Podcasting/Banshee.Podcasting src/Libraries/Hyena/Hyena.Data.Sqlite src/Libraries/Migo/Migo.Syndication



Author: gburt
Date: Thu May 22 19:49:27 2008
New Revision: 3963
URL: http://svn.gnome.org/viewvc/banshee?rev=3963&view=rev

Log:
2008-05-22  Gabriel Burt  <gabriel burt gmail com>

	There were some pretty big performance issues with podcasting if you had
	quite a few items in your library.  The two issues were not having proper
	indices (to join CoreTracks.ExternalID = PodcastItems.ItemID for example)
	and hitting the database to get Migo.Feed/FeedItem/FeedEnclosure objects
	when we already had them cached in MigoModelProvider's dictionary.

	* src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs:
	Schedule a delegate job to reload the feeds on startup.

	* src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs:
	Add an index on CoreTracks for the ExternalID column.

	* src/Core/Banshee.Core/Makefile.am:
	* src/Core/Banshee.Core/Banshee.Core.mdp:
	* src/Core/Banshee.Core/Banshee.Kernel/DelegateJob.cs: New class for
	running parameterless methods/delegates as a Job.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs: Add a
	CreateIndex convenience method, and make FetchSingle virtual

	* src/Libraries/Migo/Migo.Syndication/FeedItem.cs:
	* src/Libraries/Migo/Migo.Syndication/FeedEnclosure.cs:
	* src/Libraries/Migo/Migo.Syndication/Feed.cs: Add indices, speeds up
	podcast queries a whole lot.

	* src/Libraries/Migo/Migo.Syndication/MigoModelProvider.cs: Override
	FetchSingle to pull directly from the dictionary and avoid the DB entirely
	if possible (happens very frequently).

	* src/Libraries/Migo/Migo.Syndication/FeedManager.cs: Only download 2
	feeds at at time, not 4.


Added:
   trunk/banshee/src/Core/Banshee.Core/Banshee.Kernel/DelegateJob.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp
   trunk/banshee/src/Core/Banshee.Core/Makefile.am
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
   trunk/banshee/src/Libraries/Migo/Migo.Syndication/Feed.cs
   trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedEnclosure.cs
   trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedItem.cs
   trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedManager.cs
   trunk/banshee/src/Libraries/Migo/Migo.Syndication/MigoModelProvider.cs

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp	Thu May 22 19:49:27 2008
@@ -1,4 +1,4 @@
-<Project name="Banshee.Core" fileversion="2.0" language="C#" clr-version="Net_2_0" UseParentDirectoryAsNamespace="True" ctype="DotNetProject">
+<Project name="Banshee.Core" fileversion="2.0" UseParentDirectoryAsNamespace="True" language="C#" clr-version="Net_2_0" ctype="DotNetProject">
   <Configurations active="Debug">
     <Configuration name="Debug" ctype="DotNetProjectConfiguration">
       <Output directory="../../../bin" assemblyKeyFile="." assembly="Banshee.Core" />
@@ -69,6 +69,7 @@
     <File name="Banshee.Base/XdgBaseDirectorySpec.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Base/Tests/FileNamePatternTests.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Base/Tests/TaglibReadWriteTests.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Kernel/DelegateJob.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Project" localcopy="False" refto="Hyena" />

Added: trunk/banshee/src/Core/Banshee.Core/Banshee.Kernel/DelegateJob.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Kernel/DelegateJob.cs	Thu May 22 19:49:27 2008
@@ -0,0 +1,48 @@
+//
+// DelegateJob.cs
+//
+// Authors:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace Banshee.Kernel
+{
+    public class DelegateJob : Job
+    {
+        public delegate void JobDelegate ();
+        private JobDelegate method;
+        
+        public DelegateJob (JobDelegate method)
+        {
+            this.method = method;
+        }
+        
+        protected override void RunJob ()
+        {
+            method ();
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Core/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Makefile.am	Thu May 22 19:49:27 2008
@@ -49,6 +49,7 @@
 	Banshee.IO/Provider.cs \
 	Banshee.IO/StreamAssist.cs \
 	Banshee.IO/Utilities.cs \
+	Banshee.Kernel/DelegateJob.cs \
 	Banshee.Kernel/IInstanceCriticalJob.cs \
 	Banshee.Kernel/IJob.cs \
 	Banshee.Kernel/Job.cs \

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	Thu May 22 19:49:27 2008
@@ -52,7 +52,7 @@
         // NOTE: Whenever there is a change in ANY of the database schema,
         //       this version MUST be incremented and a migration method
         //       MUST be supplied to match the new version number
-        protected const int CURRENT_VERSION = 10;
+        protected const int CURRENT_VERSION = 11;
         protected const int CURRENT_METADATA_VERSION = 1;
         
 #region Migration Driver
@@ -381,6 +381,8 @@
 
 #endregion
 
+#region Version 10
+
         [DatabaseVersion (10)]
         private bool Migrate_10 ()
         {
@@ -391,6 +393,19 @@
             Execute ("ALTER TABLE CoreTracks ADD COLUMN ExternalID INTEGER");
             return true;
         }
+        
+#endregion
+
+#region Version 11
+        
+        [DatabaseVersion (11)]
+        private bool Migrate_11 ()
+        {
+            Execute("CREATE INDEX CoreTracksExternalIDIndex ON CoreTracks(PrimarySourceID, ExternalID)");
+            return true;
+        }
+        
+#endregion
 
 #pragma warning restore 0169
         
@@ -474,6 +489,7 @@
             ", (int)TrackMediaAttributes.Default, (int)StreamPlaybackError.None));
             Execute("CREATE INDEX CoreTracksPrimarySourceIndex ON CoreTracks(ArtistID, AlbumID, PrimarySourceID, Disc, TrackNumber, Uri)");
             Execute("CREATE INDEX CoreTracksAggregatesIndex ON CoreTracks(FileSize, Duration)");
+            Execute("CREATE INDEX CoreTracksExternalIDIndex ON CoreTracks(PrimarySourceID, ExternalID)");
             
             Execute(@"
                 CREATE TABLE CoreAlbums (

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastService.cs	Thu May 22 19:49:27 2008
@@ -90,7 +90,7 @@
             InitializeInterface ();
         }
 
-        private void MigrateIfPossible ()
+        private void MigrateLegacyIfNeeded ()
         {
             if (DatabaseConfigurationClient.Client.Get<int> ("Podcast", "Version", 0) == 0) {
                 if (ServiceManager.DbConnection.TableExists ("Podcasts") &&
@@ -180,12 +180,14 @@
         public void DelayedInitialize ()
         {
             // Migrate data from 0.13.2 podcast tables, if they exist
-            MigrateIfPossible ();
-              
-            foreach (Feed feed in Feed.Provider.FetchAll ()) {
-                feed.Update ();
-                RefreshArtworkFor (feed);
-            }
+            MigrateLegacyIfNeeded ();
+            
+            Banshee.Kernel.Scheduler.Schedule (new Banshee.Kernel.DelegateJob (delegate {
+                foreach (Feed feed in Feed.Provider.FetchAll ()) {
+                    feed.Update ();
+                    RefreshArtworkFor (feed);
+                }
+            }));
         }
         
         bool disposing;
@@ -227,7 +229,7 @@
         private void RefreshArtworkFor (Feed feed)
         {
             if (feed.LastDownloadTime != DateTime.MinValue)
-                Banshee.Kernel.Scheduler.Schedule (new PodcastImageFetchJob (feed), Banshee.Kernel.JobPriority.Highest);
+                Banshee.Kernel.Scheduler.Schedule (new PodcastImageFetchJob (feed), Banshee.Kernel.JobPriority.Normal);
         }
         
         private void OnItemAdded (FeedItem item)

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	Thu May 22 19:49:27 2008
@@ -267,6 +267,14 @@
             }
         }
         
+        protected void CreateIndex (string name, string columns)
+        {
+            Connection.Execute (String.Format (
+                "CREATE INDEX {0} ON {1} ({2})",
+                name, TableName, columns
+            ));
+        }
+        
         public virtual void Save (T target)
         {
             try {
@@ -392,7 +400,7 @@
             return FetchSingle ((long) id);
         }
         
-        public T FetchSingle (long id)
+        public virtual T FetchSingle (long id)
         {
             using (IDataReader reader = connection.Query (SelectSingleCommand, id)) {
                 if (reader.Read ()) {

Modified: trunk/banshee/src/Libraries/Migo/Migo.Syndication/Feed.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo.Syndication/Feed.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo.Syndication/Feed.cs	Thu May 22 19:49:27 2008
@@ -69,17 +69,28 @@
         {
         }
         
+        protected override void CreateTable ()
+        {
+            base.CreateTable ();
+            
+            CreateIndex ("PodcastSyndicationsIndex", "IsSubscribed, Title");
+        }
+        
         protected override int ModelVersion {
-            get { return 2; }
+            get { return 3; }
         }
 
         protected override void MigrateTable (int old_version)
         {
-            Log.Debug("WE DID IT!");
+            CheckTable ();
+
             if (old_version < 2) {
-                CheckTable ();
                 Connection.Execute (String.Format ("UPDATE {0} SET IsSubscribed=1", TableName));
-            } else  Log.Debug ("Um... no we didn't");
+            }
+            
+            if (old_version < 3) {
+                CreateIndex ("PodcastSyndicationsIndex", "IsSubscribed, Title");
+            }
         }
     }
 

Modified: trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedEnclosure.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedEnclosure.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedEnclosure.cs	Thu May 22 19:49:27 2008
@@ -231,7 +231,7 @@
             protected set { dbid = value; }
         }
         
-        [DatabaseColumn ("ItemID")]
+        [DatabaseColumn ("ItemID", Index = "PodcastEnclosuresItemIDIndex")]
         protected long item_id;
         public long ItemId {
             get { return Item.DbId; }

Modified: trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedItem.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedItem.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedItem.cs	Thu May 22 19:49:27 2008
@@ -36,6 +36,13 @@
 
 namespace Migo.Syndication
 {
+    public class FeedItemProvider : MigoModelProvider<FeedItem>
+    {
+        public FeedItemProvider (HyenaSqliteConnection connection) : base (connection, "PodcastItems")
+        {
+        }
+    }
+
     public class FeedItem : MigoItem<FeedItem>
     {
         private static SqliteModelProvider<FeedItem> provider;
@@ -49,7 +56,7 @@
         }
         
         public static void Init () {
-            provider = new MigoModelProvider<FeedItem> (FeedsManager.Instance.Connection, "PodcastItems");
+            provider = new FeedItemProvider (FeedsManager.Instance.Connection);
         }
 
         private bool active = true;
@@ -78,7 +85,7 @@
             protected set { dbid = value; }
         }
 
-        [DatabaseColumn("FeedID")]
+        [DatabaseColumn("FeedID", Index = "PodcastItemsFeedIDIndex")]
         protected long feed_id;
         public long FeedId {
             get { return feed_id; }
@@ -112,7 +119,7 @@
             set { description = value; }
         }
         
-        [DatabaseColumn]
+        [DatabaseColumn("Guid", Index = "PodcastItemsGuidIndex")]
         public string Guid {
             get { return guid; }
             set { guid = value; }

Modified: trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedManager.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedManager.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo.Syndication/FeedManager.cs	Thu May 22 19:49:27 2008
@@ -59,7 +59,7 @@
             update_task_list = new TaskList<FeedUpdateTask> ();
             
             // Limit to 4 feeds downloading at a time
-            update_task_group = new TaskGroup<FeedUpdateTask> (4, update_task_list);
+            update_task_group = new TaskGroup<FeedUpdateTask> (2, update_task_list);
             
             update_task_group.TaskStopped += OnUpdateTaskStopped;
             update_task_group.TaskAssociated += OnUpdateTaskAdded;

Modified: trunk/banshee/src/Libraries/Migo/Migo.Syndication/MigoModelProvider.cs
==============================================================================
--- trunk/banshee/src/Libraries/Migo/Migo.Syndication/MigoModelProvider.cs	(original)
+++ trunk/banshee/src/Libraries/Migo/Migo.Syndication/MigoModelProvider.cs	Thu May 22 19:49:27 2008
@@ -36,33 +36,32 @@
 {
     // Caches all results retrieved from the database, such that any subsequent retrieval will
     // return the same instance.
-    public class MigoModelProvider<T> : SqliteModelProvider<T> where T : ICacheableItem, new()
+    public class MigoModelProvider<T> : SqliteModelProvider<T> where T : ICacheableItem, MigoItem<T>, new()
     {
         private Dictionary<long, T> full_cache = new Dictionary<long, T> ();
         
         public MigoModelProvider (HyenaSqliteConnection connection, string table_name) : base (connection, table_name)
         {
         }
+
+#region Overrides
+                
+        public override T FetchSingle (long id)
+        {
+            return GetCached (id) ?? CacheResult (base.FetchSingle (id));
+        }
         
         public override void Save (T target)
         {
             base.Save (target);
-            long dbid = PrimaryKeyFor (target);
-            if (!full_cache.ContainsKey (dbid)) {
-                full_cache[dbid] = target;
+            if (!full_cache.ContainsKey (target.DbId)) {
+                full_cache[target.DbId] = target;
             }
         }
 
         public override T Load (System.Data.IDataReader reader)
         {
-            long dbid = PrimaryKeyFor (reader);
-            if (full_cache.ContainsKey (dbid)) {
-                return full_cache[dbid];
-            } else {
-                T item = base.Load (reader);
-                full_cache[dbid] = item;
-                return item;
-            }
+            return GetCached (PrimaryKeyFor (reader)) ?? CacheResult (base.Load (reader));
         }
         
         public override void Delete (long id)
@@ -80,5 +79,27 @@
                 
             base.Delete (items);
         }
+        
+#endregion
+
+#region Utility Methods
+
+        private T GetCached (long id)
+        {
+            if (full_cache.ContainsKey (id)) {
+                return full_cache[id];
+            } else {
+                return null;
+            }
+        }
+        
+        private T CacheResult (T item)
+        {
+            full_cache[item.DbId] = item;
+            return item;
+        }
+
+#endregion
+        
     }
 }
\ No newline at end of file



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]