diff options
| author | Techywarrior <techywarrior@gmail.com> | 2013-04-05 19:45:32 -0700 |
|---|---|---|
| committer | Techywarrior <techywarrior@gmail.com> | 2013-04-05 19:45:32 -0700 |
| commit | 51b71afd5cfcaa6db606073a24c4c891cdf46cb3 (patch) | |
| tree | b801589b7e167125b7fae7add6b9a914daeeaa10 /MediaBrowser.Server.Implementations | |
| parent | 7c3f257581344aadf6f697f3159becbd613db7e2 (diff) | |
| parent | 9c7f492e2cd3b940d8041e6949cea9898a057826 (diff) | |
Merge branch 'master' of https://github.com/MediaBrowser/MediaBrowser
Diffstat (limited to 'MediaBrowser.Server.Implementations')
8 files changed, 287 insertions, 162 deletions
diff --git a/MediaBrowser.Server.Implementations/Library/DisplayPreferencesManager.cs b/MediaBrowser.Server.Implementations/Library/DisplayPreferencesManager.cs new file mode 100644 index 000000000..57a9c9d78 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/DisplayPreferencesManager.cs @@ -0,0 +1,99 @@ +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Logging; +using System; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Library +{ + /// <summary> + /// Class DisplayPreferencesManager + /// </summary> + public class DisplayPreferencesManager : IDisplayPreferencesManager + { + /// <summary> + /// The _logger + /// </summary> + private readonly ILogger _logger; + + /// <summary> + /// The _display preferences + /// </summary> + private readonly ConcurrentDictionary<Guid, Task<DisplayPreferences>> _displayPreferences = new ConcurrentDictionary<Guid, Task<DisplayPreferences>>(); + + /// <summary> + /// Gets the active user repository + /// </summary> + /// <value>The display preferences repository.</value> + public IDisplayPreferencesRepository Repository { get; set; } + + /// <summary> + /// Initializes a new instance of the <see cref="DisplayPreferencesManager"/> class. + /// </summary> + /// <param name="logger">The logger.</param> + public DisplayPreferencesManager(ILogger logger) + { + _logger = logger; + } + + /// <summary> + /// Gets the display preferences. + /// </summary> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <returns>DisplayPreferences.</returns> + public Task<DisplayPreferences> GetDisplayPreferences(Guid displayPreferencesId) + { + return _displayPreferences.GetOrAdd(displayPreferencesId, keyName => RetrieveDisplayPreferences(displayPreferencesId)); + } + + /// <summary> + /// Retrieves the display preferences. + /// </summary> + /// <param name="displayPreferencesId">The display preferences id.</param> + /// <returns>DisplayPreferences.</returns> + private async Task<DisplayPreferences> RetrieveDisplayPreferences(Guid displayPreferencesId) + { + var displayPreferences = await Repository.GetDisplayPreferences(displayPreferencesId).ConfigureAwait(false); + + return displayPreferences ?? new DisplayPreferences { Id = displayPreferencesId }; + } + + /// <summary> + /// Saves display preferences for an item + /// </summary> + /// <param name="displayPreferences">The display preferences.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + public async Task SaveDisplayPreferences(DisplayPreferences displayPreferences, CancellationToken cancellationToken) + { + if (displayPreferences == null) + { + throw new ArgumentNullException("displayPreferences"); + } + if (displayPreferences.Id == Guid.Empty) + { + throw new ArgumentNullException("displayPreferences.Id"); + } + + try + { + await Repository.SaveDisplayPreferences(displayPreferences, + cancellationToken).ConfigureAwait(false); + + var newValue = Task.FromResult(displayPreferences); + + // Once it succeeds, put it into the dictionary to make it available to everyone else + _displayPreferences.AddOrUpdate(displayPreferences.Id, newValue, delegate { return newValue; }); + } + catch (Exception ex) + { + _logger.ErrorException("Error saving display preferences", ex); + + throw; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index c5e4de2bc..9293d8199 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -5,7 +5,6 @@ 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.Concurrent; @@ -26,8 +25,8 @@ namespace MediaBrowser.Server.Implementations.Library /// <summary> /// The _active connections /// </summary> - private readonly List<ClientConnectionInfo> _activeConnections = - new List<ClientConnectionInfo>(); + private readonly ConcurrentDictionary<string, ClientConnectionInfo> _activeConnections = + new ConcurrentDictionary<string, ClientConnectionInfo>(StringComparer.OrdinalIgnoreCase); /// <summary> /// The _users @@ -70,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.Library /// <value>All connections.</value> public IEnumerable<ClientConnectionInfo> AllConnections { - get { return _activeConnections.Where(c => GetUserById(c.UserId) != null).OrderByDescending(c => c.LastActivityDate); } + get { return _activeConnections.Values.OrderByDescending(c => c.LastActivityDate); } } /// <summary> @@ -99,11 +98,6 @@ namespace MediaBrowser.Server.Implementations.Library /// <value>The configuration manager.</value> private IServerConfigurationManager ConfigurationManager { get; set; } - /// <summary> - /// The _user data - /// </summary> - private readonly ConcurrentDictionary<string, Task<DisplayPreferences>> _displayPreferences = new ConcurrentDictionary<string, Task<DisplayPreferences>>(); - private readonly ConcurrentDictionary<string, Task<UserItemData>> _userData = new ConcurrentDictionary<string, Task<UserItemData>>(); /// <summary> @@ -166,63 +160,6 @@ namespace MediaBrowser.Server.Implementations.Library #endregion /// <summary> - /// Gets the display preferences. - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="displayPreferencesId">The display preferences id.</param> - /// <returns>DisplayPreferences.</returns> - public Task<DisplayPreferences> GetDisplayPreferences(Guid userId, Guid displayPreferencesId) - { - var key = userId + displayPreferencesId.ToString(); - - return _displayPreferences.GetOrAdd(key, keyName => RetrieveDisplayPreferences(userId, displayPreferencesId)); - } - - /// <summary> - /// Retrieves the display preferences. - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="displayPreferencesId">The display preferences id.</param> - /// <returns>DisplayPreferences.</returns> - private async Task<DisplayPreferences> RetrieveDisplayPreferences(Guid userId, Guid displayPreferencesId) - { - var displayPreferences = await Kernel.Instance.DisplayPreferencesRepository.GetDisplayPreferences(userId, displayPreferencesId).ConfigureAwait(false); - - return displayPreferences ?? new DisplayPreferences(); - } - - /// <summary> - /// Saves display preferences for an item - /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="displayPreferencesId">The display preferences id.</param> - /// <param name="displayPreferences">The display preferences.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - public async Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, CancellationToken cancellationToken) - { - var key = userId + displayPreferencesId.ToString(); - - try - { - await Kernel.Instance.DisplayPreferencesRepository.SaveDisplayPreferences(userId, displayPreferencesId, - displayPreferences, - cancellationToken).ConfigureAwait(false); - - var newValue = Task.FromResult(displayPreferences); - - // 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; - } - } - - /// <summary> /// Gets a User by Id /// </summary> /// <param name="id">The id.</param> @@ -232,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Library { if (id == Guid.Empty) { - throw new ArgumentNullException(); + throw new ArgumentNullException("id"); } return Users.FirstOrDefault(u => u.Id == id); @@ -376,29 +313,19 @@ namespace MediaBrowser.Server.Implementations.Library /// <returns>ClientConnectionInfo.</returns> private ClientConnectionInfo GetConnection(Guid userId, string clientType, string deviceId, string deviceName) { - lock (_activeConnections) - { - var conn = _activeConnections.FirstOrDefault(c => string.Equals(c.Client, clientType, StringComparison.OrdinalIgnoreCase) && string.Equals(deviceId, c.DeviceId)); - - if (conn == null) - { - conn = new ClientConnectionInfo - { - UserId = userId, - Client = clientType, - DeviceName = deviceName, - DeviceId = deviceId - }; + var key = clientType + deviceId; - _activeConnections.Add(conn); - } - else - { - conn.UserId = userId; - } + var connection = _activeConnections.GetOrAdd(key, keyName => new ClientConnectionInfo + { + UserId = userId, + Client = clientType, + DeviceName = deviceName, + DeviceId = deviceId + }); - return conn; - } + connection.UserId = userId; + + return connection; } /// <summary> @@ -802,11 +729,11 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> - /// Gets the display preferences. + /// Gets the user data. /// </summary> /// <param name="userId">The user id.</param> /// <param name="userDataId">The user data id.</param> - /// <returns>Task{DisplayPreferences}.</returns> + /// <returns>Task{UserItemData}.</returns> public Task<UserItemData> GetUserData(Guid userId, Guid userDataId) { var key = userId + userDataId.ToString(); @@ -815,11 +742,11 @@ namespace MediaBrowser.Server.Implementations.Library } /// <summary> - /// Retrieves the display preferences. + /// Retrieves the user data. /// </summary> /// <param name="userId">The user id.</param> /// <param name="userDataId">The user data id.</param> - /// <returns>DisplayPreferences.</returns> + /// <returns>Task{UserItemData}.</returns> private async Task<UserItemData> RetrieveUserData(Guid userId, Guid userDataId) { var userdata = await Kernel.Instance.UserDataRepository.GetUserData(userId, userDataId).ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 043ef0845..f2593f1c5 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -130,6 +130,7 @@ <Compile Include="HttpServer\SwaggerService.cs" /> <Compile Include="IO\DirectoryWatchers.cs" /> <Compile Include="Library\CoreResolutionIgnoreRule.cs" /> + <Compile Include="Library\DisplayPreferencesManager.cs" /> <Compile Include="Library\LibraryManager.cs" /> <Compile Include="Library\LuceneSearchEngine.cs" /> <Compile Include="Library\ResolverHelper.cs" /> diff --git a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs index dced1ce28..c34f8a1ba 100644 --- a/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs +++ b/MediaBrowser.Server.Implementations/Providers/ProviderManager.cs @@ -104,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Providers /// <param name="providers">The providers.</param> public void AddMetadataProviders(IEnumerable<BaseMetadataProvider> providers) { - MetadataProviders = providers.ToArray(); + MetadataProviders = providers.OrderBy(e => e.Priority).ToArray(); } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs index 8a15d4028..f471365ce 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteDisplayPreferencesRepository.cs @@ -34,6 +34,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite } /// <summary> + /// Gets a value indicating whether [enable delayed commands]. + /// </summary> + /// <value><c>true</c> if [enable delayed commands]; otherwise, <c>false</c>.</value> + protected override bool EnableDelayedCommands + { + get + { + return false; + } + } + + /// <summary> /// The _protobuf serializer /// </summary> private readonly IProtobufSerializer _protobufSerializer; @@ -78,8 +90,8 @@ namespace MediaBrowser.Server.Implementations.Sqlite string[] queries = { - "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 displaypreferences (id GUID, data BLOB)", + "create unique index if not exists displaypreferencesindex on displaypreferences (id)", "create table if not exists schema_version (table_name primary key, version)", //pragmas "pragma temp_store = memory" @@ -91,75 +103,77 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// <summary> /// Save the display preferences associated with an item in the repo /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="displayPreferencesId">The display preferences id.</param> /// <param name="displayPreferences">The display preferences.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException">item</exception> - public Task SaveDisplayPreferences(Guid userId, Guid displayPreferencesId, DisplayPreferences displayPreferences, CancellationToken cancellationToken) + public async Task SaveDisplayPreferences(DisplayPreferences displayPreferences, CancellationToken cancellationToken) { if (displayPreferences == null) { throw new ArgumentNullException("displayPreferences"); } - if (cancellationToken == null) - { - throw new ArgumentNullException("cancellationToken"); - } - if (userId == Guid.Empty) + if (displayPreferences.Id == Guid.Empty) { - throw new ArgumentNullException("userId"); + throw new ArgumentNullException("displayPreferences.Id"); } - if (displayPreferencesId == Guid.Empty) + if (cancellationToken == null) { - throw new ArgumentNullException("displayPreferencesId"); + throw new ArgumentNullException("cancellationToken"); } cancellationToken.ThrowIfCancellationRequested(); - - return Task.Run(() => + + var serialized = _protobufSerializer.SerializeToBytes(displayPreferences); + + cancellationToken.ThrowIfCancellationRequested(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = "replace into displaypreferences (id, data) values (@1, @2)"; + cmd.AddParam("@1", displayPreferences.Id); + cmd.AddParam("@2", serialized); + + using (var tran = connection.BeginTransaction()) { - var serialized = _protobufSerializer.SerializeToBytes(displayPreferences); + try + { + cmd.Transaction = tran; - cancellationToken.ThrowIfCancellationRequested(); + await cmd.ExecuteNonQueryAsync(cancellationToken); - 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); - }); + tran.Commit(); + } + catch (OperationCanceledException) + { + tran.Rollback(); + } + catch (Exception e) + { + Logger.ErrorException("Failed to commit transaction.", e); + tran.Rollback(); + } + } } /// <summary> /// Gets the display preferences. /// </summary> - /// <param name="userId">The user id.</param> /// <param name="displayPreferencesId">The display preferences id.</param> /// <returns>Task{DisplayPreferences}.</returns> /// <exception cref="System.ArgumentNullException">item</exception> - public async Task<DisplayPreferences> GetDisplayPreferences(Guid userId, Guid displayPreferencesId) + public async Task<DisplayPreferences> GetDisplayPreferences(Guid displayPreferencesId) { - if (userId == Guid.Empty) - { - throw new ArgumentNullException("userId"); - } if (displayPreferencesId == Guid.Empty) { throw new ArgumentNullException("displayPreferencesId"); } var cmd = connection.CreateCommand(); - cmd.CommandText = "select data from displaypreferences where id = @id and userId=@userId"; + cmd.CommandText = "select data from displaypreferences where id = @id"; var idParam = cmd.Parameters.Add("@id", DbType.Guid); idParam.Value = displayPreferencesId; - 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)) { if (reader.Read()) diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs index c5320a1f6..e722ac3dc 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteRepository.cs @@ -30,7 +30,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// <summary> /// The flush interval /// </summary> - private const int FlushInterval = 5000; + private const int FlushInterval = 2000; /// <summary> /// The flush timer @@ -44,6 +44,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite protected ILogger Logger { get; private set; } /// <summary> + /// Gets a value indicating whether [enable delayed commands]. + /// </summary> + /// <value><c>true</c> if [enable delayed commands]; otherwise, <c>false</c>.</value> + protected virtual bool EnableDelayedCommands + { + get + { + return true; + } + } + + /// <summary> /// Initializes a new instance of the <see cref="SqliteRepository" /> class. /// </summary> /// <param name="logManager">The log manager.</param> @@ -85,8 +97,11 @@ namespace MediaBrowser.Server.Implementations.Sqlite await connection.OpenAsync().ConfigureAwait(false); - // Run once - FlushTimer = new Timer(Flush, null, TimeSpan.FromMilliseconds(FlushInterval), TimeSpan.FromMilliseconds(-1)); + if (EnableDelayedCommands) + { + // Run once + FlushTimer = new Timer(Flush, null, TimeSpan.FromMilliseconds(FlushInterval), TimeSpan.FromMilliseconds(-1)); + } } /// <summary> @@ -147,16 +162,9 @@ namespace MediaBrowser.Server.Implementations.Sqlite { if (connection != null) { - // If we're not already flushing, do it now - if (!IsFlushing) - { - Flush(null); - } - - // Don't dispose in the middle of a flush - while (IsFlushing) + if (EnableDelayedCommands) { - Thread.Sleep(25); + FlushOnDispose(); } if (connection.IsOpen()) @@ -182,6 +190,24 @@ namespace MediaBrowser.Server.Implementations.Sqlite } /// <summary> + /// Flushes the on dispose. + /// </summary> + private void FlushOnDispose() + { + // If we're not already flushing, do it now + if (!IsFlushing) + { + Flush(null); + } + + // Don't dispose in the middle of a flush + while (IsFlushing) + { + Thread.Sleep(25); + } + } + + /// <summary> /// Queues the command. /// </summary> /// <param name="cmd">The CMD.</param> diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs index 2c8d7f437..b2e11d06f 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserDataRepository.cs @@ -35,6 +35,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite } /// <summary> + /// Gets a value indicating whether [enable delayed commands]. + /// </summary> + /// <value><c>true</c> if [enable delayed commands]; otherwise, <c>false</c>.</value> + protected override bool EnableDelayedCommands + { + get + { + return false; + } + } + + /// <summary> /// The _protobuf serializer /// </summary> private readonly IProtobufSerializer _protobufSerializer; @@ -106,7 +118,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// or /// userDataId /// </exception> - public Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) + public async Task SaveUserData(Guid userId, Guid userDataId, UserItemData userData, CancellationToken cancellationToken) { if (userData == null) { @@ -127,19 +139,36 @@ namespace MediaBrowser.Server.Implementations.Sqlite cancellationToken.ThrowIfCancellationRequested(); - return Task.Run(() => + var serialized = _protobufSerializer.SerializeToBytes(userData); + + cancellationToken.ThrowIfCancellationRequested(); + + var cmd = connection.CreateCommand(); + cmd.CommandText = "replace into userdata (id, userId, data) values (@1, @2, @3)"; + cmd.AddParam("@1", userDataId); + cmd.AddParam("@2", userId); + cmd.AddParam("@3", serialized); + + using (var tran = connection.BeginTransaction()) { - var serialized = _protobufSerializer.SerializeToBytes(userData); + try + { + cmd.Transaction = tran; - cancellationToken.ThrowIfCancellationRequested(); + await cmd.ExecuteNonQueryAsync(cancellationToken); - var cmd = connection.CreateCommand(); - cmd.CommandText = "replace into userdata (id, userId, data) values (@1, @2, @3)"; - cmd.AddParam("@1", userDataId); - cmd.AddParam("@2", userId); - cmd.AddParam("@3", serialized); - QueueCommand(cmd); - }); + tran.Commit(); + } + catch (OperationCanceledException) + { + tran.Rollback(); + } + catch (Exception e) + { + Logger.ErrorException("Failed to commit transaction.", e); + tran.Rollback(); + } + } } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs index 812c98789..f55b13d19 100644 --- a/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs +++ b/MediaBrowser.Server.Implementations/Sqlite/SQLiteUserRepository.cs @@ -46,6 +46,18 @@ namespace MediaBrowser.Server.Implementations.Sqlite private readonly IApplicationPaths _appPaths; /// <summary> + /// Gets a value indicating whether [enable delayed commands]. + /// </summary> + /// <value><c>true</c> if [enable delayed commands]; otherwise, <c>false</c>.</value> + protected override bool EnableDelayedCommands + { + get + { + return false; + } + } + + /// <summary> /// Initializes a new instance of the <see cref="SQLiteUserDataRepository" /> class. /// </summary> /// <param name="appPaths">The app paths.</param> @@ -97,7 +109,7 @@ namespace MediaBrowser.Server.Implementations.Sqlite /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException">user</exception> - public Task SaveUser(User user, CancellationToken cancellationToken) + public async Task SaveUser(User user, CancellationToken cancellationToken) { if (user == null) { @@ -109,20 +121,37 @@ namespace MediaBrowser.Server.Implementations.Sqlite throw new ArgumentNullException("cancellationToken"); } - return Task.Run(() => - { - cancellationToken.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); - var serialized = _jsonSerializer.SerializeToBytes(user); + var serialized = _jsonSerializer.SerializeToBytes(user); - cancellationToken.ThrowIfCancellationRequested(); + cancellationToken.ThrowIfCancellationRequested(); - var cmd = connection.CreateCommand(); - cmd.CommandText = "replace into users (guid, data) values (@1, @2)"; - cmd.AddParam("@1", user.Id); - cmd.AddParam("@2", serialized); - QueueCommand(cmd); - }); + var cmd = connection.CreateCommand(); + cmd.CommandText = "replace into users (guid, data) values (@1, @2)"; + cmd.AddParam("@1", user.Id); + cmd.AddParam("@2", serialized); + + using (var tran = connection.BeginTransaction()) + { + try + { + cmd.Transaction = tran; + + await cmd.ExecuteNonQueryAsync(cancellationToken); + + tran.Commit(); + } + catch (OperationCanceledException) + { + tran.Rollback(); + } + catch (Exception e) + { + Logger.ErrorException("Failed to commit transaction.", e); + tran.Rollback(); + } + } } /// <summary> |
