public (List <string> ChangeVectors, NonPersistentDocumentFlags NonPersistentFlags) DeleteConflictsFor( DocumentsOperationContext context, Slice lowerId, BlittableJsonReaderObject document) { if (ConflictsCount == 0) { return(null, NonPersistentDocumentFlags.None); } var changeVectors = new List <string>(); var nonPersistentFlags = NonPersistentDocumentFlags.None; string deleteAttachmentChangeVector = null; using (GetConflictsIdPrefix(context, lowerId, out Slice prefixSlice)) { var conflictsTable = context.Transaction.InnerTransaction.OpenTable(ConflictsSchema, ConflictsSlice); conflictsTable.DeleteForwardFrom(ConflictsSchema.Indexes[IdAndChangeVectorSlice], prefixSlice, true, long.MaxValue, conflictDocument => { var etag = TableValueToEtag((int)ConflictsTable.Etag, ref conflictDocument.Reader); _documentsStorage.EnsureLastEtagIsPersisted(context, etag); var conflictChangeVector = TableValueToChangeVector(context, (int)ConflictsTable.ChangeVector, ref conflictDocument.Reader); changeVectors.Add(conflictChangeVector); var flags = TableValueToFlags((int)ConflictsTable.Flags, ref conflictDocument.Reader); if ((flags & DocumentFlags.HasAttachments) != DocumentFlags.HasAttachments) { return; } if (string.IsNullOrEmpty(deleteAttachmentChangeVector)) { var newEtag = _documentsStorage.GenerateNextEtag(); deleteAttachmentChangeVector = _documentsStorage.GetNewChangeVector(context, newEtag); context.LastDatabaseChangeVector = conflictChangeVector; } nonPersistentFlags |= DeleteAttachmentConflicts(context, lowerId, document, conflictDocument, deleteAttachmentChangeVector); }); } // once this value has been set, we can't set it to false // an older transaction may be running and seeing it is false it // will not detect a conflict. It is an optimization only that // we have to do, so we'll handle it. // Only register the event if we actually deleted any conflicts var listCount = changeVectors.Count; if (listCount > 0) { var tx = context.Transaction.InnerTransaction.LowLevelTransaction; tx.AfterCommitWhenNewReadTransactionsPrevented += () => { Interlocked.Add(ref ConflictsCount, -listCount); }; } return(changeVectors, nonPersistentFlags); }
public (List <string> ChangeVectors, NonPersistentDocumentFlags NonPersistentFlags) DeleteConflictsFor( DocumentsOperationContext context, Slice lowerId, BlittableJsonReaderObject document) { if (ConflictsCount == 0) { return(null, NonPersistentDocumentFlags.None); } var changeVectors = new List <string>(); var nonPersistentFlags = NonPersistentDocumentFlags.None; string deleteAttachmentChangeVector = null; using (GetConflictsIdPrefix(context, lowerId, out Slice prefixSlice)) { var conflictsTable = context.Transaction.InnerTransaction.OpenTable(ConflictsSchema, ConflictsSlice); conflictsTable.DeleteForwardFrom(ConflictsSchema.Indexes[IdAndChangeVectorSlice], prefixSlice, true, long.MaxValue, conflictDocument => { var conflicted = TableValueToConflictDocument(context, ref conflictDocument.Reader); var collection = _documentsStorage.ExtractCollectionName(context, conflicted.Collection); if (conflicted.Doc != null) { _documentsStorage.RevisionsStorage.Put( context, conflicted.Id, conflicted.Doc, conflicted.Flags | DocumentFlags.Conflicted, nonPersistentFlags, conflicted.ChangeVector, conflicted.LastModified.Ticks, collectionName: collection, configuration: RevisionsStorage.ConflictConfiguration.Default); } else if (conflicted.Flags.Contain(DocumentFlags.FromReplication) == false) { using (Slice.External(context.Allocator, conflicted.LowerId, out var key)) { var lastModifiedTicks = _documentDatabase.Time.GetUtcNow().Ticks; _documentsStorage.RevisionsStorage.DeleteRevision(context, key, conflicted.Collection, conflicted.ChangeVector, lastModifiedTicks); } } _documentsStorage.EnsureLastEtagIsPersisted(context, conflicted.Etag); changeVectors.Add(conflicted.ChangeVector); if (conflicted.Flags.Contain(DocumentFlags.HasAttachments) == false) { return; } if (string.IsNullOrEmpty(deleteAttachmentChangeVector)) { var newEtag = _documentsStorage.GenerateNextEtag(); deleteAttachmentChangeVector = _documentsStorage.GetNewChangeVector(context, newEtag); context.LastDatabaseChangeVector = conflicted.ChangeVector; } nonPersistentFlags |= DeleteAttachmentConflicts(context, lowerId, document, conflictDocument, deleteAttachmentChangeVector); }); } // once this value has been set, we can't set it to false // an older transaction may be running and seeing it is false it // will not detect a conflict. It is an optimization only that // we have to do, so we'll handle it. // Only register the event if we actually deleted any conflicts var listCount = changeVectors.Count; if (listCount > 0) { var tx = context.Transaction.InnerTransaction.LowLevelTransaction; tx.AfterCommitWhenNewReadTransactionsPrevented += () => { Interlocked.Add(ref ConflictsCount, -listCount); }; } return(changeVectors, nonPersistentFlags | NonPersistentDocumentFlags.Resolved); }