From b4dd8a210629bc74445f106e2379b986af9520c5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 2 Apr 2013 13:37:49 -0400 Subject: moved displaypreferences to usermanager to solve concurrency issues --- .../HttpServer/HttpServer.cs | 2 +- .../Library/LibraryManager.cs | 29 ------- .../Library/UserManager.cs | 66 ++++++++++++++- .../Sqlite/SQLiteDisplayPreferencesRepository.cs | 93 +++++++++++----------- 4 files changed, 113 insertions(+), 77 deletions(-) (limited to 'MediaBrowser.Server.Implementations') diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs index edb227c79..669603958 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpServer.cs @@ -160,7 +160,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer if (exception != null) { - _logger.ErrorException("Error processing request", exception); + _logger.ErrorException("Error processing request for {0}", exception, req.RawUrl); if (!string.IsNullOrEmpty(exception.Message)) { diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 5cbe8ae18..0c1d2ddf8 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -124,15 +124,6 @@ namespace MediaBrowser.Server.Implementations.Library LazyInitializer.EnsureInitialized(ref _libraryItemsCache, ref _libraryItemsCacheInitialized, ref _libraryItemsCacheSyncLock, CreateLibraryItemsCache); return _libraryItemsCache; } - set - { - _libraryItemsCache = value; - - if (value == null) - { - _libraryItemsCacheInitialized = false; - } - } } /// @@ -756,26 +747,6 @@ namespace MediaBrowser.Server.Implementations.Library await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false); } - /// - /// Saves display preferences for a Folder - /// - /// The user. - /// The folder. - /// The data. - /// Task. - public Task SaveDisplayPreferencesForFolder(User user, Folder folder, DisplayPreferences data) - { - // Need to update all items with the same DisplayPreferencesId - foreach (var child in RootFolder.GetRecursiveChildren(user) - .OfType() - .Where(i => i.DisplayPreferencesId == folder.DisplayPreferencesId)) - { - child.AddOrUpdateDisplayPreferences(user, data); - } - - return Kernel.DisplayPreferencesRepository.SaveDisplayPreferences(folder, CancellationToken.None); - } - /// /// Gets the default view. /// diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 49b2a3f18..b17f2955e 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -1,10 +1,12 @@ -using MediaBrowser.Common.Events; +using System.Collections.Concurrent; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Connectivity; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -97,6 +99,11 @@ namespace MediaBrowser.Server.Implementations.Library /// The configuration manager. private IServerConfigurationManager ConfigurationManager { get; set; } + /// + /// The _user data + /// + private readonly ConcurrentDictionary> _displayPreferences = new ConcurrentDictionary>(); + /// /// Initializes a new instance of the class. /// @@ -156,6 +163,62 @@ namespace MediaBrowser.Server.Implementations.Library } #endregion + /// + /// Gets the display preferences. + /// + /// The user id. + /// The display preferences id. + /// DisplayPreferences. + public Task GetDisplayPreferences(Guid userId, Guid displayPreferencesId) + { + var key = userId + displayPreferencesId.ToString(); + + return _displayPreferences.GetOrAdd(key, keyName => RetrieveDisplayPreferences(userId, displayPreferencesId)); + } + + /// + /// Retrieves the display preferences. + /// + /// The user id. + /// The display preferences id. + /// DisplayPreferences. + private async Task RetrieveDisplayPreferences(Guid userId, Guid displayPreferencesId) + { + var displayPreferences = await Kernel.Instance.DisplayPreferencesRepository.GetDisplayPreferences(userId, displayPreferencesId).ConfigureAwait(false); + + return displayPreferences ?? new DisplayPreferences(); + } + + /// + /// Saves display preferences for an item + /// + /// The user id. + /// The display preferences id. + /// The display preferences. + /// The cancellation token. + /// Task. + public async Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, CancellationToken cancellationToken) + { + var key = userId + displayPreferencesId.ToString(); + var newValue = Task.FromResult(displayPreferences); + + try + { + await Kernel.Instance.DisplayPreferencesRepository.SaveDisplayPreferences(userId, displayPreferencesId, + displayPreferences, + cancellationToken).ConfigureAwait(false); + + // Once it succeeds, put it into the dictionary to make it available to everyone else + _displayPreferences.AddOrUpdate(key, newValue, delegate { return newValue; }); + } + catch (Exception ex) + { + _logger.ErrorException("Error saving display preferences", ex); + + throw; + } + } + /// /// Gets a User by Id /// @@ -711,6 +774,5 @@ namespace MediaBrowser.Server.Implementations.Library return Kernel.UserDataRepository.SaveUserData(item, CancellationToken.None); } - } } diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs index baa38cde0..44674e125 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs @@ -1,11 +1,9 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; using System; -using System.Collections.Generic; using System.Data; using System.IO; using System.Threading; @@ -80,8 +78,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite string[] queries = { - "create table if not exists display_prefs (item_id GUID, user_id GUID, data BLOB)", - "create unique index if not exists idx_display_prefs on display_prefs (item_id, user_id)", + "create table if not exists displaypreferences (id GUID, userId GUID, data BLOB)", + "create unique index if not exists displaypreferencesindex on displaypreferences (id, userId)", "create table if not exists schema_version (table_name primary key, version)", //pragmas "pragma temp_store = memory" @@ -93,82 +91,87 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// /// Save the display preferences associated with an item in the repo /// - /// The item. + /// The user id. + /// The display preferences id. + /// The display preferences. /// The cancellation token. /// Task. /// item - public Task SaveDisplayPreferences(Folder item, CancellationToken cancellationToken) + public Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, CancellationToken cancellationToken) { - if (item == null) + if (displayPreferences == null) { - throw new ArgumentNullException("item"); + throw new ArgumentNullException("displayPreferences"); } - if (cancellationToken == null) { throw new ArgumentNullException("cancellationToken"); } + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } + if (displayPreferencesId == Guid.Empty) + { + throw new ArgumentNullException("displayPreferencesId"); + } cancellationToken.ThrowIfCancellationRequested(); - + return Task.Run(() => { - var cmd = connection.CreateCommand(); + var serialized = _protobufSerializer.SerializeToBytes(displayPreferences); - cmd.CommandText = "delete from display_prefs where item_id = @guid"; - cmd.AddParam("@guid", item.DisplayPreferencesId); + cancellationToken.ThrowIfCancellationRequested(); + var cmd = connection.CreateCommand(); + cmd.CommandText = "replace into displaypreferences (id, userId, data) values (@1, @2, @3)"; + cmd.AddParam("@1", displayPreferencesId); + cmd.AddParam("@2", userId); + cmd.AddParam("@3", serialized); QueueCommand(cmd); - - if (item.DisplayPreferences != null) - { - foreach (var data in item.DisplayPreferences) - { - cmd = connection.CreateCommand(); - cmd.CommandText = "insert into display_prefs (item_id, user_id, data) values (@1, @2, @3)"; - cmd.AddParam("@1", item.DisplayPreferencesId); - cmd.AddParam("@2", data.UserId); - - cmd.AddParam("@3", _protobufSerializer.SerializeToBytes(data)); - - QueueCommand(cmd); - } - } }); } /// - /// Gets display preferences for an item + /// Gets the display preferences. /// - /// The item. - /// IEnumerable{DisplayPreferences}. - /// - public IEnumerable RetrieveDisplayPreferences(Folder item) + /// The user id. + /// The display preferences id. + /// Task{DisplayPreferences}. + /// item + public async Task GetDisplayPreferences(Guid userId, Guid displayPreferencesId) { - if (item == null) + if (userId == Guid.Empty) + { + throw new ArgumentNullException("userId"); + } + if (displayPreferencesId == Guid.Empty) { - throw new ArgumentNullException("item"); + throw new ArgumentNullException("displayPreferencesId"); } var cmd = connection.CreateCommand(); - cmd.CommandText = "select data from display_prefs where item_id = @guid"; - var guidParam = cmd.Parameters.Add("@guid", DbType.Guid); - guidParam.Value = item.DisplayPreferencesId; + cmd.CommandText = "select data from displaypreferences where id = @id and userId=@userId"; + + var idParam = cmd.Parameters.Add("@id", DbType.Guid); + idParam.Value = displayPreferencesId; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + var userIdParam = cmd.Parameters.Add("@userId", DbType.Guid); + userIdParam.Value = userId; + + using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow).ConfigureAwait(false)) { - while (reader.Read()) + if (reader.Read()) { using (var stream = GetStream(reader, 0)) { - var data = _protobufSerializer.DeserializeFromStream(stream); - if (data != null) - { - yield return data; - } + return _protobufSerializer.DeserializeFromStream(stream); } } } + + return null; } } } -- cgit v1.2.3