Exemple #1
0
 public UpdateCascadeOperationExecutor(DocumentDatabase db, UpdateCascadeSetting setting, UpdateCascadeOperation operation, JsonDocument referencedDoc)
 {
     this.db            = db;
     this.services      = Services.GetServices(db);
     this.setting       = setting;
     this.operation     = operation;
     this.referencedDoc = referencedDoc;
 }
 public UpdateCascadeOperationExecutor(DocumentDatabase db, UpdateCascadeSetting setting, UpdateCascadeOperation operation, JsonDocument referencedDoc)
 {
     this.db = db;
     this.services = Services.GetServices(db);
     this.setting = setting;
     this.operation = operation;
     this.referencedDoc = referencedDoc;
 }
 public override void AfterPut(string key, RavenJObject document, RavenJObject metadata, Guid etag, TransactionInformation transactionInformation)
 {
     base.AfterPut(key, document, metadata, etag, transactionInformation);
     JsonDocument originalDocument = this.originalDocument.Value;
     if (originalDocument == null) return;
     var setting = GetSetting(metadata);
     if (setting == null) return;
     if (HasAnyReferencedPropertyChanged(originalDocument.DataAsJson, document, setting))
     {
         var operation = new UpdateCascadeOperation(setting, key, etag);
         operationRepository.Save(operation, transactionInformation);
     }
 }
        public override void AfterPut(string key, RavenJObject document, RavenJObject metadata, Guid etag, TransactionInformation transactionInformation)
        {
            base.AfterPut(key, document, metadata, etag, transactionInformation);
            JsonDocument originalDocument = this.originalDocument.Value;

            if (originalDocument == null)
            {
                return;
            }
            var setting = GetSetting(metadata);

            if (setting == null)
            {
                return;
            }
            if (HasAnyReferencedPropertyChanged(originalDocument.DataAsJson, document, setting))
            {
                var operation = new UpdateCascadeOperation(setting, key, etag);
                operationRepository.Save(operation, transactionInformation);
            }
        }
Exemple #5
0
 public void Execute(Database.DocumentDatabase database)
 {
     try
     {
         services = Services.GetServices(database);
         services.IsShutDownInProgress = false;
         db = database;
         this.db.PutIndex(UpdateCascadeOperation.ByStatusIndexName, UpdateCascadeOperation.GetByStatusIndexDefinition());
         Task.Factory.StartNew(services.RunningOperationsCoordinator.RestartNotCompletedOperations).ContinueWith(t =>
         {
             if (t.Status == TaskStatus.Faulted && t.Exception != null)
             {
                 log.ErrorException("Failed to restart not completed operations", t.Exception);
             }
         });
     }
     catch (Exception ex)
     {
         log.FatalException("Failed to execute UpdateCascadeStartupTask", ex);
     }
 }
        public bool TryStartOperation(UpdateCascadeOperation operation, JsonDocument referencedDoc)
        {
            var services = Services.GetServices(this.db);

            if (services.IsShutDownInProgress)
            {
                log.Warn("Tried to start operation {0} while shuting down", operation.Id);
                return false;
            }

            RunningOperation ro = null;
            UpdateCascadeSetting setting;
            if (!services.SettingsCache.TryGetValue(operation.UpdateCascadeSettingId, out setting))
            {
                log.Error("Tried to add and run the operation {0}. But there is no corresponding setting {1}", operation.Id, operation.UpdateCascadeSettingId);
                return false;
            }

            lock (runningOperations)
            {
                if (runningOperations.TryGetValue(operation.ReferencedDocId, out ro))
                {
                    // the operation might be already here. This shouldn't occur
                    if (operation.Id == ro.Operation.Id)
                    {
                        log.Warn("Tried to start an operation that is already started. Operation Id = {0}", operation.Id);
                        return false;
                    }
                    // the operation might refer to an older entity. This is unprobable, I think
                    if (Buffers.Compare(operation.ReferencedDocEtag.ToByteArray(), ro.Operation.ReferencedDocEtag.ToByteArray()) < 0)
                    {
                        log.Warn("Tried to start an operation that refers to an entity which is older than the referenced by a running operation. Older operation id: {0}, existing operation id: {1}", operation.Id, ro.Operation.Id);
                        return false;
                    }

                    log.Warn("The same referenced entity {0} has been updated while a previous update cascade operation of that entity is in progress, that might indicate that the document is updated so often that referencing entities cannot be updated at time. Update cascade bundle is not recomended in this scenario", operation.ReferencedDocId);

                    // the same referenced entity has been updated while a previous update cascade operation of that entity is in progress
                    // we need to cancel that operation and span a new one.
                    var tokenSource = ro.TokenSource;
                    if (tokenSource != null) tokenSource.Cancel();
                    try
                    {
                        var task = ro.ExecutorTask;
                        if (task!= null) task.Wait();
                    }
                    catch (AggregateException ex)
                    {
                        ex.Handle(x => x is TaskCanceledException);
                    }
                }
                var runningOperation = new RunningOperation
                {
                    Operation = operation,
                    TokenSource =  new CancellationTokenSource(),
                    Executor = new UpdateCascadeOperationExecutor(db, setting, operation, referencedDoc),
                };
                runningOperations[operation.ReferencedDocId] = runningOperation;
                log.Trace("Starting operation: {0}", operation.Id);
                runningOperation.ExecutorTask = runningOperation.Executor.ExecuteAsync(runningOperation.TokenSource.Token);
                runningOperation.ExecutorTask.ContinueWith(t =>
                {
                    if (!services.IsShutDownInProgress)
                    {
                        lock (runningOperations)
                        {
                            RunningOperation rop;
                            if (runningOperations.TryGetValue(operation.ReferencedDocId, out rop))
                            {
                                if (rop.Operation.Id == operation.Id)
                                {
                                    runningOperations.Remove(operation.ReferencedDocId);
                                }
                            }
                            t.Dispose();
                        }
                    }

                }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                return true;
            }
        }
        public bool TryStartOperation(UpdateCascadeOperation operation, JsonDocument referencedDoc)
        {
            var services = Services.GetServices(this.db);

            if (services.IsShutDownInProgress)
            {
                log.Warn("Tried to start operation {0} while shuting down", operation.Id);
                return(false);
            }

            RunningOperation     ro = null;
            UpdateCascadeSetting setting;

            if (!services.SettingsCache.TryGetValue(operation.UpdateCascadeSettingId, out setting))
            {
                log.Error("Tried to add and run the operation {0}. But there is no corresponding setting {1}", operation.Id, operation.UpdateCascadeSettingId);
                return(false);
            }

            lock (runningOperations)
            {
                if (runningOperations.TryGetValue(operation.ReferencedDocId, out ro))
                {
                    // the operation might be already here. This shouldn't occur
                    if (operation.Id == ro.Operation.Id)
                    {
                        log.Warn("Tried to start an operation that is already started. Operation Id = {0}", operation.Id);
                        return(false);
                    }
                    // the operation might refer to an older entity. This is unprobable, I think
                    if (Buffers.Compare(operation.ReferencedDocEtag.ToByteArray(), ro.Operation.ReferencedDocEtag.ToByteArray()) < 0)
                    {
                        log.Warn("Tried to start an operation that refers to an entity which is older than the referenced by a running operation. Older operation id: {0}, existing operation id: {1}", operation.Id, ro.Operation.Id);
                        return(false);
                    }

                    log.Warn("The same referenced entity {0} has been updated while a previous update cascade operation of that entity is in progress, that might indicate that the document is updated so often that referencing entities cannot be updated at time. Update cascade bundle is not recomended in this scenario", operation.ReferencedDocId);

                    // the same referenced entity has been updated while a previous update cascade operation of that entity is in progress
                    // we need to cancel that operation and span a new one.
                    var tokenSource = ro.TokenSource;
                    if (tokenSource != null)
                    {
                        tokenSource.Cancel();
                    }
                    try
                    {
                        var task = ro.ExecutorTask;
                        if (task != null)
                        {
                            task.Wait();
                        }
                    }
                    catch (AggregateException ex)
                    {
                        ex.Handle(x => x is TaskCanceledException);
                    }
                }
                var runningOperation = new RunningOperation
                {
                    Operation   = operation,
                    TokenSource = new CancellationTokenSource(),
                    Executor    = new UpdateCascadeOperationExecutor(db, setting, operation, referencedDoc),
                };
                runningOperations[operation.ReferencedDocId] = runningOperation;
                log.Trace("Starting operation: {0}", operation.Id);
                runningOperation.ExecutorTask = runningOperation.Executor.ExecuteAsync(runningOperation.TokenSource.Token);
                runningOperation.ExecutorTask.ContinueWith(t =>
                {
                    if (!services.IsShutDownInProgress)
                    {
                        lock (runningOperations)
                        {
                            RunningOperation rop;
                            if (runningOperations.TryGetValue(operation.ReferencedDocId, out rop))
                            {
                                if (rop.Operation.Id == operation.Id)
                                {
                                    runningOperations.Remove(operation.ReferencedDocId);
                                }
                            }
                            t.Dispose();
                        }
                    }
                }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                return(true);
            }
        }