Fix EF Core memory leak

This commit is contained in:
Patrick Barron 2020-07-12 14:45:52 -04:00
parent c0bd10879a
commit 8959621da7
1 changed files with 40 additions and 14 deletions

View File

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