/// <summary> /// Loads stateful entities. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="category">The category.</param> /// <param name="stateCategory">The state category.</param> /// <param name="kind">The reactive entity kind.</param> /// <param name="onLoading">The function is called for each loading entity.</param> /// <param name="onError">Function to report an error.</param> /// <param name="blobLogger">The blob logger to write raw recovery blobs to.</param> /// <param name="token">Cancellation token.</param> private void LoadStatefulEntities <TEntity>( string category, string stateCategory, ReactiveEntityKind kind, Action <TEntity, Stream> onLoading, Action <string, TEntity, Exception> onError, BlobLogger blobLogger, CancellationToken token) where TEntity : ReactiveEntity { Debug.Assert(!string.IsNullOrEmpty(stateCategory), "Category should not be null or empty."); Debug.Assert(onLoading != null, "onLoading should not be null."); LoadDefinitions <TEntity>(category, kind, entity => { var key = entity.Uri.ToCanonicalString(); var stopwatch = Stopwatch.StartNew(); if (!_reader.TryGetItemReader(stateCategory, key, out Stream stateStream)) { // Stateless entity, i.e. no state has been written yet. // At the very least, there will always be a header if anything has been written. stateStream = null; } else { entity.SetMetric(EntityMetric.ReadState, stopwatch.Elapsed); blobLogger.Append(stateCategory, key, stateStream); } using (stateStream) // notice null is fine for a C# using statement { try { onLoading(entity, stateStream); } catch (MitigationBailOutException) { throw; } catch (Exception ex) { _engine.Parent.TraceSource.Recovery_LoadingStateFailure(_engine.Parent.Uri, category, stateCategory, key, ex.Message); throw; } } }, onError, blobLogger, token); }
/// <summary> /// Gets an item reader for the specified <paramref name="category"/> and <paramref name="key"/>. /// </summary> /// <param name="reader">The reader to obtain the item reader from.</param> /// <param name="category">The category of the item to get a reader for.</param> /// <param name="key">The key of the item to get a reader for.</param> /// <returns>A <see cref="Stream"/> that can be used to read the item.</returns> /// <exception cref="InvalidOperationException">An item with the specified <paramref name="category"/> and <paramref name="key"/> does not exist.</exception> public static Stream GetItemReader(this IStateReader reader, string category, string key) { if (!reader.TryGetItemReader(category, key, out var stream)) { throw new InvalidOperationException(FormattableString.Invariant($"Failed to load '{category}/{key}'.")); } return(stream); }
public void InMemoryStorageBasicWritingReadingTest() { InMemoryStorageProvider provider = new InMemoryStorageProvider(); string category = "someCategory"; string itemKey = "someItem"; string id = "someId"; byte[] buffer1 = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; byte[] buffer2 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; byte[][] buffers = new byte[][] { buffer1, buffer2 }; for (int i = 0; i < 2; i++) { byte[] expectedBuffer = buffers[i]; using (IStateWriter writer = i == 0 ? provider.StartNewCheckpoint(id) : provider.UpdateCheckpoint(id)) { using (Stream stream = writer.GetItemWriter(category, itemKey)) { stream.Write(expectedBuffer, 0, expectedBuffer.Length); } writer.CommitAsync().Wait(); } IStateReader reader = null; try { if (provider.TryReadCheckpoint(out id, out reader)) { bool success = reader.TryGetItemReader(category, itemKey, out var stream); Assert.IsTrue(success, "Could not get a reader for the requested item."); Assert.AreEqual(expectedBuffer.Length, stream.Length); byte[] actualBuffer = new byte[expectedBuffer.Length]; int byteRead = stream.Read(actualBuffer, 0, actualBuffer.Length); Assert.AreEqual(byteRead, stream.Length); CollectionAssert.AreEqual(expectedBuffer, actualBuffer); } } finally { reader?.Dispose(); } } }
public bool TryGetItemReader(string category, string key, out Stream stream) { LogStart(nameof(TryGetItemReader), category, key); try { return(_reader.TryGetItemReader(category, key, out stream)); } catch (Exception ex) when(LogError(nameof(TryGetItemReader), ex, category, key)) { throw; } finally { LogStop(nameof(TryGetItemReader), category, key); } }
/// <summary> /// Get a stream to read the state of the item specified by the provided category and key. /// </summary> /// <param name="category">Category of the item to read state for.</param> /// <param name="key">Key of the item to read state for.</param> /// <param name="stream">Stream to read that state of the item from.</param> /// <returns><b>true</b> if the category and item key exists; otherwise, <b>false</b>.</returns> /// <exception cref="EngineUnloadedException">The request is rejected because the engine has been unloaded.</exception> /// <exception cref="ObjectDisposedException">The reader has been disposed.</exception> public bool TryGetItemReader(string category, string key, out Stream stream) { CheckAccess(); return(_reader.TryGetItemReader(category, key, out stream)); }
/// <summary> /// Gets an item reader for the persisted entity state in the specified <paramref name="category"/> and with the specified <paramref name="key"/>. /// </summary> /// <param name="category">The category of the persisted entity state to read from.</param> /// <param name="key">The key of the persisted entity state to read from.</param> /// <param name="stream">The <see cref="Stream"/> used to read the item.</param> /// <returns><c>true</c> if an item with th specified <paramref name="category"/> and <paramref name="key"/> was found; otherwise, <c>false</c>.</returns> public bool TryGetItemReader(string category, string key, out Stream stream) => _reader.TryGetItemReader(_prefix + category, key, out stream);
public void InMemoryStorageItemDeletionTest() { InMemoryStorageProvider provider = new InMemoryStorageProvider(); string category = "someCategory"; string itemKey = "someItem"; string id = "someId"; byte[] buffer = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; using (IStateWriter writer = provider.StartNewCheckpoint(id)) { using (Stream stream = writer.GetItemWriter(category, itemKey)) { stream.Write(buffer, 0, buffer.Length); } writer.CommitAsync().Wait(); } IStateReader reader = null; try { if (provider.TryReadCheckpoint(out id, out reader)) { bool success = reader.TryGetItemReader(category, itemKey, out _); Assert.IsTrue(success, "An stream could not be retrieved for the requested item."); } else { Assert.Fail("Could not retrieve the checkpoint."); } } finally { reader?.Dispose(); } using (IStateWriter writer = provider.UpdateCheckpoint(id)) { writer.DeleteItem(category, itemKey); writer.CommitAsync().Wait(); } reader = null; try { if (provider.TryReadCheckpoint(out id, out reader)) { bool success = reader.TryGetItemReader(category, itemKey, out _); Assert.IsFalse(success, "An stream could be retrieved for the requested item."); } else { Assert.Fail("Could not retrieve the checkpoint."); } } finally { reader?.Dispose(); } }