/// <summary> /// Creates a new instance of the <see cref="EntityNotFoundException"/> class with the specified information about the entity. /// </summary> /// <param name="uri">URI identifying the reactive entity that was not found.</param> /// <param name="type">Reactive entity kind.</param> /// <param name="qeId">URI identifier the query engine whose registry does not contain an entity with the specified URI.</param> /// <param name="paramName">Parameter name of the argument containing the URI of the entity that was not found.</param> public EntityNotFoundException(Uri uri, ReactiveEntityKind type, Uri qeId, string paramName) : base(GetMessage(uri, type, qeId), paramName) { QueryEngineUri = qeId; EntityUri = uri; EntityType = type; }
private void AddEntityPlaceholder(ReactiveEntityKind kind, string key) { var uri = new Uri(key); #pragma warning disable IDE0079 // Remove unnecessary suppression. #pragma warning disable CA2000 // Dispose objects before losing scope. (Entities are owned by the registry.) var added = kind switch { ReactiveEntityKind.Observable => Registry.Observables.TryAdd(key, ObservableDefinitionEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.Observer => Registry.Observers.TryAdd(key, ObserverDefinitionEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.Stream => Registry.Subjects.TryAdd(key, SubjectEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.StreamFactory => Registry.SubjectFactories.TryAdd(key, StreamFactoryDefinitionEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.SubscriptionFactory => Registry.SubscriptionFactories.TryAdd(key, SubscriptionFactoryDefinitionEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.Subscription => Registry.Subscriptions.TryAdd(key, SubscriptionEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.ReliableSubscription => Registry.ReliableSubscriptions.TryAdd(key, ReliableSubscriptionEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.Other => Registry.Other.TryAdd(key, OtherDefinitionEntity.CreateInvalidInstance(uri)), ReactiveEntityKind.Template => Registry.Templates.TryAdd(key, OtherDefinitionEntity.CreateInvalidInstance(uri)), _ => throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Cannot create an invalid entity '{0}' of type '{1}'.", key, kind)), }; #pragma warning restore CA2000 #pragma warning restore IDE0079 if (added) { Parent.TraceSource.Registry_AddEntityPlaceholder(Parent.Uri, kind.ToString(), key); } }
/// <summary> /// Creates a new instance of the <see cref="EntityAlreadyExistsException"/> class with the specified information about the entity and an inner exception. /// </summary> /// <param name="uri">URI identifying the reactive entity that already exists.</param> /// <param name="type">Reactive entity kind.</param> /// <param name="qeId">URI identifier the query engine whose registry already contains an entity with the specified URI.</param> /// <param name="paramName">Parameter name of the argument containing the URI that caused the conflict.</param> /// <param name="inner">Inner exception with additional information about the naming conflict.</param> public EntityAlreadyExistsException(Uri uri, ReactiveEntityKind type, Uri qeId, string paramName, Exception inner) : base(GetMessage(uri, type, qeId), paramName, inner) { QueryEngineUri = qeId; EntityUri = uri; EntityType = type; }
public ReactiveEntity Load(ReactiveEntityKind kind) { var expression = DeserializeExpression(); var uri = _serializer.Deserialize <Uri>(_stream); var state = _serializer.Deserialize <object>(_stream); var entity = CreateEntity(kind, uri, expression, state); entity.Deserialize(_serializer, _stream); return(entity); }
/// <summary> /// Creates an invalid instance of the given reactive entity kind with the given URI. /// </summary> /// <param name="uri">The URI.</param> /// <param name="kind">The reactive entity kind.</param> /// <returns> /// The invalid instance, or null if an unexpected kind is provided. /// </returns> public static ReactiveEntity CreateInvalidInstance(Uri uri, ReactiveEntityKind kind) { return(kind switch { ReactiveEntityKind.Observable => ObservableDefinitionEntity.CreateInvalidInstance(uri), ReactiveEntityKind.Observer => ObserverDefinitionEntity.CreateInvalidInstance(uri), ReactiveEntityKind.Stream => SubjectEntity.CreateInvalidInstance(uri), ReactiveEntityKind.StreamFactory => StreamFactoryDefinitionEntity.CreateInvalidInstance(uri), ReactiveEntityKind.Subscription => SubscriptionEntity.CreateInvalidInstance(uri), ReactiveEntityKind.ReliableSubscription => ReliableSubscriptionEntity.CreateInvalidInstance(uri), ReactiveEntityKind.Template or ReactiveEntityKind.Other => OtherDefinitionEntity.CreateInvalidInstance(uri), _ => null, });
private bool OnEntitySaveFailed(Uri uri, IReactiveResource entity, ReactiveEntityKind kind, Exception error) { var entitySaveFailed = Parent.EntitySaveFailed; if (entitySaveFailed != null) { var e = new ReactiveEntitySaveFailedEventArgs(uri, entity, kind, error); entitySaveFailed.InvokeSafe(Parent, e); return(e.Handled); } return(false); }
private void HandleError(ReactiveEntityKind kind, string key, IReactiveResource entity, Exception ex, Action <Exception> unhandled) { if (ex is EngineUnloadedException) { return; } var uri = new Uri(key); var error = new EntitySaveFailedException(uri, kind, ex); if (!_engine.OnEntitySaveFailed(uri, entity, kind, error)) { unhandled(error); } }
/// <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); }
private void HandleError(ReactiveEntityKind kind, string key, IReactiveResource entity, Exception ex, Action <Exception> unhandled) { if (ex is EngineUnloadedException) { return; } var uri = new Uri(key); var error = new EntityLoadFailedException(uri, kind, ex); // TODO: support mitigation for any kind of artifact if (!_engine.OnEntityLoadFailed(uri, entity, kind, error, out _)) { unhandled(error); } }
private bool OnEntityLoadFailed(Uri uri, IReactiveResource entity, ReactiveEntityKind kind, Exception error, out ReactiveEntityRecoveryFailureMitigation mitigation) { mitigation = ReactiveEntityRecoveryFailureMitigation.Ignore; if (error is MitigationBailOutException) { return(true); } var entityLoadFailed = Parent.EntityLoadFailed; if (entityLoadFailed != null) { var e = new ReactiveEntityLoadFailedEventArgs(uri, entity, kind, error); entityLoadFailed.InvokeSafe(Parent, e); mitigation = e.Mitigation; return(e.Handled); } return(false); }
/// <summary> /// Creates a new instance of the <see cref="ReactiveEntityEventArgs"/> class for the specified entity. /// </summary> /// <param name="uri">URI of the reactive entity.</param> /// <param name="entity">Reactive entity.</param> /// <param name="entityType">Kind of the reactive entity.</param> protected ReactiveEntityEventArgs(Uri uri, IReactiveResource entity, ReactiveEntityKind entityType) { Uri = uri; Entity = entity; EntityType = entityType; }
/// <summary> /// Creates a new instance of the <see cref="EntityLoadFailedException"/> type for the entity with the specified URI and entity kind, including an inner exception. /// </summary> /// <param name="uri">URI identifying the entity that failed to be loaded.</param> /// <param name="type">Reactive entity kind of the entity that failed to be loaded.</param> /// <param name="inner">Exception that caused the entity save failure.</param> public EntityLoadFailedException(Uri uri, ReactiveEntityKind type, Exception inner) : base(GetMessage(uri, type), inner) { EntityUri = uri; EntityType = type; }
/// <summary> /// Creates a new instance of the <see cref="ReactiveEntityLoadFailedEventArgs"/> class for the specified entity. /// </summary> /// <param name="uri">URI of the reactive entity.</param> /// <param name="entity">Reactive entity.</param> /// <param name="entityType">Kind of the reactive entity.</param> /// <param name="error">The error that occured during load.</param> public ReactiveEntityLoadFailedEventArgs(Uri uri, IReactiveResource entity, ReactiveEntityKind entityType, Exception error) : base(uri, entity, entityType) { Error = error; }
/// <summary> /// Loads the definitions. /// </summary> /// <typeparam name="TEntity">The type of the entity.</typeparam> /// <param name="category">The category.</param> /// <param name="kind">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 LoadDefinitions <TEntity>( string category, ReactiveEntityKind kind, Action <TEntity> onLoading, Action <string, TEntity, Exception> onError, BlobLogger blobLogger, CancellationToken token) where TEntity : ReactiveEntity { Debug.Assert(!string.IsNullOrEmpty(category), "Category should not be null or empty."); Debug.Assert(onLoading != null, "onLoading should not be null."); var trace = _engine.Parent.TraceSource; trace.Recovery_LoadingDefinitionsStarted(_engine.Parent.Uri, category); if (!_reader.TryGetItemKeys(category, out IEnumerable <string> entities)) { entities = Array.Empty <string>(); } var total = 0; var failed = 0; Parallel.ForEach( entities, new ParallelOptions { MaxDegreeOfParallelism = _engine.Parent.Options.RecoveryDegreeOfParallelism, TaskScheduler = RecoveryScheduler.Default, CancellationToken = token, }, key => { var entity = default(TEntity); try { var stopwatch = Stopwatch.StartNew(); if (!_reader.TryGetItemReader(category, key, out Stream stream)) { throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "No items in key '{0}' for category '{1}'.", key, category)); } var elapsedReading = stopwatch.Elapsed; blobLogger.Append(category, key, stream); var policy = _engine.Parent._serializationPolicy; stopwatch.Restart(); using (var reader = new EntityReader(stream, _engine.Registry, policy)) { reader.ReadHeader(); _engine.TryMitigate( () => entity = (TEntity)reader.Load(kind), ReactiveEntity.CreateInvalidInstance(new Uri(key), kind), true, _placeholderMitigator); reader.ReadFooter(); } var elapsedLoading = stopwatch.Elapsed; entity.SetMetric(EntityMetric.ReadEntity, elapsedReading); entity.SetMetric(EntityMetric.LoadEntity, elapsedLoading); onLoading(entity); } catch (MitigationBailOutException) { } #pragma warning disable CA1031 // Do not catch general exception types. (By design; mitigation callback is the "handler".) catch (Exception ex) { Interlocked.Increment(ref failed); trace.Recovery_LoadingDefinitionsFailure(_engine.Parent.Uri, category, key, ex.Message); onError(key, entity, ex); } #pragma warning restore CA1031 Interlocked.Increment(ref total); }); token.ThrowIfCancellationRequested(); trace.Recovery_LoadingDefinitionsCompleted(_engine.Parent.Uri, category, total, failed); }
private static string GetMessage(Uri uri, ReactiveEntityKind type, Uri qeId) { return(string.Format(CultureInfo.InvariantCulture, "An entity of type '{0}' with identifier '{1}' already exists in query engine '{2}'.", type, uri.ToCanonicalString(), qeId.ToCanonicalString())); }
private static string GetMessage(Uri uri, ReactiveEntityKind type) { return(string.Format(CultureInfo.InvariantCulture, "The entity of type '{0}' with identifier '{1}' failed to load.", type, uri.ToCanonicalString())); }
/// <summary> /// Creates a new instance of the <see cref="EntitySaveFailedException"/> type for the entity with the specified URI and entity kind. /// </summary> /// <param name="uri">URI identifying the entity that failed to be saved.</param> /// <param name="type">Reactive entity kind of the entity that failed to be saved.</param> public EntitySaveFailedException(Uri uri, ReactiveEntityKind type) : base(GetMessage(uri, type)) { EntityUri = uri; EntityType = type; }