/// <summary> /// Updates data from the specified <see cref="LogTableRecord" /> into the table designated by the <see cref="LogTableDefinition" />. /// </summary> /// <param name="table">The <see cref="LogTableDefinition" />.</param> /// <param name="record">The <see cref="LogTableRecord" />.</param> /// <returns><c>true</c> if submission was successful, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="table" /> is null. /// <para>or</para> /// <paramref name="record" /> is null. /// </exception> public bool Update(LogTableDefinition table, LogTableRecord record) { if (table == null) { throw new ArgumentNullException(nameof(table)); } if (record == null) { throw new ArgumentNullException(nameof(record)); } LogTrace($"UPDATE request received for {table.Name} (primary key = {record[table.PrimaryKey]})"); DataLogDatabaseResult result = _writer.Update(table, record); bool updateSuccessful = result.Success; // If the operation failed, try the alternate (if one exists) if (!updateSuccessful && _alternateWriter != null) { LogTrace($"UPDATE failed. Attempting update to alternate database."); DataLogDatabaseResult alternateResult = _alternateWriter.Update(table, record); updateSuccessful = alternateResult.Success; } // If the operation hasn't succeeded, check to see if we should add this to the cache. if (!updateSuccessful) { _cache?.Add(table, record, false); } return(updateSuccessful); }
public DataLogDatabaseResult Insert(LogTableDefinition table, LogTableRecord record) { if (table == null) { throw new ArgumentNullException(nameof(table)); } if (record == null) { throw new ArgumentNullException(nameof(record)); } LogTrace($"INSERT {table.Name} (primary key = {record[table.PrimaryKey]})"); DataLogDatabaseResult result; using (SqlCommand insert = DataLogSqlBuilder.BuildInsert(table, record)) { result = new DataLogDatabaseResult(table.Name, insert); try { using (SqlConnection connection = new SqlConnection(_connectionString.ToString())) { connection.Open(); insert.Connection = connection; try { insert.ExecuteNonQuery(); } catch (SqlException ex) when(ex.Message.Contains("Invalid object")) { // Table doesn't exist - create it and try again LogDebug($"Generating new table {table.Name}"); if (CreateTable(connection, table)) { LogDebug($"Table {table.Name} created."); LogTrace($"Retrying INSERT {table.Name}"); insert.ExecuteNonQuery(); } } } } catch (Exception ex) { result.Error = ex.Message; } } if (!result.Success) { LogWarn($"INSERT {table.Name} failed: {result.Error}"); LogTrace($"SQL command: " + result.Command); LogTrace($"SQL parameters: {string.Join("; ", result.Parameters.Select(n => $"{n.Key}={n.Value}"))}"); } return(result); }
public DataLogDatabaseResult Update(LogTableDefinition table, LogTableRecord record) { if (table == null) { throw new ArgumentNullException(nameof(table)); } if (record == null) { throw new ArgumentNullException(nameof(record)); } LogTrace($"UPDATE {table.Name} (primary key = {record[table.PrimaryKey]})"); DataLogDatabaseResult result; using (SqlCommand update = DataLogSqlBuilder.BuildUpdate(table, record)) { result = new DataLogDatabaseResult(table.Name, update); try { using (SqlConnection connection = new SqlConnection(_connectionString.ToString())) { connection.Open(); update.Connection = connection; int affectedRows = update.ExecuteNonQuery(); if (affectedRows == 0) { result.Error = "No rows were affected."; } } } catch (Exception ex) { result.Error = ex.Message; } } if (!result.Success) { LogWarn($"UPDATE {table.Name} failed: {result.Error}"); LogTrace($"SQL command: " + result.Command); LogTrace($"SQL parameters: {string.Join("; ", result.Parameters.Select(n => $"{n.Key}={n.Value}"))}"); } return(result); }
/// <summary> /// Inserts data from the specified <see cref="LogTableRecord" /> into the table designated by the <see cref="LogTableDefinition" />. /// </summary> /// <param name="table">The <see cref="LogTableDefinition" />.</param> /// <param name="record">The <see cref="LogTableRecord" />.</param> /// <returns><c>true</c> if submission was successful, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="table" /> is null. /// <para>or</para> /// <paramref name="record" /> is null. /// </exception> public bool Insert(LogTableDefinition table, LogTableRecord record) { if (table == null) { throw new ArgumentNullException(nameof(table)); } if (record == null) { throw new ArgumentNullException(nameof(record)); } LogTrace($"INSERT request received for {table.Name} (primary key = {record[table.PrimaryKey]})"); DataLogDatabaseResult result = _writer.Insert(table, record); bool insertSuccessful = result.Success; // If the operation failed, try the alternate (if one exists) if (!insertSuccessful && _alternateWriter != null) { LogTrace($"INSERT failed. Attempting insert to alternate database."); DataLogDatabaseResult alternateResult = _alternateWriter.Insert(table, record); insertSuccessful = alternateResult.Success; } // If the operation hasn't succeeded, check to see if we should add this to the cache. if (!insertSuccessful && _cache != null) { if (result.Error.Contains("Violation of PRIMARY KEY constraint", StringComparison.OrdinalIgnoreCase)) { // Bypass the cache for primary key violations result.Retries = -1; CacheOperationsRetried?.Invoke(this, new DataLogCacheEventArgs(new[] { result })); } else { _cache.Add(table, record, true); } } return(insertSuccessful); }
public IEnumerable <DataLogDatabaseResult> RetryFromCache() { if (!Directory.Exists(_cacheLocation.FullName)) { return(Enumerable.Empty <DataLogDatabaseResult>()); } // Ignore files that have exceeded the maximum retry time. DateTime cutoff = DateTime.Now - _maximumRetryTime; bool loggedStart = false; int fileErrors = 0; List <DataLogDatabaseResult> results = new List <DataLogDatabaseResult>(); foreach (FileInfo file in _cacheLocation.EnumerateFiles("*.xml").Where(n => n.CreationTime > cutoff).OrderBy(n => n.CreationTime)) { if (!loggedStart) { LogDebug("Retrying from cache..."); loggedStart = true; } try { LogTrace($"Reading cache file {file.Name}"); DataLogCacheData data = ReadCacheData(file); data.Retries++; DataLogDatabaseResult result = data.IsInsert ? _databaseWriter.Insert(data.Table, data.Record) : _databaseWriter.Update(data.Table, data.Record); bool operationSuccessful = result.Success; if (!operationSuccessful && _alternateWriter != null) { DataLogDatabaseResult alternateResult = data.IsInsert ? _alternateWriter.Insert(data.Table, data.Record) : _alternateWriter.Update(data.Table, data.Record); operationSuccessful = alternateResult.Success; } if (operationSuccessful) { LogTrace($"Cache operation successful. Deleting file {file.Name}."); try { Retry.WhileThrowing <IOException>(() => file.Delete(), 5, TimeSpan.FromSeconds(1)); } catch (IOException ex) { LogDebug($"File {file.Name} could not be deleted: {ex.Message}"); } } else { LogTrace($"Cache operation failed. {file.Name} has been retried {data.Retries} times."); WriteCacheData(file, data); } result.Retries = data.Retries; results.Add(result); } catch (Exception ex) { // Do nothing - could be a fluke, or a file that we can't read LogTrace($"Unknown error: {ex.Message}"); fileErrors++; } } if (results.Any()) { LogDebug($"Cache retry results: {results.Count(n => n.Success)} succeeded, {results.Count(n => !n.Success)} failed, {fileErrors} cache errors."); } return(results); }