Browse Source

Minor performance improvements to item saving

Bond_009 4 years ago
parent
commit
48e1cf9fd7

+ 11 - 2
Emby.Server.Implementations/Data/BaseSqliteRepository.cs

@@ -143,8 +143,17 @@ namespace Emby.Server.Implementations.Data
         public IStatement PrepareStatement(IDatabaseConnection connection, string sql)
             => connection.PrepareStatement(sql);
 
-        public IEnumerable<IStatement> PrepareAll(IDatabaseConnection connection, IEnumerable<string> sql)
-            => sql.Select(connection.PrepareStatement);
+        public IStatement[] PrepareAll(IDatabaseConnection connection, IReadOnlyList<string> sql)
+        {
+            int len = sql.Count;
+            IStatement[] statements = new IStatement[len];
+            for (int i = 0; i < len; i++)
+            {
+                statements[i] = connection.PrepareStatement(sql[i]);
+            }
+
+            return statements;
+        }
 
         protected bool TableExists(ManagedConnection connection, string name)
         {

+ 45 - 28
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -560,7 +560,7 @@ namespace Emby.Server.Implementations.Data
             {
                 SaveItemCommandText,
                 "delete from AncestorIds where ItemId=@ItemId"
-            }).ToList();
+            });
 
             using (var saveItemStatement = statements[0])
             using (var deleteAncestorsStatement = statements[1])
@@ -2925,7 +2925,7 @@ namespace Emby.Server.Implementations.Data
             {
                 connection.RunInTransaction(db =>
                 {
-                    var statements = PrepareAll(db, statementTexts).ToList();
+                    var statements = PrepareAll(db, statementTexts);
 
                     if (!isReturningZeroItems)
                     {
@@ -3329,7 +3329,7 @@ namespace Emby.Server.Implementations.Data
             {
                 connection.RunInTransaction(db =>
                 {
-                    var statements = PrepareAll(db, statementTexts).ToList();
+                    var statements = PrepareAll(db, statementTexts);
 
                     if (!isReturningZeroItems)
                     {
@@ -3718,26 +3718,31 @@ namespace Emby.Server.Implementations.Data
                 statement?.TryBind("@MaxPremiereDate", query.MaxPremiereDate.Value);
             }
 
+            StringBuilder clauseBuilder = new StringBuilder();
+            const string Or = " OR ";
+
             var trailerTypes = query.TrailerTypes;
             int trailerTypesLen = trailerTypes.Length;
             if (trailerTypesLen > 0)
             {
-                const string Or = " OR ";
-                StringBuilder clause = new StringBuilder("(", trailerTypesLen * 32);
+                clauseBuilder.Append('(');
+
                 for (int i = 0; i < trailerTypesLen; i++)
                 {
                     var paramName = "@TrailerTypes" + i;
-                    clause.Append("TrailerTypes like ")
+                    clauseBuilder.Append("TrailerTypes like ")
                         .Append(paramName)
                         .Append(Or);
                     statement?.TryBind(paramName, "%" + trailerTypes[i] + "%");
                 }
 
                 // Remove last " OR "
-                clause.Length -= Or.Length;
-                clause.Append(')');
+                clauseBuilder.Length -= Or.Length;
+                clauseBuilder.Append(')');
+
+                whereClauses.Add(clauseBuilder.ToString());
 
-                whereClauses.Add(clause.ToString());
+                clauseBuilder.Length = 0;
             }
 
             if (query.IsAiring.HasValue)
@@ -3757,23 +3762,35 @@ namespace Emby.Server.Implementations.Data
                 }
             }
 
-            if (query.PersonIds.Length > 0)
+            int personIdsLen = query.PersonIds.Length;
+            if (personIdsLen > 0)
             {
                 // TODO: Should this query with CleanName ?
 
-                var clauses = new List<string>();
-                var index = 0;
-                foreach (var personId in query.PersonIds)
+                clauseBuilder.Append('(');
+
+                Span<byte> idBytes = stackalloc byte[16];
+                for (int i = 0; i < personIdsLen; i++)
                 {
-                    var paramName = "@PersonId" + index;
+                    string paramName = "@PersonId" + i;
+                    clauseBuilder.Append("(guid in (select itemid from People where Name = (select Name from TypedBaseItems where guid=")
+                        .Append(paramName)
+                        .Append("))) OR ");
 
-                    clauses.Add("(guid in (select itemid from People where Name = (select Name from TypedBaseItems where guid=" + paramName + ")))");
-                    statement?.TryBind(paramName, personId.ToByteArray());
-                    index++;
+                    if (statement != null)
+                    {
+                        query.PersonIds[i].TryWriteBytes(idBytes);
+                        statement.TryBind(paramName, idBytes);
+                    }
                 }
 
-                var clause = "(" + string.Join(" OR ", clauses) + ")";
-                whereClauses.Add(clause);
+                // Remove last " OR "
+                clauseBuilder.Length -= Or.Length;
+                clauseBuilder.Append(')');
+
+                whereClauses.Add(clauseBuilder.ToString());
+
+                clauseBuilder.Length = 0;
             }
 
             if (!string.IsNullOrWhiteSpace(query.Person))
@@ -5149,7 +5166,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 
             CheckDisposed();
 
-            var itemIdBlob = itemId.ToByteArray();
+            Span<byte> itemIdBlob = stackalloc byte[16]
+            itemId.TryWriteBytes(itemIdBlob);
 
             // First delete
             deleteAncestorsStatement.Reset();
@@ -5165,17 +5183,15 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 
             for (var i = 0; i < ancestorIds.Count; i++)
             {
-                if (i > 0)
-                {
-                    insertText.Append(',');
-                }
-
                 insertText.AppendFormat(
                     CultureInfo.InvariantCulture,
-                    "(@ItemId, @AncestorId{0}, @AncestorIdText{0})",
+                    "(@ItemId, @AncestorId{0}, @AncestorIdText{0}),",
                     i.ToString(CultureInfo.InvariantCulture));
             }
 
+            // Remove last ,
+            insertText.Length--;
+
             using (var statement = PrepareStatement(db, insertText.ToString()))
             {
                 statement.TryBind("@ItemId", itemIdBlob);
@@ -5185,8 +5201,9 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
                     var index = i.ToString(CultureInfo.InvariantCulture);
 
                     var ancestorId = ancestorIds[i];
+                    ancestorId.TryWriteBytes(itemIdBlob);
 
-                    statement.TryBind("@AncestorId" + index, ancestorId.ToByteArray());
+                    statement.TryBind("@AncestorId" + index, itemIdBlob);
                     statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture));
                 }
 
@@ -5466,7 +5483,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
                 connection.RunInTransaction(
                     db =>
                     {
-                        var statements = PrepareAll(db, statementTexts).ToList();
+                        var statements = PrepareAll(db, statementTexts);
 
                         if (!isReturningZeroItems)
                         {

+ 18 - 21
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -513,10 +513,11 @@ namespace Emby.Server.Implementations.Library
                 throw new ArgumentNullException(nameof(type));
             }
 
-            if (key.StartsWith(_configurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal))
+            string programDataPath = _configurationManager.ApplicationPaths.ProgramDataPath;
+            if (key.StartsWith(programDataPath, StringComparison.Ordinal))
             {
                 // Try to normalize paths located underneath program-data in an attempt to make them more portable
-                key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length)
+                key = key.Substring(programDataPath.Length)
                     .TrimStart('/', '\\')
                     .Replace('/', '\\');
             }
@@ -871,17 +872,17 @@ namespace Emby.Server.Implementations.Library
 
         public Guid GetStudioId(string name)
         {
-            return GetItemByNameId<Studio>(Studio.GetPath, name);
+            return GetItemByNameId<Studio>(Studio.GetPath(name));
         }
 
         public Guid GetGenreId(string name)
         {
-            return GetItemByNameId<Genre>(Genre.GetPath, name);
+            return GetItemByNameId<Genre>(Genre.GetPath(name));
         }
 
         public Guid GetMusicGenreId(string name)
         {
-            return GetItemByNameId<MusicGenre>(MusicGenre.GetPath, name);
+            return GetItemByNameId<MusicGenre>(MusicGenre.GetPath(name));
         }
 
         /// <summary>
@@ -943,7 +944,7 @@ namespace Emby.Server.Implementations.Library
             {
                 var existing = GetItemList(new InternalItemsQuery
                 {
-                    IncludeItemTypes = new[] { typeof(T).Name },
+                    IncludeItemTypes = new[] { nameof(MusicArtist) },
                     Name = name,
                     DtoOptions = options
                 }).Cast<MusicArtist>()
@@ -957,13 +958,11 @@ namespace Emby.Server.Implementations.Library
                 }
             }
 
-            var id = GetItemByNameId<T>(getPathFn, name);
-
-            var item = GetItemById(id) as T;
+            var path = getPathFn(name);
+            var id = GetItemByNameId<T>(path);
 
-            if (item == null)
+            if (GetItemById(id) is T item)
             {
-                var path = getPathFn(name);
                 item = new T
                 {
                     Name = name,
@@ -974,15 +973,16 @@ namespace Emby.Server.Implementations.Library
                 };
 
                 CreateItem(item, null);
+
+                return item;
             }
 
-            return item;
+            return null;
         }
 
-        private Guid GetItemByNameId<T>(Func<string, string> getPathFn, string name)
+        private Guid GetItemByNameId<T>(string path)
               where T : BaseItem, new()
         {
-            var path = getPathFn(name);
             var forceCaseInsensitiveId = _configurationManager.Configuration.EnableNormalizedItemByNameIds;
             return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
         }
@@ -1805,21 +1805,18 @@ namespace Emby.Server.Implementations.Library
         /// <param name="items">The items.</param>
         /// <param name="parent">The parent item.</param>
         /// <param name="cancellationToken">The cancellation token.</param>
-        public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
+        public void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
         {
-            // Don't iterate multiple times
-            var itemsList = items.ToList();
-
-            _itemRepository.SaveItems(itemsList, cancellationToken);
+            _itemRepository.SaveItems(items, cancellationToken);
 
-            foreach (var item in itemsList)
+            foreach (var item in items)
             {
                 RegisterItem(item);
             }
 
             if (ItemAdded != null)
             {
-                foreach (var item in itemsList)
+                foreach (var item in items)
                 {
                     // With the live tv guide this just creates too much noise
                     if (item.SourceType != SourceType.Library)

+ 2 - 3
Emby.Server.Implementations/Security/AuthenticationRepository.cs

@@ -257,8 +257,7 @@ namespace Emby.Server.Implementations.Security
                 connection.RunInTransaction(
                     db =>
                     {
-                        var statements = PrepareAll(db, statementTexts)
-                            .ToList();
+                        var statements = PrepareAll(db, statementTexts);
 
                         using (var statement = statements[0])
                         {
@@ -282,7 +281,7 @@ namespace Emby.Server.Implementations.Security
                     ReadTransactionMode);
             }
 
-            result.Items = list.ToArray();
+            result.Items = list;
             return result;
         }
 

+ 1 - 1
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -200,7 +200,7 @@ namespace MediaBrowser.Controller.Library
         /// <summary>
         /// Creates the items.
         /// </summary>
-        void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken);
+        void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken);
 
         /// <summary>
         /// Updates the item.