public async Task <bool> Commit <TDataType>(int id) where TDataType : DataEntity { using (_logger.BeginScope("{Operation} is {Action} {DataType} with Id ({Id})", nameof(FileDataWorker), "commiting data", typeof(TDataType).Name, id)) { var filename = GetFileName <TDataType>(id); var maxAttempts = MaxAttempts <TDataType>(); _logger.LogTrace("Will try to write to {filename} {MaxAttempts} times", filename, maxAttempts); var attempts = 0; while (attempts < maxAttempts) { attempts++; _logger.LogTrace("Attempt number {Attempt}", attempts); try { if (await FileStreamer.CloseStream(filename)) { _logger.LogInformation("Closed the file and committed the data to disk"); await FileStreamer.UnlockFile(filename); return(true); } } catch (Exception exception) { _logger.LogWarning(exception, "Failed to commit data to disk as an error happened"); } } _logger.LogError("Failed to commit data to disk"); await DiscardChanges <TDataType>(id); return(false); } }
public async Task <bool> CloseStreamWhenThereIsNoStream() { var result = FileStreamer.CloseStream(Filename); MockWriteStream .Verify(x => x.Close(), Times.Never); MockReadStream .Verify(x => x.Close(), Times.Never); return(await result); }
public async Task <bool> CloseStreamWhenThereIsAWriteStream() { await FileStreamer.WriteDataToStream(Filename, Data); var result = FileStreamer.CloseStream(Filename); MockWriteStream .Verify(x => x.Close(), Times.Once); MockWriteStream .Verify(x => x.Dispose(), Times.Once); MockReadStream .Verify(x => x.Close(), Times.Never); MockReadStream .Verify(x => x.Dispose(), Times.Never); return(await result); }
public async Task <bool> CloseStreamWhenThereIsAReadStreamIsAlreadyClosed() { await FileStreamer.ReadDataFromStream <BasicData>(Filename); await FileStreamer.CloseStream(Filename); var result = FileStreamer.CloseStream(Filename); MockWriteStream .Verify(x => x.Close(), Times.Never); MockWriteStream .Verify(x => x.Dispose(), Times.Never); MockReadStream .Verify(x => x.Close(), Times.Once); MockReadStream .Verify(x => x.Dispose(), Times.Once); return(await result); }
public async Task <bool> CommitEvents <TDataType>(TDataType data) where TDataType : DataEntity { using (_logger.BeginScope("{Operation} is {Action} for {DataType}", nameof(FileAuditWorker), "committing events", typeof(TDataType).Name)) { var filename = GetFileName <TDataType>(data.Id); var maxAttempts = MaxAttempts <TDataType>(); _logger.LogTrace("Will try to write to {filename} {MaxAttempts} times", filename, maxAttempts >= 0 ? maxAttempts.ToString() : "until success"); var attempts = 0; while (maxAttempts == -1 || attempts < maxAttempts) { attempts++; _logger.LogTrace("Attempt number {Attempt}", attempts); try { _logger.LogTrace("Closing audit file"); if (await FileStreamer.CloseStream(filename)) { _logger.LogTrace("Closed audit file"); await FileStreamer.UnlockFile(filename); _logger.LogInformation("Committed audit to file"); return(true); } _logger.LogWarning("Failed to close audit file"); } catch (Exception exception) { _logger.LogWarning(exception, "Failed to commit audit"); } } await DiscardEvents(data); _logger.LogWarning("Discarded events after max attempts trying to commit audit"); return(false); } }
public async Task <bool> Unindex <TDataType>(TDataType data) where TDataType : DataEntity { using (_logger.BeginScope("{Operation} is {Action} for {DataType}", nameof(FileIndexWorker), "unindexing", typeof(TDataType).Name)) { var indexProperties = typeof(TDataType) .GetProperties() .Where(x => x.GetCustomAttributes(typeof(IndexAttribute), true).Any()) .ToArray(); if (!indexProperties.Any()) { _logger.LogTrace("There are no properties are indexed"); return(true); } _logger.LogInformation("Starting to unindex"); var unindexSuccess = true; foreach (var indexProperty in indexProperties) { var indexName = indexProperty.Name; _logger.LogTrace("Unindexing {IndexName}", indexName); if (await IndexExist <TDataType>(indexName)) { _logger.LogTrace("Index exists"); var indexFileName = GetFileName <TDataType>(indexName); using (_logger.BeginScope("The index file {filename} will be used", indexFileName)) { var index = await FileStreamer.ReadDataFromStream <Index <object> >(indexFileName); _logger.LogTrace("Loaded index data"); if (index.Keys is null) { _logger.LogWarning("There are no keys in the index"); continue; } var keys = index.Keys .Where(x => x.Ids.Any(y => y == data.Id)) .ToArray(); if (!keys.Any()) { _logger.LogInformation("There where no keys with the data's Id indexes against it."); continue; } foreach (var key in keys) { key.Ids.Remove(data.Id); _logger.LogTrace("Removed id from index key"); if (!key.Ids.Any()) { index.Keys.Remove(key); _logger.LogTrace("No more ids against the key removed the key from the index"); } } if (index.Keys.Any()) { _logger.LogTrace("The index still has some keys"); if (await FileStreamer.WriteDataToStream(indexFileName, index)) { _logger.LogTrace("Successfully wrote index to the index file"); if (!await FileStreamer.CloseStream(indexFileName)) { _logger.LogWarning("Failed to save the index to disk"); unindexSuccess = false; } else { _logger.LogInformation("Index updated"); } } else { _logger.LogWarning("Failed to write data to the file"); unindexSuccess = false; } } else { _logger.LogTrace("No more keys in the index"); if (!await FileStreamer.Delete(indexFileName)) { _logger.LogWarning("Failed to remove index file"); unindexSuccess = false; } else { _logger.LogInformation("Removed index file"); } } } } else { _logger.LogTrace("Index doesn't exist"); } } if (unindexSuccess) { _logger.LogInformation("Unindex data successfully"); } else { _logger.LogWarning("Failed to unindex data"); } return(unindexSuccess); } }
public async Task <bool> Index <TDataType>(TDataType data) where TDataType : DataEntity { using (_logger.BeginScope("{Operation} is {Action} for {DataType}", nameof(FileIndexWorker), "indexing", typeof(TDataType).Name)) { var indexProperties = typeof(TDataType) .GetProperties() .Where(x => x.GetCustomAttributes(typeof(IndexAttribute), true).Any()) .ToArray(); if (!indexProperties.Any()) { _logger.LogTrace("There are no properties to index"); return(true); } _logger.LogInformation("Starting to index"); var indexSuccess = true; foreach (var indexProperty in indexProperties) { var indexName = indexProperty.Name; _logger.LogTrace("Indexing into {IndexName}", indexName); Index <object> index; var indexKey = indexProperty.GetValue(data); var indexFileName = GetFileName <TDataType>(indexName); using (_logger.BeginScope("The index file {filename} will be used", indexFileName)) { var hasChanges = false; if (await IndexExist <TDataType>(indexName)) { _logger.LogTrace("Index exists"); index = await FileStreamer.ReadDataFromStream <Index <object> >(indexFileName); _logger.LogTrace("Loaded index data"); var otherKeys = index.Keys .Where(x => ( (x.Value is null && indexKey != null) || (indexKey is null && x.Value != null) || ( x.Value is null || !x.Value.Equals(indexKey) ) ) && x.Ids.Any(y => y == data.Id) ) .ToArray(); if (otherKeys.Any()) { _logger.LogTrace("The index key for the data has changed"); hasChanges = true; } foreach (var otherKey in otherKeys) { otherKey.Ids.Remove(data.Id); _logger.LogTrace("Removed old index key"); } var key = index.Keys.FirstOrDefault(x => (x.Value is null && indexKey is null) || (x.Value != null && x.Value.Equals(indexKey))); if (key is null) { _logger.LogTrace("Index key doesn't already exist"); index.Keys.Add(new IndexKey <object> { Value = indexKey, Ids = new[] { data.Id } }); hasChanges = true; } else { _logger.LogTrace("Index key already exists"); if (indexProperty.GetCustomAttributes(typeof(IndexAttribute), true) .OfType <IndexAttribute>().Any(x => x.IsUnique) && key.Ids.Any() && key.Ids.All(x => x != data.Id)) { _logger.LogError("Unable to index data as unique index would be invalidated"); indexSuccess = false; hasChanges = false; } else { if (key.Ids.All(x => x != data.Id)) { _logger.LogTrace("Added id to index key"); key.Ids.Add(data.Id); hasChanges = true; } } } } else { _logger.LogTrace("Creating {IndexName}", indexName); index = new Index <object> { Keys = new List <IndexKey <object> > { new IndexKey <object> { Value = indexKey, Ids = new List <int> { data.Id } } } }; hasChanges = true; } if (hasChanges) { _logger.LogTrace("There are changes to the index"); if (await FileStreamer.WriteDataToStream(indexFileName, index)) { _logger.LogTrace("Wrote changes to index file"); if (!await FileStreamer.CloseStream(indexFileName)) { _logger.LogWarning("Failed to commit data to the disk"); indexSuccess = false; } else { _logger.LogInformation("Saved changes to index"); } } else { _logger.LogWarning("Failed to write data to the disk"); indexSuccess = false; } } } } if (indexSuccess) { _logger.LogInformation("Indexed data successfully"); } else { _logger.LogWarning("Failed to index data"); } return(indexSuccess); } }