ソースを参照

Fix EF Core memory leak

Patrick Barron 5 年 前
コミット
8959621da7
1 ファイル変更40 行追加14 行削除
  1. 40 14
      Jellyfin.Server.Implementations/Users/UserManager.cs

+ 40 - 14
Jellyfin.Server.Implementations/Users/UserManager.cs

@@ -23,6 +23,7 @@ using MediaBrowser.Model.Cryptography;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Users;
+using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.Logging;
 
 namespace Jellyfin.Server.Implementations.Users
@@ -86,7 +87,18 @@ namespace Jellyfin.Server.Implementations.Users
         public event EventHandler<GenericEventArgs<User>>? OnUserLockedOut;
 
         /// <inheritdoc/>
-        public IEnumerable<User> Users => _dbProvider.CreateContext().Users;
+        public IEnumerable<User> Users
+        {
+            get
+            {
+                using var dbContext = _dbProvider.CreateContext();
+                return dbContext.Users.Include(user => user.Permissions)
+                    .Include(user => user.Preferences)
+                    .Include(user => user.AccessSchedules)
+                    .Include(user => user.ProfileImage)
+                    .ToList();
+            }
+        }
 
         /// <inheritdoc/>
         public IEnumerable<Guid> UsersIds => _dbProvider.CreateContext().Users.Select(u => u.Id);
@@ -99,7 +111,12 @@ namespace Jellyfin.Server.Implementations.Users
                 throw new ArgumentException("Guid can't be empty", nameof(id));
             }
 
-            return _dbProvider.CreateContext().Users.Find(id);
+            using var dbContext = _dbProvider.CreateContext();
+            return dbContext.Users.Include(user => user.Permissions)
+                .Include(user => user.Preferences)
+                .Include(user => user.AccessSchedules)
+                .Include(user => user.ProfileImage)
+                .FirstOrDefault(user => user.Id == id);
         }
 
         /// <inheritdoc/>
@@ -110,7 +127,13 @@ namespace Jellyfin.Server.Implementations.Users
                 throw new ArgumentException("Invalid username", nameof(name));
             }
 
-            return _dbProvider.CreateContext().Users.ToList()
+            using var dbContext = _dbProvider.CreateContext();
+
+            return dbContext.Users.Include(user => user.Permissions)
+                .Include(user => user.Preferences)
+                .Include(user => user.AccessSchedules)
+                .Include(user => user.ProfileImage)
+                .ToList()
                 .FirstOrDefault(u => string.Equals(u.Username, name, StringComparison.OrdinalIgnoreCase));
         }
 
@@ -127,7 +150,7 @@ namespace Jellyfin.Server.Implementations.Users
                 throw new ArgumentException("Invalid username", nameof(newName));
             }
 
-            if (user.Username.Equals(newName, StringComparison.Ordinal))
+            if (user.Username.Equals(newName, StringComparison.OrdinalIgnoreCase))
             {
                 throw new ArgumentException("The new and old names must be different.");
             }
@@ -149,7 +172,7 @@ namespace Jellyfin.Server.Implementations.Users
         /// <inheritdoc/>
         public void UpdateUser(User user)
         {
-            var dbContext = _dbProvider.CreateContext();
+            using var dbContext = _dbProvider.CreateContext();
             dbContext.Users.Update(user);
             dbContext.SaveChanges();
         }
@@ -157,7 +180,7 @@ namespace Jellyfin.Server.Implementations.Users
         /// <inheritdoc/>
         public async Task UpdateUserAsync(User user)
         {
-            var dbContext = _dbProvider.CreateContext();
+            await using var dbContext = _dbProvider.CreateContext();
             dbContext.Users.Update(user);
 
             await dbContext.SaveChangesAsync().ConfigureAwait(false);
@@ -171,7 +194,7 @@ namespace Jellyfin.Server.Implementations.Users
                 throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
             }
 
-            var dbContext = _dbProvider.CreateContext();
+            using var dbContext = _dbProvider.CreateContext();
 
             // TODO: Remove after user item data is migrated.
             var max = dbContext.Users.Any() ? dbContext.Users.Select(u => u.InternalId).Max() : 0;
@@ -194,8 +217,12 @@ namespace Jellyfin.Server.Implementations.Users
         /// <inheritdoc/>
         public void DeleteUser(Guid userId)
         {
-            var dbContext = _dbProvider.CreateContext();
-            var user = dbContext.Users.Find(userId);
+            using var dbContext = _dbProvider.CreateContext();
+            var user = dbContext.Users.Include(u => u.Permissions)
+                .Include(u => u.Preferences)
+                .Include(u => u.AccessSchedules)
+                .Include(u => u.ProfileImage)
+                .FirstOrDefault(u => u.Id == userId);
             if (user == null)
             {
                 throw new ResourceNotFoundException(nameof(userId));
@@ -380,7 +407,7 @@ namespace Jellyfin.Server.Implementations.Users
                 throw new ArgumentNullException(nameof(username));
             }
 
-            var user = Users.ToList().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase));
+            var user = Users.FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase));
             bool success;
             IAuthenticationProvider? authenticationProvider;
 
@@ -408,8 +435,7 @@ namespace Jellyfin.Server.Implementations.Users
 
                     // Search the database for the user again
                     // the authentication provider might have created it
-                    user = Users
-                        .ToList().FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase));
+                    user = Users.FirstOrDefault(i => string.Equals(username, i.Username, StringComparison.OrdinalIgnoreCase));
 
                     if (authenticationProvider is IHasNewUserPolicy hasNewUserPolicy)
                     {
@@ -546,7 +572,7 @@ namespace Jellyfin.Server.Implementations.Users
         public void Initialize()
         {
             // TODO: Refactor the startup wizard so that it doesn't require a user to already exist.
-            var dbContext = _dbProvider.CreateContext();
+            using var dbContext = _dbProvider.CreateContext();
 
             if (dbContext.Users.Any())
             {
@@ -698,7 +724,7 @@ namespace Jellyfin.Server.Implementations.Users
         /// <inheritdoc/>
         public void ClearProfileImage(User user)
         {
-            var dbContext = _dbProvider.CreateContext();
+            using var dbContext = _dbProvider.CreateContext();
             dbContext.Remove(user.ProfileImage);
             dbContext.SaveChanges();
         }