[f-spot/cleanup-backend: 23/24] Provide more efficient implementation for loading photos



commit 8b5991e10c7c51ce2534ef70e20c57d1480c80d5
Author: Mike Gemünde <mike gemuende de>
Date:   Fri Jul 16 19:06:34 2010 +0200

    Provide more efficient implementation for loading photos
    
    The method LoadAll() is added to DatabasePhotoModelProvider to provide loading a
    bunch of photos at once. This is more efficient, because the versions which are
    also loaded can be queried at once from database. DatabasePhotoModelCache is
    extended to make use of the method.

 src/FSpot.Database/DatabasePhoto.cs             |   20 ++++---
 src/FSpot.Database/DatabasePhotoModelCache.cs   |   38 +++++++++++-
 src/FSpot.Database/DatabasePhotoVersion.cs      |    2 +-
 src/FSpot.Database/PhotoModelProvider.cs        |   71 ++++++++++++++++++++---
 src/FSpot.Database/PhotoVersionModelProvider.cs |    4 +-
 src/FSpot.Database/SqliteCachedModelProvider.cs |   24 ++++----
 6 files changed, 123 insertions(+), 36 deletions(-)
---
diff --git a/src/FSpot.Database/DatabasePhoto.cs b/src/FSpot.Database/DatabasePhoto.cs
index e6d32db..b9cf6a3 100644
--- a/src/FSpot.Database/DatabasePhoto.cs
+++ b/src/FSpot.Database/DatabasePhoto.cs
@@ -32,8 +32,8 @@ namespace FSpot.Database
 
         public DatabasePhoto ()
         {
-            /* To be removed */            
-            Tags = new Tag[] {  };
+            /* To be removed */
+            Tags = new Tag[] {};
         }
 
 #endregion
@@ -82,9 +82,12 @@ namespace FSpot.Database
             }
         }
 
-        private List<IBrowsableItemVersion> versions;
+        private List<DatabasePhotoVersion> versions;
         public IEnumerable<IBrowsableItemVersion> Versions {
-            get { return versions; }
+            get {
+                foreach (IBrowsableItemVersion version in versions)
+                    yield return version;
+            }
         }
 
         public string Name {
@@ -100,9 +103,8 @@ namespace FSpot.Database
 
 #region Remaining IBrowsableItem Implementation
 
-        internal void SetVersions (List<IBrowsableItemVersion> versions)
-        {
-            this.versions = versions;
+        internal List<DatabasePhotoVersion> VersionList {
+           get { return versions ?? (versions = new List<DatabasePhotoVersion> ()); }
         }
 
 #endregion
@@ -112,8 +114,8 @@ namespace FSpot.Database
         public object CacheEntryId { get; set; }
 
         public long CacheModelId { get; set; }
-        
+
 #endregion
-        
+
     }
 }
diff --git a/src/FSpot.Database/DatabasePhotoModelCache.cs b/src/FSpot.Database/DatabasePhotoModelCache.cs
index c6d78c7..1a8c6ec 100644
--- a/src/FSpot.Database/DatabasePhotoModelCache.cs
+++ b/src/FSpot.Database/DatabasePhotoModelCache.cs
@@ -10,6 +10,7 @@
 //
 
 using System;
+using System.Data;
 
 using Hyena.Data.Sqlite;
 
@@ -19,12 +20,43 @@ namespace FSpot.Database
 
     public class DatabasePhotoModelCache : SqliteModelCache<DatabasePhoto>
     {
+
+#region Private Fields
+
+        private PhotoModelProvider provider;
+        private HyenaSqliteConnection connection;
+
+#endregion
+
 #region Constructors
 
-        public DatabasePhotoModelCache (HyenaSqliteConnection connection, string uuid, ICacheableDatabaseModel model, PhotoModelProvider provider) : base(connection, uuid, model, provider)
+        public DatabasePhotoModelCache (HyenaSqliteConnection connection, string uuid, ICacheableDatabaseModel model, PhotoModelProvider provider)
+            : base(connection, uuid, model, provider)
         {
+            this.provider = provider;
+            this.connection = connection;
         }
-        
-        #endregion
+
+#endregion
+
+
+#region Override SqliteModelCache behavior
+
+        /// <summary>
+        ///    Provide a more effivient implementation by using the method LoadAll of <see cref="PhotoModelProvider"/>
+        /// </summary>
+        protected override void FetchSet (long offset, long limit)
+        {
+            lock (this) {
+                using (IDataReader reader = connection.Query (select_range_command, offset, limit)) {
+                    foreach (DatabasePhoto photo in provider.LoadAll (reader)) {
+                        Add (offset, photo);
+                        offset ++;
+                    }
+                }
+            }
+        }
+
+#endregion
     }
 }
diff --git a/src/FSpot.Database/DatabasePhotoVersion.cs b/src/FSpot.Database/DatabasePhotoVersion.cs
index 9dde142..a33d4f8 100644
--- a/src/FSpot.Database/DatabasePhotoVersion.cs
+++ b/src/FSpot.Database/DatabasePhotoVersion.cs
@@ -83,7 +83,7 @@ namespace FSpot.Database
             set {
                 if (value == null)
                     throw new ArgumentNullException ();
-                
+
                 BaseUri = value.GetBaseUri ();
                 Filename = value.GetFilename ();
             }
diff --git a/src/FSpot.Database/PhotoModelProvider.cs b/src/FSpot.Database/PhotoModelProvider.cs
index e7d6409..de0fe9e 100644
--- a/src/FSpot.Database/PhotoModelProvider.cs
+++ b/src/FSpot.Database/PhotoModelProvider.cs
@@ -43,20 +43,73 @@ namespace FSpot.Database
 
 #endregion
 
-#region Override SqliteCachedModelProvider Behavior
-
-        protected override void Populate (DatabasePhoto item)
+#region Public Methods
+
+        /// <summary>
+        ///    This method loads a bunch of photos at once. It is more efficient than loading each one, because
+        ///    The photo versions can be also loaded at once.
+        /// </summary>
+        /// <remarks>
+        ///    This method is mainly used to provide efficient loading of photos for a DatabasePhotoModelCache.
+        /// </remarks>
+        public IEnumerable<DatabasePhoto> LoadAll (System.Data.IDataReader reader)
         {
-            List<IBrowsableItemVersion> versions = new List<IBrowsableItemVersion> ();
+            Dictionary<int, DatabasePhoto> photo_lookup = new Dictionary<int, DatabasePhoto> ();
+            List<DatabasePhoto> photo_list = new List<DatabasePhoto> ();
+            StringBuilder photo_id_query = new StringBuilder ("photo_id IN (");
+
+            bool first = true;
+            while (reader.Read ()) {
+                DatabasePhoto photo = base.Load (reader);
+
+                photo_lookup.Add (photo.Id, photo);
+                photo_list.Add (photo);
+
+                if ( ! first)
+                    photo_id_query.Append (", ");
+
+                photo_id_query.Append (photo.Id);
+
+                first = false;
+            }
+
+            photo_id_query.Append (")");
+
+            IEnumerator<DatabasePhoto> photo_enum = photo_list.GetEnumerator ();
+            photo_enum.MoveNext ();
+
+            foreach (DatabasePhotoVersion version in photo_versions.FetchAllMatching (photo_id_query.ToString ())) {
+                photo_lookup [version.PhotoId].VersionList.Add (version);
+            }
+
+            return photo_list;
+        }
+
+#endregion
 
-            foreach (DatabasePhotoVersion version in photo_versions.FetchAllMatching ("photo_id = ?", item.Id)) {
-                versions.Add (version);
+#region Protected Methods
+
+        protected void Populate (DatabasePhoto photo)
+        {
+            foreach (DatabasePhotoVersion version in photo_versions.FetchAllMatching ("photo_id = ?", photo.Id)) {
+                photo.VersionList.Add (version);
             }
 
-            if (versions.Count == 0)
-                Log.DebugFormat ("No versions for photo ({0}) found.", item.Id);
+            if (photo.VersionList.Count == 0)
+                Log.DebugFormat ("No versions for photo ({0}) found.", photo.Id);
+        }
+
+#endregion
+
+#region Override SqliteModelProvider Behavior
+
+
+        public override DatabasePhoto Load (System.Data.IDataReader reader)
+        {
+            DatabasePhoto photo = base.Load (reader);
+            Populate (photo);
 
-            item.SetVersions (versions);
+            return photo;
         }
 
         public override void Delete (IEnumerable<DatabasePhoto> photos)
diff --git a/src/FSpot.Database/PhotoVersionModelProvider.cs b/src/FSpot.Database/PhotoVersionModelProvider.cs
index 916403e..946b7ee 100644
--- a/src/FSpot.Database/PhotoVersionModelProvider.cs
+++ b/src/FSpot.Database/PhotoVersionModelProvider.cs
@@ -26,8 +26,8 @@ namespace FSpot.Database
         public PhotoVersionModelProvider (HyenaSqliteConnection connection) : base(connection, "photo_versions")
         {
         }
-        
+
 #endregion
-        
+
     }
 }
diff --git a/src/FSpot.Database/SqliteCachedModelProvider.cs b/src/FSpot.Database/SqliteCachedModelProvider.cs
index 40e0aa5..1bfaf05 100644
--- a/src/FSpot.Database/SqliteCachedModelProvider.cs
+++ b/src/FSpot.Database/SqliteCachedModelProvider.cs
@@ -58,22 +58,22 @@ namespace FSpot.Database
         protected void AddToCache (long id, T item)
         {
             WeakReference pointer;
-            
+
             if (cache.TryGetValue (id, out pointer)) {
                 pointer.Target = item;
                 return;
             }
-            
+
             cache.Add (id, new WeakReference (item));
         }
 
         protected T LookupInCache (long id)
         {
             WeakReference pointer;
-            
+
             if (cache.TryGetValue (id, out pointer))
                 return (T)pointer.Target;
-            
+
             return default(T);
         }
 
@@ -82,18 +82,18 @@ namespace FSpot.Database
         public override T Load (System.Data.IDataReader reader)
         {
             long id = PrimaryKeyFor (reader);
-            
+
             T item = LookupInCache (id);
-            
+
             if (item != null)
                 return item;
-            
+
             item = base.Load (reader);
-            
+
             AddToCache (id, item);
-            
+
             Populate (item);
-            
+
             return item;
         }
 
@@ -103,10 +103,10 @@ namespace FSpot.Database
             // But, this implementation should be a little bit faster because it does not
             // query to database if the item is still cached.
             T item = LookupInCache (id);
-            
+
             if (item != null)
                 return item;
-            
+
             return base.FetchSingle (id);
         }
 



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