public void Save(ReactiveEntity entity) { SerializeExpression(entity.Expression); _serializer.Serialize(entity.Uri, _stream); _serializer.Serialize(entity.State, _stream); entity.Serialize(_serializer, _stream); }
private bool TryGetCandidate(out ReactiveEntity entity, out bool complete) { var stopwatch = Stopwatch.StartNew(); while (stopwatch.Elapsed < _quantum) { if (!_enumerator.MoveNext()) { _traceSource.TemplateMigration_Completed(_queryEngine.Uri); _enumerator.Dispose(); entity = null; complete = true; return(false); } if (!_enumerator.Current.Expression.IsTemplatized()) { entity = _enumerator.Current; complete = false; return(true); } } entity = null; complete = false; return(false); }
protected override bool OnRemove(ReactiveEntity entity) { if (_parent.Parent.Options.GarbageCollectionEnabled && _parent.Parent.Options.GarbageCollectionSweepEnabled) { _parent._garbageCollector.Enqueue(entity); } else { _parent.RemoveEntity(entity); } return(true); }
/// <summary> /// Try to invoke the specified <paramref name="action"/> and handle any exception that occurs. /// If an exception occurs and <paramref name="shouldMitigate"/> is true, the specified <paramref name="mitigator"/> is used to apply a mitigation. /// </summary> /// <param name="action">The action to try.</param> /// <param name="entity">The entity being loaded/mitigated.</param> /// <param name="shouldMitigate">true if errors should be mitigated; otherwise, false.</param> /// <param name="mitigator">The mitigator to use if the failed action should be mitigated.</param> private void TryMitigate(Action action, ReactiveEntity entity, bool shouldMitigate, ReactiveEntityRecoveryFailureMitigator mitigator) { try { action(); } catch (Exception ex) { var error = new EntityLoadFailedException(entity.Uri, entity.Kind, ex); if (shouldMitigate && Parent._engine.OnEntityLoadFailed(entity.Uri, entity, entity.Kind, error, out ReactiveEntityRecoveryFailureMitigation mitigation)) { var trace = Parent.TraceSource; trace.Mitigation_Execute(entity.Uri, mitigation); #pragma warning disable IDE0079 // Remove unnecessary suppression. #pragma warning disable CA1031 // Do not catch general exception types. (Protecting against engine unavailability; last resort mitigation with tracing of errors.) try { if (!mitigator.DoMitigate(entity, mitigation)) { trace.Mitigation_NotAccepted(mitigation, entity.Uri, ex); } } catch (Exception mx) { trace.Mitigation_Failure(mitigation, entity.Uri, mx); } #pragma warning restore CA1031 #pragma warning restore IDE0079 // For this implementation, whenever a mitigation occurs, we will throw a // bail out exception. This is to prevent further processing of the // 'normal' recovery process from throwing additional errors that will // trigger additional mitigations. An unfortunate consequence is that the // mitigations must ensure all steps that would have occurred in the // 'normal' recovery process occur in the mitigation (esp. for things // mitigations like `Regenerate`. Right now, this is not a problem, as the // steps being mitigated are late in the recovery process. throw new MitigationBailOutException(); } // This may result in a second call to the `EntityLoadFailed` event. throw; } }
/// <summary> /// Saves a definition. /// </summary> /// <param name="entity">The entity to save.</param> /// <param name="stream">The stream to save to.</param> protected virtual void SaveDefinition(ReactiveEntity entity, Stream stream) { Debug.Assert(entity != null, "Entity should not be null."); Debug.Assert(stream != null, "Stream should not be null."); var policy = _engine.Parent._serializationPolicy; using (entity.Measure(EntityMetric.SaveEntity)) { using var definitionWriter = new EntityWriter(stream, policy); definitionWriter.WriteHeader(); definitionWriter.Save(entity); } }
private void RemoveEntitySafe(ReactiveEntity entity) { #pragma warning disable IDE0079 // Remove unnecessary suppression. #pragma warning disable CA1031 // Do not catch general exception types. (Purpose of Safe variant.) try { RemoveEntity(entity); } catch (Exception ex) { Parent.TraceSource.FailSafe_Exception(nameof(RemoveEntity), ex); } #pragma warning restore CA1031 #pragma warning restore IDE0079 }
private void RemoveEntity(ReactiveEntity entity) { var removed = true; var uri = entity.Uri; var key = uri.ToCanonicalString(); switch (entity.Kind) { case ReactiveEntityKind.Observable: { UndefineObservable(uri); break; } case ReactiveEntityKind.Observer: { UndefineObserver(uri); break; } case ReactiveEntityKind.Stream: { DeleteStream(uri); break; } case ReactiveEntityKind.StreamFactory: { UndefineSubjectFactory(uri); break; } case ReactiveEntityKind.SubscriptionFactory: { UndefineSubscriptionFactory(uri); break; } case ReactiveEntityKind.Subscription: { DeleteSubscription(uri); break; } case ReactiveEntityKind.ReliableSubscription: { DeleteReliableSubscription(uri); break; } case ReactiveEntityKind.Other: { removed = Registry.Other.TryRemove(key, out _); break; } case ReactiveEntityKind.Template: { removed = Registry.Templates.TryRemove(key, out _); break; } case ReactiveEntityKind.None: default: throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Cannot remove a placeholder ignore '{0}' of type '{1}'.", key, entity.Kind)); } if (removed) { Parent.TraceSource.Registry_RemoveEntity(entity.Kind.ToString(), key, Parent.Uri); } }
protected override void OnAll(ReactiveEntity entity) { _parent.AddEntityPlaceholder(entity.Kind, entity.Uri.ToCanonicalString()); }
protected override bool OnRegenerate(ReactiveEntity entity) { _onRegenerate(entity); return(true); }
/// <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); }
public void Enqueue(ReactiveEntity entity) { _collectibleEntities.Enqueue(entity); }
/// <summary> /// Predicate defining whether the definition should be included in the checkpoint. /// </summary> /// <param name="entity">The entity.</param> /// <returns> /// True if should be included. /// </returns> protected override bool ShouldSaveDefinition(ReactiveEntity entity) => true;
/// <summary> /// Predicate defining whether the definition should be included in the checkpoint. /// </summary> /// <param name="entity">The entity.</param> /// <returns> /// True if should be included. /// </returns> protected override bool ShouldSaveDefinition(ReactiveEntity entity) { Debug.Assert(entity != null, "Entity should not be null."); return(!entity.IsPersisted); }
/// <summary> /// Predicate defining whether the definition should be included in the checkpoint. /// </summary> /// <param name="entity">The entity.</param> /// <returns>True if should be included.</returns> protected abstract bool ShouldSaveDefinition(ReactiveEntity entity);