private void UpdateCascadeReferencingCollection(ReferencingCollectionSetting rc, ReferencingCollectionOperation co) { co.StartedDate = DateTime.UtcNow; co.Status = UpdateCascadeOperationStatus.Executing; co.UpdatedDocumentCount = 0; SaveOperationSilentlyIgnoringError(); // we can continue anyway log.Trace("Update cascade {0} referencing document collection for update cascade operation {1} started", rc.ReferencingEntityName, operation.Id); try { int updatedByIndex = 0; Guid lastEtag; do { lastEtag = db.GetLastEtag(); var query = new IndexQuery { CutoffEtag = lastEtag, Query = string.Format("{0}:{1} AND {2}:{3}NULL TO {4}{5}", rc.ReferencedIdPropertyNameInIndex, RavenQuery.Escape(referencedDoc.Key), rc.ReferencedEtagPropertyNameInIndex, "{", RavenQuery.Escape(Convert.ToString(referencedDoc.Etag, CultureInfo.InvariantCulture)), "}") }; updatedByIndex = db.UpdateByIndex(rc.IndexName, query, doc => UpdateDocumentWithProgressReport(doc, co), TimeSpan.FromHours(8), cancellationToken, null); } while (updatedByIndex > 0); db.UpdateDocumentsAfter(lastEtag, UpdateDocument, cancellationToken, null); co.Status = UpdateCascadeOperationStatus.CompletedSuccessfully; log.Trace("Update cascade {0} documents for operation {1} completed successfully. {2} documents have been updated in {3}", rc.ReferencingEntityName, operation.Id, co.UpdatedDocumentCount, co.ElapsedTime); } catch (OperationCanceledException) // save the operation and rethrow { co.Status = UpdateCascadeOperationStatus.Canceled; throw; } catch (Exception ex) // Log the error, save the operation, and move to the next. { co.ErrorMessage = ex.Message; co.Status = UpdateCascadeOperationStatus.Failed; log.ErrorException(string.Format("Update cascade {0} documents for operation {1} failed miserably. Moving on the next one ...", rc.ReferencingEntityName, operation.Id), ex); } finally { co.CompletedDate = DateTime.UtcNow; if (!(services.IsShutDownInProgress && co.Status == UpdateCascadeOperationStatus.Canceled)) { SaveOperationSilentlyIgnoringError(); // we want to preserve OperationCanceledException. } } }
private bool UpdateDocument(JsonDocument referencingDocument) { var referencingEntityName = referencingDocument.Metadata.Value <string>(Constants.RavenEntityName); ReferencingCollectionSetting referencingCollectionSetting = null; if (!this.setting.ReferencingCollections.TryGetValue(referencingEntityName, out referencingCollectionSetting)) { log.Debug("{0} document doesn't need to be cascade updated because it doesn't belong to any document collection that hold denormalized references to {1}. Operation {2} ", referencingDocument.Key, setting.ReferencedEntityName, operation.Id); return(false); } var denormalizedReferences = referencingDocument.DataAsJson.GetObjectsAtPath(referencingCollectionSetting.ReferencingPropertyPath); bool shouldUpdate = false; foreach (var reference in denormalizedReferences) { Guid?referencedEtag = reference.Value <Guid?>("Etag"); var referencedDocId = reference.Value <string>("Id"); if (referencedDocId == referencedDoc.Key && (referencedEtag == null || Buffers.Compare(referencedEtag.Value.ToByteArray(), referencedDoc.Etag.Value.ToByteArray()) < 0)) { shouldUpdate = true; foreach (var property in setting.DenormalizedReferencePropertyNames) { reference[property] = referencedDoc.DataAsJson[property].CloneToken(); } reference["Etag"] = RavenJToken.FromObject(referencedDoc.Etag.Value); } } if (shouldUpdate) { log.Debug("{0} document has been cascade updated in memory beacause it references {1} document and its referencing Etag is prior to the referenced document one {2}", referencingDocument.Key, referencedDoc.Key, referencedDoc.Etag); } else { log.Debug("{0} document has not been cascade updated in memory beacause it does not references {1} document or its referencing Etag is subsequent to the referenced document one {2}", referencingDocument.Key, referencedDoc.Key, referencedDoc.Etag); } return(shouldUpdate); }
private void UpdateCascadeReferencingCollection(ReferencingCollectionSetting rc, ReferencingCollectionOperation co) { co.StartedDate = DateTime.UtcNow; co.Status = UpdateCascadeOperationStatus.Executing; co.UpdatedDocumentCount = 0; SaveOperationSilentlyIgnoringError(); // we can continue anyway log.Trace("Update cascade {0} referencing document collection for update cascade operation {1} started", rc.ReferencingEntityName, operation.Id); try { int updatedByIndex = 0; Guid lastEtag; do { lastEtag = db.GetLastEtag(); var query = new IndexQuery { CutoffEtag = lastEtag, Query = string.Format("{0}:{1} AND {2}:{3}NULL TO {4}{5}", rc.ReferencedIdPropertyNameInIndex, RavenQuery.Escape(referencedDoc.Key), rc.ReferencedEtagPropertyNameInIndex, "{", RavenQuery.Escape(Convert.ToString(referencedDoc.Etag, CultureInfo.InvariantCulture)), "}") }; updatedByIndex = db.UpdateByIndex(rc.IndexName, query, doc => UpdateDocumentWithProgressReport(doc, co), TimeSpan.FromHours(8), cancellationToken, null); } while (updatedByIndex > 0); db.UpdateDocumentsAfter(lastEtag, UpdateDocument, cancellationToken, null); co.Status = UpdateCascadeOperationStatus.CompletedSuccessfully; log.Trace("Update cascade {0} documents for operation {1} completed successfully. {2} documents have been updated in {3}", rc.ReferencingEntityName, operation.Id, co.UpdatedDocumentCount, co.ElapsedTime); } catch (OperationCanceledException) // save the operation and rethrow { co.Status = UpdateCascadeOperationStatus.Canceled; throw; } catch (Exception ex) // Log the error, save the operation, and move to the next. { co.ErrorMessage = ex.Message; co.Status = UpdateCascadeOperationStatus.Failed; log.ErrorException(string.Format("Update cascade {0} documents for operation {1} failed miserably. Moving on the next one ...", rc.ReferencingEntityName, operation.Id), ex); } finally { co.CompletedDate = DateTime.UtcNow; if (!(services.IsShutDownInProgress && co.Status == UpdateCascadeOperationStatus.Canceled)) SaveOperationSilentlyIgnoringError(); // we want to preserve OperationCanceledException. } }