فهرست منبع

Merge pull request #3838 from Bond-009/memorystream

MemoryStream optimizations
Anthony Lavado 5 سال پیش
والد
کامیت
5480674c4f

+ 11 - 5
Emby.Server.Implementations/AppBase/ConfigurationHelper.cs

@@ -1,3 +1,5 @@
+#nullable enable
+
 using System;
 using System;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
@@ -22,7 +24,7 @@ namespace Emby.Server.Implementations.AppBase
         {
         {
             object configuration;
             object configuration;
 
 
-            byte[] buffer = null;
+            byte[]? buffer = null;
 
 
             // Use try/catch to avoid the extra file system lookup using File.Exists
             // Use try/catch to avoid the extra file system lookup using File.Exists
             try
             try
@@ -36,19 +38,23 @@ namespace Emby.Server.Implementations.AppBase
                 configuration = Activator.CreateInstance(type);
                 configuration = Activator.CreateInstance(type);
             }
             }
 
 
-            using var stream = new MemoryStream();
+            using var stream = new MemoryStream(buffer?.Length ?? 0);
             xmlSerializer.SerializeToStream(configuration, stream);
             xmlSerializer.SerializeToStream(configuration, stream);
 
 
             // Take the object we just got and serialize it back to bytes
             // Take the object we just got and serialize it back to bytes
-            var newBytes = stream.ToArray();
+            byte[] newBytes = stream.GetBuffer();
+            int newBytesLen = (int)stream.Length;
 
 
             // If the file didn't exist before, or if something has changed, re-save
             // If the file didn't exist before, or if something has changed, re-save
-            if (buffer == null || !buffer.SequenceEqual(newBytes))
+            if (buffer == null || !newBytes.AsSpan(0, newBytesLen).SequenceEqual(buffer))
             {
             {
                 Directory.CreateDirectory(Path.GetDirectoryName(path));
                 Directory.CreateDirectory(Path.GetDirectoryName(path));
 
 
                 // Save it after load in case we got new items
                 // Save it after load in case we got new items
-                File.WriteAllBytes(path, newBytes);
+                using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
+                {
+                    fs.Write(newBytes, 0, newBytesLen);
+                }
             }
             }
 
 
             return configuration;
             return configuration;

+ 3 - 2
Emby.Server.Implementations/HttpServer/HttpResultFactory.cs

@@ -105,7 +105,7 @@ namespace Emby.Server.Implementations.HttpServer
                 responseHeaders = new Dictionary<string, string>();
                 responseHeaders = new Dictionary<string, string>();
             }
             }
 
 
-            if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out string expires))
+            if (addCachePrevention && !responseHeaders.TryGetValue(HeaderNames.Expires, out _))
             {
             {
                 responseHeaders[HeaderNames.Expires] = "0";
                 responseHeaders[HeaderNames.Expires] = "0";
             }
             }
@@ -326,7 +326,8 @@ namespace Emby.Server.Implementations.HttpServer
             return GetHttpResult(request, ms, contentType, true, responseHeaders);
             return GetHttpResult(request, ms, contentType, true, responseHeaders);
         }
         }
 
 
-        private IHasHeaders GetCompressedResult(byte[] content,
+        private IHasHeaders GetCompressedResult(
+            byte[] content,
             string requestedCompressionType,
             string requestedCompressionType,
             IDictionary<string, string> responseHeaders,
             IDictionary<string, string> responseHeaders,
             bool isHeadRequest,
             bool isHeadRequest,

+ 2 - 2
Emby.Server.Implementations/HttpServer/StreamWriter.cs

@@ -95,13 +95,13 @@ namespace Emby.Server.Implementations.HttpServer
 
 
                 if (bytes != null)
                 if (bytes != null)
                 {
                 {
-                    await responseStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
+                    await responseStream.WriteAsync(bytes, 0, bytes.Length, cancellationToken).ConfigureAwait(false);
                 }
                 }
                 else
                 else
                 {
                 {
                     using (var src = SourceStream)
                     using (var src = SourceStream)
                     {
                     {
-                        await src.CopyToAsync(responseStream).ConfigureAwait(false);
+                        await src.CopyToAsync(responseStream, cancellationToken).ConfigureAwait(false);
                     }
                     }
                 }
                 }
             }
             }

+ 6 - 4
Emby.Server.Implementations/Serialization/MyXmlSerializer.cs

@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
 using System.IO;
 using System.IO;
 using System.Xml;
 using System.Xml;
 using System.Xml.Serialization;
 using System.Xml.Serialization;
+using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
 using MediaBrowser.Model.Serialization;
 
 
 namespace Emby.Server.Implementations.Serialization
 namespace Emby.Server.Implementations.Serialization
@@ -53,10 +54,11 @@ namespace Emby.Server.Implementations.Serialization
         /// <param name="stream">The stream.</param>
         /// <param name="stream">The stream.</param>
         public void SerializeToStream(object obj, Stream stream)
         public void SerializeToStream(object obj, Stream stream)
         {
         {
-            using (var writer = new XmlTextWriter(stream, null))
+            using (var writer = new StreamWriter(stream, null, IODefaults.StreamWriterBufferSize, true))
+            using (var textWriter = new XmlTextWriter(writer))
             {
             {
-                writer.Formatting = Formatting.Indented;
-                SerializeToWriter(obj, writer);
+                textWriter.Formatting = Formatting.Indented;
+                SerializeToWriter(obj, textWriter);
             }
             }
         }
         }
 
 
@@ -95,7 +97,7 @@ namespace Emby.Server.Implementations.Serialization
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         public object DeserializeFromBytes(Type type, byte[] buffer)
         public object DeserializeFromBytes(Type type, byte[] buffer)
         {
         {
-            using (var stream = new MemoryStream(buffer))
+            using (var stream = new MemoryStream(buffer, 0, buffer.Length, false, true))
             {
             {
                 return DeserializeFromStream(type, stream);
                 return DeserializeFromStream(type, stream);
             }
             }

+ 1 - 1
Jellyfin.Api/Controllers/ImageController.cs

@@ -969,7 +969,7 @@ namespace Jellyfin.Api.Controllers
             var text = await reader.ReadToEndAsync().ConfigureAwait(false);
             var text = await reader.ReadToEndAsync().ConfigureAwait(false);
 
 
             var bytes = Convert.FromBase64String(text);
             var bytes = Convert.FromBase64String(text);
-            return new MemoryStream(bytes) { Position = 0 };
+            return new MemoryStream(bytes, 0, bytes.Length, false, true);
         }
         }
 
 
         private ImageInfo? GetImageInfo(BaseItem item, ItemImageInfo info, int? imageIndex)
         private ImageInfo? GetImageInfo(BaseItem item, ItemImageInfo info, int? imageIndex)

+ 7 - 0
MediaBrowser.Model/IO/IODefaults.cs

@@ -1,3 +1,5 @@
+using System.IO;
+
 namespace MediaBrowser.Model.IO
 namespace MediaBrowser.Model.IO
 {
 {
     /// <summary>
     /// <summary>
@@ -14,5 +16,10 @@ namespace MediaBrowser.Model.IO
         /// The default file stream buffer size.
         /// The default file stream buffer size.
         /// </summary>
         /// </summary>
         public const int FileStreamBufferSize = 4096;
         public const int FileStreamBufferSize = 4096;
+
+        /// <summary>
+        /// The default <see cref="StreamWriter" /> buffer size.
+        /// </summary>
+        public const int StreamWriterBufferSize = 1024;
     }
     }
 }
 }

+ 17 - 14
MediaBrowser.Providers/Manager/ImageSaver.cs

@@ -124,13 +124,16 @@ namespace MediaBrowser.Providers.Manager
             var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false);
             var retryPaths = GetSavePaths(item, type, imageIndex, mimeType, false);
 
 
             // If there are more than one output paths, the stream will need to be seekable
             // If there are more than one output paths, the stream will need to be seekable
-            var memoryStream = new MemoryStream();
-            await using (source.ConfigureAwait(false))
+            if (paths.Length > 1 && !source.CanSeek)
             {
             {
-                await source.CopyToAsync(memoryStream).ConfigureAwait(false);
-            }
+                var memoryStream = new MemoryStream();
+                await using (source.ConfigureAwait(false))
+                {
+                    await source.CopyToAsync(memoryStream).ConfigureAwait(false);
+                }
 
 
-            source = memoryStream;
+                source = memoryStream;
+            }
 
 
             var currentImage = GetCurrentImage(item, type, index);
             var currentImage = GetCurrentImage(item, type, index);
             var currentImageIsLocalFile = currentImage != null && currentImage.IsLocalFile;
             var currentImageIsLocalFile = currentImage != null && currentImage.IsLocalFile;
@@ -140,20 +143,21 @@ namespace MediaBrowser.Providers.Manager
 
 
             await using (source.ConfigureAwait(false))
             await using (source.ConfigureAwait(false))
             {
             {
-                var currentPathIndex = 0;
-
-                foreach (var path in paths)
+                for (int i = 0; i < paths.Length; i++)
                 {
                 {
-                    source.Position = 0;
+                    if (i != 0)
+                    {
+                        source.Position = 0;
+                    }
+
                     string retryPath = null;
                     string retryPath = null;
                     if (paths.Length == retryPaths.Length)
                     if (paths.Length == retryPaths.Length)
                     {
                     {
-                        retryPath = retryPaths[currentPathIndex];
+                        retryPath = retryPaths[i];
                     }
                     }
 
 
-                    var savedPath = await SaveImageToLocation(source, path, retryPath, cancellationToken).ConfigureAwait(false);
+                    var savedPath = await SaveImageToLocation(source, paths[i], retryPath, cancellationToken).ConfigureAwait(false);
                     savedPaths.Add(savedPath);
                     savedPaths.Add(savedPath);
-                    currentPathIndex++;
                 }
                 }
             }
             }
 
 
@@ -224,7 +228,6 @@ namespace MediaBrowser.Providers.Manager
                 }
                 }
             }
             }
 
 
-            source.Position = 0;
             await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false);
             await SaveImageToLocation(source, retryPath, cancellationToken).ConfigureAwait(false);
             return retryPath;
             return retryPath;
         }
         }
@@ -253,7 +256,7 @@ namespace MediaBrowser.Providers.Manager
 
 
                 await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous))
                 await using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous))
                 {
                 {
-                    await source.CopyToAsync(fs, IODefaults.CopyToBufferSize, cancellationToken).ConfigureAwait(false);
+                    await source.CopyToAsync(fs, cancellationToken).ConfigureAwait(false);
                 }
                 }
 
 
                 if (_config.Configuration.SaveMetadataHidden)
                 if (_config.Configuration.SaveMetadataHidden)

+ 1 - 1
MediaBrowser.Providers/Subtitles/SubtitleManager.cs

@@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Subtitles
             CancellationToken cancellationToken)
             CancellationToken cancellationToken)
         {
         {
             var parts = subtitleId.Split(new[] { '_' }, 2);
             var parts = subtitleId.Split(new[] { '_' }, 2);
-            var provider = GetProvider(parts.First());
+            var provider = GetProvider(parts[0]);
 
 
             var saveInMediaFolder = libraryOptions.SaveSubtitlesWithMedia;
             var saveInMediaFolder = libraryOptions.SaveSubtitlesWithMedia;