private void ProcessExecOutputRemove(ItemChange <ConnectionViewModel> change) { if (change.Current.Input.Parent is CutNodeViewModel c) { Cut.BlockingCuts[0] = null; Cut.BlockingCuts[1] = null; Cut.BlockingCuts[2] = null; Cut = null; BlockingCutEditor.Value = null; if (Inputs.Items.First().Connections.Count > 0) { ConnectionViewModel a = Inputs.Items.First().Connections.Items.First(); if (a.Output.Parent is CutNodeViewModel prev_c) { prev_c.Cut.NextCut = null; } else if (a.Output.Parent is BeginNodeViewModel begin) { begin.Actor.FirstCut = null; } } } }
public override IEnumerable <ItemChange> GetFullEnumerationLocalVersions(FullEnumerationChangeBatch sourceChanges) { if (sourceChanges == null) { throw new ArgumentNullException("sourceChanges"); } foreach (ItemMetadata item in Replica.EntityMetadataItems) { ItemChange change = null; if ((item.GlobalId == sourceChanges.DestinationVersionEnumerationRangeLowerBound || item.GlobalId > sourceChanges.DestinationVersionEnumerationRangeLowerBound) && (item.GlobalId == sourceChanges.DestinationVersionEnumerationRangeUpperBound || item.GlobalId < sourceChanges.DestinationVersionEnumerationRangeUpperBound)) { // Found the corresponding item in the local metadata // Get the local creation version and change (update) version from the metadata change = new ItemChange(IdFormats, ReplicaId, item.GlobalId, item.IsDeleted ? ChangeKind.Deleted : ChangeKind.Update, // If local item is a tombstone, mark it accordingly item.CreationVersion, item.ChangeVersion); } else { // Remote item has no local counterpart // This item is unknown to us change = new ItemChange(IdFormats, ReplicaId, null, ChangeKind.UnknownItem, // Mark the change as unknown SyncVersion.UnknownVersion, SyncVersion.UnknownVersion); } yield return(change); } }
private void ProcessExecOutputAdd(ItemChange <ConnectionViewModel> change) { if (change.Current.Input.Parent is CutNodeViewModel c) { Cut = c.Cut; BlockingCutEditor.Value = Cut; Cut.BlockingCuts[0] = BlockingCutEditor.BlockingCut1; Cut.BlockingCuts[1] = BlockingCutEditor.BlockingCut2; Cut.BlockingCuts[2] = BlockingCutEditor.BlockingCut3; if (Inputs.Items.First().Connections.Count > 0) { ConnectionViewModel a = Inputs.Items.First().Connections.Items.First(); if (a.Output.Parent is CutNodeViewModel prev_c) { prev_c.Cut.NextCut = Cut; } else if (a.Output.Parent is BeginNodeViewModel begin) { begin.Actor.FirstCut = Cut; } } Cut.ParentActor.UpdateCutList(); } }
public async Task UpdateAsyncUsesIdentityComparerGivenAtConstruction() { IEnumerable <IntWrapper> originalItems = new IntWrapper[] { 1, 2, 3 }; IEnumerable <ItemChange <IntWrapper> > changes = new ItemChange <IntWrapper>[] { new ItemChange <IntWrapper>(ChangeType.Updated, 2) }; var loader = new AsyncLoader <IntWrapper>( Seq.ListBased, loadDataAsync: _ => Task.FromResult(originalItems), fetchUpdatesAsync: (_, __) => Task.FromResult(changes), identityComparer: new IntWrapperComparer(), eventContext: new RunInlineSynchronizationContext()); await loader.LoadAsync(); // load original items loader.CollectionChanged += (s, e) => { // Verify that the resulting change was exactly the incoming change e.Should().Equal(changes); }; await loader.UpdateAsync(); // --- Perform --- // Verify that no changes to the int values in the collection were made loader.Should().Equal(new IntWrapper[] { 1, 2, 3 }, (x, y) => x.Value == y.Value); }
public void PushItemChange() { var item = new Item("/test/test.txt") { ContentMetadata = new FileContentMetadata("text/plain", Encoding.UTF8) }; var itemChange = new ItemChange(ItemChangeType.Add, item) { NewContent = new ItemContent(ItemContentType.RawText, "Testing") }; var itemChanges = new ItemChange[] { itemChange }; IEnumerable <ItemChange> itemChangesAdded = null; bool saveChangesCalled = false; var fakeContext = new Fakes.StubIDestinationContext() { AddItemChangesIEnumerableOfItemChange = (changes) => { itemChangesAdded = changes; }, SaveChangesAsyncCancellationToken = (token) => { saveChangesCalled = true; return(Task.FromResult(0)); } }; var repo = new DestinationRepository(fakeContext); repo.PushItemChangesAsync(itemChanges, "/").Wait(); Assert.IsNotNull(itemChangesAdded); Assert.AreEqual("test/test.txt", itemChangesAdded.Single().Item.Path); Assert.AreSame(itemChange.Item.ContentMetadata, itemChangesAdded.Single().Item.ContentMetadata); Assert.AreSame(itemChange.NewContent, itemChangesAdded.Single().NewContent); Assert.IsTrue(saveChangesCalled); }
private static void ValidateExistingChangeForAdd(ItemChange existingItem) { if ((existingItem.ChangeType & ItemChangeType.Delete) == 0) { throw new ApplicationException("Cannot add item on an existing item"); } }
public async Task DownloadItemAndContentInCommitAsync(ItemChange change, string commitId, Guid repositoryId, CancellationToken token) { CreateHttpClient(); var item = await _httpClient.GetItemAsync( repositoryId, change.Item.Path, includeContentMetadata : true, versionDescriptor : new Microsoft.TeamFoundation.SourceControl.WebApi.GitVersionDescriptor() { VersionType = Microsoft.TeamFoundation.SourceControl.WebApi.GitVersionType.Commit, Version = commitId }, cancellationToken : token ); change.Item.ContentMetadata = item.ContentMetadata.ToSync(); if (!item.IsFolder) { var content = await _httpClient.GetBlobContentAsync(repositoryId, item.ObjectId, cancellationToken : token); await change.SetNewContentAsync(content, token); } }
private void DoNothing( ItemMetadata item, ItemChange change, SaveChangeContext context, bool deleted = false, MegaNodeHelper existingNode = null) { // creating if (item == null) { if (existingNode == null) { context.RecordRecoverableErrorForItem(new RecoverableErrorData(new Exception())); } item = _metadataStore.Metadata.CreateItemMetadata(change.ItemId, change.CreationVersion); item.ChangeVersion = change.ChangeVersion; _metadataStore.SaveItemMetadata(item, existingNode.Node.Id, existingNode.Path); return; } if (deleted) { item.MarkAsDeleted(change.ChangeVersion); } item.ChangeVersion = change.ChangeVersion; _metadataStore.SaveItemMetadata(item); }
private void ProcessConstraint( ItemChange change, SaveChangeContext context, MegaStoreConstraintException e, ItemMetadata item, MegaNodeHelper conflictingNode) { switch (e.ConstraintType) { case MegaStoreConstraintType.TargetExists: ResolveConflict(item, change, context, conflictingNode); break; case MegaStoreConstraintType.NoParent: OnDemandedResync(); context.RecordConstraintConflictForItem(ConstraintConflictReason.NoParent); break; // todo add no-free-space handling case MegaStoreConstraintType.ZeroSize: context.RecordConstraintConflictForItem(ConstraintConflictReason.Other); break; case MegaStoreConstraintType.NotEmpty: OnDemandedResync(); context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); break; } }
public void FailedAssertOfChangeAppendsReasonAsExpected() { var change = new ItemChange <int>(ChangeType.Updated, 2); Action assert = () => change.Should().BeChange(ChangeType.Removed, 1, "because {0} should be removed", 1); assert.ShouldThrow <Exception>().WithMessage("*removal*of 1 because 1 should be removed*"); }
public void CanAssertRemoval() { var change = new ItemChange <int>(ChangeType.Removed, 2); change.Should().BeOfChangeType(ChangeType.Removed); change.Should().BeRemoval(); }
public void DownloadCommitWithAddedTextItem() { var push = CreatePushRequest("5597f65ce55386a771e4bf6fa190b5a26c0f5ce5"); var fakeDownloadRequest = new Fakes.StubIDownloadRequest() { DownloadChangesInCommitAsyncStringGuidCancellationToken = (commitId, repositoryId, token) => { var changes = new ItemChange[] { new ItemChange(ItemChangeType.Add, new Item("/index.html")) }; return(Task.FromResult(changes.AsEnumerable())); }, DownloadItemAndContentInCommitAsyncItemChangeStringGuidCancellationToken = (itemChange, commitId, repositoryId, token) => { itemChange.Item.ContentMetadata = CreateTextContentMetadataTestData(); itemChange.NewContent = CreateTextContentTestData(); return(Task.FromResult(0)); } }; var repo = new SourceRepository(fakeDownloadRequest); repo.DownloadChangesAsync(push, "/", CancellationToken.None).Wait(); var change = push.Commits.Single().Changes.Single(); Assert.AreEqual(ItemChangeType.Add, change.ChangeType); Assert.AreEqual("/index.html", change.Item.Path); Assert.IsNotNull(change.Item.ContentMetadata); Assert.IsFalse(change.Item.ContentMetadata.IsBinary); Assert.AreEqual("text/html", change.Item.ContentMetadata.ContentType); Assert.IsNotNull(change.NewContent); Assert.AreEqual(ItemContentType.RawText, change.NewContent.ContentType); Assert.AreEqual("Testing", change.NewContent.Content); }
public void CanAssertRemovalOfItem() { var change = new ItemChange <int>(ChangeType.Removed, 1); change.Should().BeChange(ChangeType.Removed, 1); change.Should().BeRemovalOf(1); }
public void ReplaceUsesIdentityComparerGivenAtConstruction() { var collectionChangedHandler = Substitute.For <CollectionChangedHandler <IntWrapper> >(); IEnumerable <IntWrapper> originalItems = new IntWrapper[] { 1, 2, 3 }; IntWrapper replacement = 2; IEnumerable <ItemChange <IntWrapper> > expectedChanges = new ItemChange <IntWrapper>[] { new ItemChange <IntWrapper>(ChangeType.Updated, replacement) }; var loader = new ThreadSafeAsyncLoader <IntWrapper>( Seq.ListBased, loadDataAsync: _ => Task.FromResult(originalItems), identityComparer: new IntWrapperComparer(), eventContext: new RunInlineSynchronizationContext()); loader.LoadAsync(); // load original items loader.CollectionChanged += collectionChangedHandler; loader.CollectionChanged += (s, e) => { // Verify that the expected update was made e.Should().Equal(expectedChanges); }; loader.Replace(replacement, replacement); // --- Perform --- // Verify that changes were made by checking for collection changed events collectionChangedHandler.Received().Invoke(loader, Arg.Any <IEnumerable <ItemChange <IntWrapper> > >()); }
public void ReplaceAllUsesIdentityComparerGivenAtConstruction() { IEnumerable <IntWrapper> originalItems = new IntWrapper[] { 1, 2, 3 }; var replacements = new IntWrapper[] { 1, 3 }; // NOTE: Due to conservate update check, unchanged items will appear as item changes of type update // NOTE2: Need to use the actual instances, since IntWrapper uses reference equality var expectedChanges = new ItemChange <IntWrapper>[] { new ItemChange <IntWrapper>(ChangeType.Updated, replacements[0]), new ItemChange <IntWrapper>(ChangeType.Updated, replacements[1]), new ItemChange <IntWrapper>(ChangeType.Removed, originalItems.ElementAt(1)) }; var loader = new ThreadSafeAsyncLoader <IntWrapper>( Seq.ListBased, loadDataAsync: _ => Task.FromResult(originalItems), identityComparer: new IntWrapperComparer(), eventContext: new RunInlineSynchronizationContext()); loader.LoadAsync(); // load initial values loader.CollectionChanged += (s, e) => { // Verify that the actual changes match the expected changes e.Should().BeEquivalentTo(expectedChanges); }; loader.ReplaceAll(replacements); // --- Perform --- }
private void LoadPropertiesForAll_OneCall() { if (lstChanges.Items.Count > 0) { this.Cursor = Cursors.WaitCursor; List <Item> oItemList = new List <Item>(); foreach (ListViewItem oLVI in lstChanges.Items) { ItemChange oItemChange = (ItemChange)oLVI.Tag; oItemList.Add(oItemChange.Item); // build a list of all items } StringBuilder oSB = new StringBuilder(); oSB.AppendFormat("\r\n"); oSB.AppendFormat("=================================================================================\r\n"); oSB.AppendFormat("[ All Change Events in on call + LoadPropertiesForItems]=========================\r\n"); oSB.AppendFormat(""); oSB.Append(GatherChanges(oItemList)); // now do once call to get props for all. string sContent = oSB.ToString(); ShowTextDocument oForm = new ShowTextDocument(); oForm.txtEntry.WordWrap = false; oForm.Text = "Properties for all items"; oForm.txtEntry.Text = sContent; oForm.ShowDialog(); this.Cursor = Cursors.Default; } }
private void ProcessChange(ItemChange change) { Debug.WriteLine("{0} {1}", change.ChangeType.ToString(), change.Item.Path); if ((change.ChangeType & ItemChangeType.Add) != 0) { AddChange(change); } else if ((change.ChangeType & ItemChangeType.Delete) != 0) { DeleteChange(change); } else if ((change.ChangeType & ItemChangeType.Edit) != 0) { EditChange(change); } else if ((change.ChangeType & ItemChangeType.Rename) != 0) { RenameChange(change); } else { // Ignore all other types } }
private static void ValidateExistingChangeForEdit(ItemChange existingChange) { if ((existingChange.ChangeType & ItemChangeType.Delete) != 0) { throw new ApplicationException("Cannot edit a deleted item"); } }
public void CanAssertAddition() { var change = new ItemChange <int>(ChangeType.Added, 4); change.Should().BeOfChangeType(ChangeType.Added); change.Should().BeAddition(); }
public void DownloadCommitWithAddedBinaryItem() { var push = CreatePushRequest("b6f447775f71a092854a2555eea084bd6d19958e"); var fakeDownloadRequest = new Fakes.StubIDownloadRequest() { DownloadChangesInCommitAsyncStringGuidCancellationToken = (commitId, repositoryId, token) => { var changes = new ItemChange[] { new ItemChange(ItemChangeType.Add, new Item("/favicon.ico")) }; return(Task.FromResult(changes.AsEnumerable())); }, DownloadItemAndContentInCommitAsyncItemChangeStringGuidCancellationToken = (itemChange, commitId, repositoryId, token) => { itemChange.Item.ContentMetadata = CreateBinaryContentMetadataTestData(); itemChange.NewContent = CreateBinaryContentTestData(); return(Task.FromResult(0)); } }; var repo = new SourceRepository(fakeDownloadRequest); repo.DownloadChangesAsync(push, "/", CancellationToken.None).Wait(); var change = push.Commits.Single().Changes.Single(); Assert.AreEqual(ItemChangeType.Add, change.ChangeType); Assert.AreEqual("/favicon.ico", change.Item.Path); Assert.IsTrue(change.Item.ContentMetadata.IsBinary); Assert.AreEqual("image/x-icon", change.Item.ContentMetadata.ContentType); Assert.IsNotNull(change.NewContent); Assert.AreEqual(ItemContentType.Base64Encoded, change.NewContent.ContentType); Assert.AreEqual(12, change.NewContent.Content.Length); }
public void CanAssertUpdateOfItem() { var change = new ItemChange <int>(ChangeType.Updated, 100); change.Should().BeChange(ChangeType.Updated, 100); change.Should().BeUpdateOf(100); }
public override void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { // Extract the data from the change TransferMechanism data = context.ChangeData as TransferMechanism; // Now apply the change if (!(saveChangeAction == SaveChangeAction.UpdateVersionOnly) && ((change.ChangeKind & ChangeKind.Deleted) == 0)) { ItemMetadata item = new ItemMetadata(); item.ItemId = change.ItemId; item.ChangeVersion = change.ChangeVersion; item.CreationVersion = change.CreationVersion; item.Uri = data.Uri; RemoteFileInfo fileInfo = new RemoteFileInfo(); fileInfo.FolderPath = Path; fileInfo.Length = data.DataStream.Length; fileInfo.Metadata = item; fileInfo.FileByteStream = data.DataStream; Proxy.UploadFile(fileInfo); // Close input stream data.DataStream.Close(); } else { Proxy.DeleteFile(Path, change.ItemId, _filters); } // If we made it here, the change was successfully applied locally // (or it is a version only change), so we can update our knowledge with the // learned knowledge from the change context.GetUpdatedDestinationKnowledge(out _syncKnowledge, out _forgottenKnowledge); }
public void CanAssertAdditionOfItem() { var change = new ItemChange <int>(ChangeType.Added, 5); change.Should().BeChange(ChangeType.Added, 5); change.Should().BeAdditionOf(5); }
public void AssertOfChangeDoesNotAcceptDifferentItem() { var change = new ItemChange <int>(ChangeType.Added, 1); Action assert = () => change.Should().BeChange(ChangeType.Added, 2); assert.ShouldThrow <Exception>().WithMessage("Expected item change to be*addition*of 2*but found *addition*of*1*"); }
public void CanAssertUpdate() { var change = new ItemChange <int>(ChangeType.Updated, 1); change.Should().BeOfChangeType(ChangeType.Updated); change.Should().BeUpdate(); }
public List <ItemChange> GetChanges(ChangeBatch sourceChanges) { // Increment the tick count GetNextTickCount(); // Increase local knowledge tick count. SyncKnowledge.SetLocalTickCount(tickCount); // Create a collection to hold the changes we'll put into our batch List <ItemChange> changes = new List <ItemChange>(); foreach (ItemChange ic in sourceChanges) { ItemMetadata item; ItemChange change; // Iterate through each item to get the corresponding version in the local store if (metadataStore.TryGetItem(ic.ItemId, out item)) { // Found the corresponding item in the local metadata // Get the local creation version and change (update) version from the metadata change = new ItemChange(IdFormats, ReplicaId, item.ItemId, item.IsTombstone ? ChangeKind.Deleted: ChangeKind.Update, item.CreationVersion, item.ChangeVersion); } else { // Remote item has no local counterpart // This item is unknown to us change = new ItemChange(IdFormats, ReplicaId, ic.ItemId, ChangeKind.UnknownItem, SyncVersion.UnknownVersion, SyncVersion.UnknownVersion); } // Add our change to the change list changes.Add(change); } return(changes); }
/// <summary> /// Detects changes not known to the destination and returns a change batch /// </summary> /// <param name="destinationKnowledge">Requester Knowledge</param> /// <param name="batchSize">Maximum number of changes to return</param> /// <returns>List of changes</returns> private List <ItemChange> DetectChanges(SyncKnowledge destinationKnowledge, SyncId lowerEnumerationBound, uint batchSize) { List <ItemChange> retVal = new List <ItemChange>(); if (destinationKnowledge == null) { throw new ArgumentNullException("destinationKnowledge"); } if (batchSize < 0) { throw new ArgumentOutOfRangeException("batchSize"); } ulong currentLocalTickCount = Replica.TickCount; // Update local knowledge with the current local tick count Replica.CurrentKnowledge.SetLocalTickCount(currentLocalTickCount); // Map the destination knowledge // This maps the knowledge from the remote replica key map (where the destination is replicaKey 0) // to the local replica key map (where the source is replicaKey) // // We do this because our metadata is relative to the local store (and local key map) // (This is typical of most sync providers) SyncKnowledge mappedKnowledge = Replica.CurrentKnowledge.MapRemoteKnowledgeToLocal(destinationKnowledge); foreach (ItemMetadata item in Replica.EntityMetadataItems.Where(x => x.GlobalId.CompareTo(lowerEnumerationBound) >= 0)) { // Check if the current version of the item is known to the destination // We simply check if the update version is contained in his knowledge // If the metadata is for a tombstone, the change is a delete if (!mappedKnowledge.Contains(Replica.ReplicaId, item.GlobalId, item.ChangeVersion)) { ItemChange itemChange = new ItemChange(IdFormats, Replica.ReplicaId, item.GlobalId, item.IsDeleted ? ChangeKind.Deleted : ChangeKind.Update, item.CreationVersion, item.ChangeVersion); // Change isn't known to the remote store, so add it to the batch retVal.Add(itemChange); } // If the batch is full, break // // N.B. Rest of changes will be detected in next batch. Current batch will not be // reenumerated (except in case destination doesn't successfully apply them) as // when destination applies the changes in this batch, they will add them to their // knowledge. if (retVal.Count == batchSize) { break; } } return(retVal); }
public void FailedAssertOfChangeTypeAppendsReasonAsExpected() { var change = new ItemChange <int>(ChangeType.Removed, 333); Action assert = () => change.Should().BeOfChangeType(ChangeType.Added, "because I say so and also because {0} <> {1}", 1, 2); assert.ShouldThrow <Exception>().WithMessage("*to be*addition*because I say so and also because 1 <> 2, but*"); }
public override void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { // Extract the data from the change TransferMechanism data = context.ChangeData as TransferMechanism; // Item metadata ItemMetadata item = _sync.GetItemMetaData(saveChangeAction, change, data); // Now apply the change if (!(saveChangeAction == SaveChangeAction.UpdateVersionOnly) && ((change.ChangeKind & ChangeKind.Deleted) == 0)) { // Only copy if destination file name is known // (May have been lost if loser of name collision) if (item.Uri != String.Empty) { FileInfo fi = new FileInfo(System.IO.Path.Combine(Path, item.Uri)); if (!fi.Directory.Exists) { fi.Directory.Create(); } // Change should have stream data, so copy the file data to the local store using (FileStream outputStream = new FileStream(System.IO.Path.Combine(Path, item.Uri), FileMode.OpenOrCreate)) { const int copyBlockSize = 4096; byte[] buffer = new byte[copyBlockSize]; int bytesRead; // Simple block-by-block copy while ((bytesRead = data.DataStream.Read(buffer, 0, copyBlockSize)) > 0) { outputStream.Write(buffer, 0, bytesRead); } // Truncate if needed outputStream.SetLength(outputStream.Position); } // Update the last write time from the updated file to the metadata entry item.LastWriteTimeUtc = fi.LastWriteTimeUtc; } // Close input stream data.DataStream.Close(); } else { // Not an update/create, so must be a delete or version only change // Is it a delete?... if (item.IsTombstone && item.Uri != String.Empty) { // Change is a delete File.Delete(System.IO.Path.Combine(Path, item.Uri)); } } // If we made it here, the change was successfully applied locally // (or it is a version only change), so we can update our knowledge with the // learned knowledge from the change _sync.GetUpdatedKnowledge(context); }
//Save the item, taking the appropriate action for the 'change' and the data from the item (in 'context') public void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { ulong timeStamp = 0; ItemMetadata item = null; switch (saveChangeAction) { case SaveChangeAction.Create: item = _metadataStore.Metadata.FindItemMetadataById(change.ItemId); if (item != null) { // doubtful solution _metadataStore.Metadata.RemoveItemMetadata(new List<SyncId> { item.GlobalId }); item = null; } CreateItem(change, context); break; case SaveChangeAction.UpdateVersionAndData: case SaveChangeAction.UpdateVersionOnly: item = _metadataStore.Metadata.FindItemMetadataById(change.ItemId); if (item == null) { CreateItem(change, context); break; } if (saveChangeAction == SaveChangeAction.UpdateVersionOnly) { item.ChangeVersion = change.ChangeVersion; _metadataStore.SaveItemMetadata(item); } else { UpdateItem(item, change, context); } break; case SaveChangeAction.DeleteAndStoreTombstone: item = _metadataStore.Metadata.FindItemMetadataById(change.ItemId); // didn't know about this item if (item == null) { item = _metadataStore.Metadata.CreateItemMetadata(change.ItemId, change.CreationVersion); item.MarkAsDeleted(change.ChangeVersion); item.ChangeVersion = change.ChangeVersion; _metadataStore.SaveItemMetadata(item); } else { DeleteItem(item, change, context); } break; case SaveChangeAction.UpdateVersionAndMergeData: item = _metadataStore.Metadata.FindItemMetadataById(change.ItemId); ResolveConflict(item, change, context, null); break; case SaveChangeAction.DeleteAndRemoveTombstone: item = _metadataStore.Metadata.FindItemMetadataById(change.ItemId); if (item != null) { DeleteItem(item, change, context, true); } break; } }
private void ProcessPropertyInputAdd(ItemChange <ConnectionViewModel> change) { SubstanceNodeViewModel sub_view = change.Current.Output.Parent as SubstanceNodeViewModel; if (sub_view == null) { return; } Cut.Properties.Add(sub_view.Substance); }
public void ChangesFromReturnsCorrectChangesForDifferentSingletonSequences() { // Precondition: ItemChange implements Equals in natural way var change1 = new ItemChange<int>(ChangeType.Added, 1); var change2 = new ItemChange<int>(ChangeType.Added, 1); change1.Should().Be(change2); var oldSeq = new int[] { 1 }; var newSeq = new int[] { 2 }; IEnumerable<IItemChange<int>> expectedChanges = new[] { new ItemChange<int>(ChangeType.Removed, 1), new ItemChange<int>(ChangeType.Added, 2) }; var changes = newSeq.ChangesFrom(oldSeq); // --- Perform --- changes.Should().BeEquivalentTo(expectedChanges); }
public void SaveConflict(ItemChange conflictingChange, object conflictingChangeData, SyncKnowledge conflictingChangeKnowledge) { throw new NotImplementedException("The method or operation is not implemented."); }
/// <summary> /// Возвращает пакет изменений, содержащий версии элементов и базовые единицы, которые хранятся в данной реплике. /// Они соответствуют элементам и базовым единицам, на которые были ссылки в пакете изменений, полученном от другого поставщика. /// </summary> /// <param name="sourceChanges">The source changes.</param> /// <returns></returns> public override IEnumerable<ItemChange> GetLocalVersions(ChangeBatch sourceChanges) { if (sourceChanges == null) { throw new ArgumentNullException("sourceChanges"); } ulong tickCount = GetNextTickCount(); Replica.CurrentKnowledge.SetLocalTickCount(tickCount); // Iterate over changes in the source ChangeBatch foreach (ItemChange itemChange in sourceChanges) { ItemChange change = null; ItemMetadata item = Replica.FindItemMetadataById(itemChange.ItemId); // Iterate through each item to get the corresponding version in the local store if (item != null) { // Found the corresponding item in the local metadata // Get the local creation version and change (update) version from the metadata change = new ItemChange(IdFormats, ReplicaId, item.GlobalId, item.IsDeleted ? ChangeKind.Deleted : ChangeKind.Update, // If local item is a tombstone, mark it accordingly item.CreationVersion, item.ChangeVersion); } else { // Remote item has no local counterpart // This item is unknown to us change = new ItemChange(IdFormats, ReplicaId, itemChange.ItemId, ChangeKind.UnknownItem, // Mark the change as unknown SyncVersion.UnknownVersion, SyncVersion.UnknownVersion); } // Add our change to the change list yield return change; } }
public void SaveConstraintConflict( ItemChange conflictingChange, SyncId conflictingItemId, ConstraintConflictReason reason, object conflictingChangeData, SyncKnowledge conflictingChangeKnowledge, bool temporary) { var i = 1; // just to implement the interface }
public bool TryGetDestinationVersion(ItemChange sourceChange, out ItemChange destinationVersion) { ItemMetadata metadata; if (!metadataStore.TryGetItem(sourceChange.ItemId, out metadata)) { destinationVersion = null; return false; } if (metadata == null) { destinationVersion = null; return false; } else { destinationVersion = new ItemChange(idFormats, replicaId, sourceChange.ItemId, metadata.IsTombstone ? ChangeKind.Deleted : ChangeKind.Update, metadata.CreationVersion, metadata.ChangeVersion); return true; } }
//Save the item, taking the appropriate action for the 'change' and the data from the item (in 'context') public void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { Thread.Sleep(1000); ulong timeStamp = 0; ItemMetadata item = null; ItemData data = null; change.WorkEstimate = 1; switch (saveChangeAction) { case SaveChangeAction.Create: //Do duplicate detection here item = _metadata.FindItemMetadataById(change.ItemId); if (null != item) { throw new Exception("SaveItemChange must not have Create action for existing items."); } item = _metadata.CreateItemMetadata(change.ItemId, change.CreationVersion); item.ChangeVersion = change.ChangeVersion; data = new ItemData( (ItemData)context.ChangeData); //We are using the same id for both the local and global item id. _store.CreateItem( data, change.ItemId.GetGuidId()); SaveItemMetadata(item, _store.Get(change.ItemId.GetGuidId()).TimeStamp); break; case SaveChangeAction.UpdateVersionAndData: case SaveChangeAction.UpdateVersionOnly: item = _metadata.FindItemMetadataById(change.ItemId); if (null == item) { throw new Exception("Item Not Found in Store!?"); } item.ChangeVersion = change.ChangeVersion; if (saveChangeAction == SaveChangeAction.UpdateVersionOnly) { SaveItemMetadata(item); } else //Also update the data and the timestamp. { data = new ItemData((ItemData)context.ChangeData); timeStamp = _store.UpdateItem(item.GlobalId.GetGuidId(), data); SaveItemMetadata(item, timeStamp); } break; case SaveChangeAction.DeleteAndStoreTombstone: item = _metadata.FindItemMetadataById(change.ItemId); if (null == item) { item = _metadata.CreateItemMetadata(change.ItemId, change.CreationVersion); } if (change.ChangeKind == ChangeKind.Deleted) { item.MarkAsDeleted(change.ChangeVersion); } else { // This should never happen in Sync Framework V1.0 throw new Exception("Invalid ChangeType"); } item.ChangeVersion = change.ChangeVersion; SaveItemMetadata(item, 0); // set timestamp to 0 for tombstones _store.DeleteItem(item.GlobalId.GetGuidId()); break; //Merge the changes! (Take the data from the local item + the remote item),noting to update the tick count to propagate the resolution! case SaveChangeAction.UpdateVersionAndMergeData: item = _metadata.FindItemMetadataById(change.ItemId); if (null == item) { throw new Exception("Item Not Found in Store!?"); } if (item.IsDeleted != true) { //Note - you must update the change version to propagate the resolution! item.ChangeVersion = new SyncVersion(0, _metadata.GetNextTickCount()); //Combine the conflicting data... ItemData mergedData = (_store.Get(item.GlobalId.GetGuidId())).Merge( (ItemData)context.ChangeData); timeStamp = _store.UpdateItem(item.GlobalId.GetGuidId(), mergedData); SaveItemMetadata(item, timeStamp); } break; case SaveChangeAction.DeleteAndRemoveTombstone: item = _metadata.FindItemMetadataById(change.ItemId); if (item != null) { List<SyncId> ids = new List<SyncId>(); ids.Add(item.GlobalId); _metadata.RemoveItemMetadata(ids); } _store.DeleteItem(change.ItemId.GetGuidId()); break; } }
public void SaveConstraintConflict(ItemChange conflictingChange, SyncId conflictingItemId, ConstraintConflictReason reason, object conflictingChangeData, SyncKnowledge conflictingChangeKnowledge, bool temporary) { throw new NotImplementedException(); }
public ChangeBatch GetChanges(ChangeBatch sourceChanges) { GetNextTickCount(); myKnowledge.SetLocalTickCount(tickCount); List<ItemChange> changes = new List<ItemChange>(); foreach (ItemChange ic in sourceChanges) { ItemMetadata item; ItemChange change; if (metadataStore.TryGetItem(ic.ItemId, out item)) { System.Diagnostics.Debug.WriteLine("Remote item has local counterpart::" + item.Uri); change = new ItemChange(IdFormats, ReplicaId, item.ItemId, (item.IsTombstone ? ChangeKind.Deleted : ChangeKind.Update), item.CreationVersion, item.ChangeVersion); } else { if (item == null) System.Diagnostics.Debug.WriteLine("Remote item has no local counterpart: item.uri is null"); else System.Diagnostics.Debug.WriteLine("Remote item has no local counterpart:" + item.Uri); change = new ItemChange(IdFormats, replicaId, ic.ItemId, ChangeKind.UnknownItem, SyncVersion.UnknownVersion, SyncVersion.UnknownVersion); } changes.Add(change); } ChangeBatch changeBatchBuilder = new ChangeBatch(IdFormats, myKnowledge , myForgottenKnowledge); changeBatchBuilder.BeginUnorderedGroup(); changeBatchBuilder.AddChanges(changes); changeBatchBuilder.EndUnorderedGroup(myKnowledge, true); return changeBatchBuilder; }
private void BackupFile(ItemMetadata item, string path, ItemChange change, SaveChangeContext context) { var t = _nodeStore.BackupFile(path); var newItem = _metadataStore.CreateItemMetadata(); _metadataStore.SaveItemMetadata(newItem, t.Node.Id, t.Path); if (item == null) { CreateItem(change, context); } else { UpdateItem(item, change, context); } }
/// <summary> /// CONFLICT /// </summary> private void ResolveConflict(ItemMetadata item, ItemChange change, SaveChangeContext context, MegaNodeHelper conflictingNode) { var data = (IFileDataRetriever)context.ChangeData; // item does not exist in metadata (can happen when create+create) if (item == null) { if (conflictingNode == null) { context.RecordRecoverableErrorForItem(new RecoverableErrorData(new Exception())); } if (FilesAreEqual(data, conflictingNode)) { DoNothing(item, change, context, false, conflictingNode); } else { BackupFile(item, conflictingNode.Path, change, context); } return; } var attr = _metadataStore.GetItemInfo(item); try { if (change.ChangeKind == ChangeKind.Deleted) { // local delete + remote delete if (item.IsDeleted) { DoNothing(item, change, context, true); } // local delete + remote update else { DownloadBack(item, change); } } else { // local update + remote delete if (item.IsDeleted) { UploadBack(item, change, context); } // update + update else { if (FilesAreEqual(data, _nodeStore.FindNodeById(attr.Id))) { DoNothing(item, change, context); } else { BackupFile(item, attr.Path, change, context); } } } } catch (MegaApiException e) { context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); } }
private void UploadBack(ItemMetadata item, ItemChange change, SaveChangeContext context) { //TODO this still re-downloads the file just uploaded item.ResurrectDeletedItem(); CreateItem(change, context, item); }
private void DownloadBack(ItemMetadata item, ItemChange change) { item.ChangeVersion = new SyncVersion(change.ChangeVersion.ReplicaKey, GetNextTickCount()); _metadataStore.SaveItemMetadata(item); }
public void SaveConflict(ItemChange conflictingChange, object conflictingChangeData, SyncKnowledge conflictingChangeKnowledge) { //Conflicts are always merged so there is never a conflict to save. See DestinationCallbacks_ItemConflicting in MyTestProgram //and the SaveChangeAction.UpdateVersionAndMergeData case in SaveChange below to see how conflicts are merged. throw new NotImplementedException(); }
public void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { DataTransfer data = context.ChangeData as DataTransfer; switch (saveChangeAction) { case SaveChangeAction.Create: { ItemMetadata item = new ItemMetadata(); item.ItemId = change.ItemId; item.ChangeVersion = change.ChangeVersion; item.CreationVersion = change.CreationVersion; item.Uri = data.Uri; data.DataStream.Position = 0; System.Diagnostics.Debug.WriteLine("Uploading File:" + item.Uri); service.UploadFile(data.DataStream.Length, item, data.DataStream); data.DataStream.Close(); sync.UpdateItemItem(item); break; } case SaveChangeAction.DeleteAndStoreTombstone: { ItemMetadata item = sync.GetItemMetaData(saveChangeAction, change, data); sync.DeleteItem(change.ItemId); service.DeleteFile(change.ItemId, item.Uri); break; } default: { throw new NotImplementedException(saveChangeAction + " ChangeAction is not implemented!"); } } context.GetUpdatedDestinationKnowledge(out myKnowledge, out myForgottenKnowledge); }
/// <summary> /// DELETE /// </summary> private void DeleteItem(ItemMetadata item, ItemChange change, SaveChangeContext context, bool removeTombstone = false) { try { var attr = _metadataStore.GetItemInfo(item); _nodeStore.DeleteFile(attr.Path, attr.Id); OnAppliedChange(ChangeType.Delete, null, attr.Path); if (removeTombstone) { _metadataStore.Metadata.RemoveItemMetadata(new List<SyncId> { item.GlobalId }); } else { item.MarkAsDeleted(change.ChangeVersion); _metadataStore.SaveItemMetadata(item); } } catch (MegaStoreConstraintException e) { ProcessConstraint(change, context, e, item, null); } // never mind, the item isn't found anyway catch (MegaStoreException) { if (removeTombstone) { _metadataStore.Metadata.RemoveItemMetadata(new List<SyncId> { item.GlobalId }); } else { item.MarkAsDeleted(change.ChangeVersion); _metadataStore.SaveItemMetadata(item); } } catch (MegaApiException e) { context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); OnDemandedResync(); } }
public bool TryGetDestinationVersion(ItemChange sourceChange, out ItemChange destinationVersion) { destinationVersion = null; return false; }
/// <summary> /// UPDATE /// </summary> /// private void UpdateItem(ItemMetadata item, ItemChange change, SaveChangeContext context) { var data = (IFileDataRetriever)context.ChangeData; var attr = _metadataStore.GetItemInfo(item); var stream = data.FileData.IsDirectory ? null : data.FileStream; try { SyncedNodeAttributes updatedNode = null; //if pathes are different then consider renaming with unchanged content if (attr.Path != data.FileData.RelativePath) { updatedNode = _nodeStore.MoveFile(attr.Path, data.FileData.RelativePath, attr.Id); OnAppliedChange(ChangeType.Rename, data.FileData.RelativePath, attr.Path); } else { updatedNode = _nodeStore.UpdateFile(attr.Path, data.FileData, stream, attr.Id); OnAppliedChange(ChangeType.Update, data.FileData.RelativePath); } item.ChangeVersion = change.ChangeVersion; _metadataStore.SaveItemMetadata(item, updatedNode.Id, updatedNode.Path); } catch (MegaStoreConstraintException e) { ProcessConstraint(change, context, e, item, e.Node); } catch (MegaStoreException e) { ForgetItem(context, item, e); } catch (MegaApiException e) { context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); OnDemandedResync(); } catch (DirectoryNotFoundException e) { context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); OnDemandedResync(); } catch (COMException e) { OnDemandedResync(); context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); } finally { CloseStream(stream); } }
public void SaveChangeWithChangeUnits(ItemChange change, SaveChangeWithChangeUnitsContext context) { throw new NotImplementedException(); }
/// <summary> /// CREATE /// </summary> private void CreateItem(ItemChange change, SaveChangeContext context, ItemMetadata itemToSaveChanges = null) { var data = (IFileDataRetriever)context.ChangeData; Stream stream = null; try { stream = data.FileData.IsDirectory ? null : data.FileStream; var createdNode = _nodeStore.InsertNode(data.FileData, data.FileData.RelativePath, stream); if (itemToSaveChanges == null) { itemToSaveChanges = _metadataStore.CreateItemMetadata(change.ItemId, change.CreationVersion); } itemToSaveChanges.ChangeVersion = change.ChangeVersion; _metadataStore.SaveItemMetadata(itemToSaveChanges, createdNode.Id, createdNode.Path); OnAppliedChange(ChangeType.Create, data.FileData.RelativePath); } catch (MegaStoreConstraintException e) { ProcessConstraint(change, context, e, null, e.Node); } catch (MegaApiException e) { context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); } catch (DirectoryNotFoundException e) { OnDemandedResync(); context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); } catch (COMException e) { OnDemandedResync(); context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); } finally { CloseStream(stream); } }
public ItemMetadata GetItemMetaData(SaveChangeAction saveChangeAction, ItemChange change, DataTransfer data) { ItemMetadata item; if (saveChangeAction == SaveChangeAction.UpdateVersionOnly || ((change.ChangeKind & ChangeKind.Deleted) == ChangeKind.Deleted)) { if (!metadataStore.TryGetItem(change.ItemId, out item)) { item = new ItemMetadata(); item.Uri = String.Empty; } } else { item = new ItemMetadata(); item.Uri = data.Uri; } item.ItemId = change.ItemId; item.CreationVersion = change.CreationVersion; item.ChangeVersion = change.ChangeVersion; if ((change.ChangeKind & ChangeKind.Deleted) == ChangeKind.Deleted) item.IsTombstone = true; if (!metadataStore.Has(item.ItemId)) { ItemMetadata oldItem; if (metadataStore.TryGetItem(item.Uri, out oldItem)) { if (item.ItemId.CompareTo(oldItem.ItemId) > 0) { oldItem.IsTombstone = true; oldItem.Uri = String.Empty; oldItem.ChangeVersion = new SyncVersion(0, tickCount); } else { item.IsTombstone = true; item.Uri = String.Empty; item.ChangeVersion = new SyncVersion(0, tickCount); } metadataStore.SetItemInfo(item); metadataStore.SetItemInfo(oldItem); } } metadataStore.SetItemInfo(item); return item; }
public bool TryGetDestinationVersion(ItemChange sourceChange, out ItemChange destinationVersion) { return sync.TryGetDestinationVersion(sourceChange, out destinationVersion); }
private List<ItemChange> DetectChanges(SyncKnowledge destinationKnowledge, uint batchSize) { System.Diagnostics.Debug.WriteLine(" Start DetectChanges in:" + folderPath); List<ItemChange> changeBatch = new List<ItemChange>(); if (destinationKnowledge == null) throw new ArgumentNullException("destinationKnowledge"); if (batchSize < 0) throw new ArgumentOutOfRangeException("batchSize"); if (!localChangedDetected) { FindLocalFileChanges(folderPath); localChangedDetected = true; } SyncKnowledge mappedKnowledge = myKnowledge.MapRemoteKnowledgeToLocal(destinationKnowledge); System.Diagnostics.Debug.WriteLine(" Is the current version of the item is known to the destination ?"); foreach (ItemMetadata item in metadataStore) { if (!mappedKnowledge.Contains(replicaId, item.ItemId, item.ChangeVersion))// Create { System.Diagnostics.Debug.WriteLine("Not Known:" + item.Uri + " IsTombstone:" + item.IsTombstone.ToString()); ItemChange itemChange = new ItemChange(IdFormats, replicaId, item.ItemId, (item.IsTombstone) ? ChangeKind.Deleted : ChangeKind.Update, item.CreationVersion, item.ChangeVersion); changeBatch.Add(itemChange); } else if (item.IsTombstone)//Delete { System.Diagnostics.Debug.WriteLine("Item is Known:" + item.Uri + " Its a Tombstone so add it:"); ItemChange itemChange = new ItemChange(IdFormats, replicaId, item.ItemId, ChangeKind.Deleted, item.CreationVersion, item.ChangeVersion); changeBatch.Add(itemChange); } else//Update { System.Diagnostics.Debug.WriteLine("mappedKnowledge is know item " + item.Uri + " And was no tombstone"); ItemChange itemChange = new ItemChange(IdFormats, replicaId, item.ItemId, ChangeKind.Update, item.CreationVersion, item.ChangeVersion); changeBatch.Add(itemChange); } if (changeBatch.Count == batchSize) break; } System.Diagnostics.Debug.WriteLine(" #### End DetectChanges ####"); return changeBatch; }
/// <summary> /// Download Mechanism /// </summary> /// <param name="saveChangeAction"></param> /// <param name="change"></param> /// <param name="context"></param> public void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { DataTransfer data = context.ChangeData as DataTransfer; ItemMetadata item = sync.GetItemMetaData(saveChangeAction, change, data); switch (saveChangeAction) { case SaveChangeAction.Create: { System.Diagnostics.Debug.WriteLine("Create File: " + item.Uri); UpdateOrCreateFile(data, item); break; } case SaveChangeAction.UpdateVersionAndData: { System.Diagnostics.Debug.WriteLine("UpdateVersion And Data File: " + item.Uri); UpdateOrCreateFile(data, item); break; } case SaveChangeAction.DeleteAndStoreTombstone: { System.Diagnostics.Debug.WriteLine(" Delete File: " + item.Uri); File.Delete(Path.Combine(folderPath, item.Uri)); break; } default: { throw new NotImplementedException(saveChangeAction + " ChangeAction is not implemented!"); } } sync.GetUpdatedKnowledge(context); }
/// <summary> /// Detects changes not known to the destination and returns a change batch /// </summary> /// <param name="destinationKnowledge">Requester Knowledge</param> /// <param name="batchSize">Maximum number of changes to return</param> /// <returns>List of changes</returns> private List<ItemChange> DetectChanges(SyncKnowledge destinationKnowledge, SyncId lowerEnumerationBound, uint batchSize) { List<ItemChange> retVal = new List<ItemChange>(); if (destinationKnowledge == null) throw new ArgumentNullException("destinationKnowledge"); if (batchSize < 0) throw new ArgumentOutOfRangeException("batchSize"); ulong currentLocalTickCount = Replica.TickCount; // Update local knowledge with the current local tick count Replica.CurrentKnowledge.SetLocalTickCount(currentLocalTickCount); // Map the destination knowledge // This maps the knowledge from the remote replica key map (where the destination is replicaKey 0) // to the local replica key map (where the source is replicaKey) // // We do this because our metadata is relative to the local store (and local key map) // (This is typical of most sync providers) SyncKnowledge mappedKnowledge = Replica.CurrentKnowledge.MapRemoteKnowledgeToLocal(destinationKnowledge); foreach (ItemMetadata item in Replica.EntityMetadataItems.Where(x => x.GlobalId.CompareTo(lowerEnumerationBound) >= 0)) { // Check if the current version of the item is known to the destination // We simply check if the update version is contained in his knowledge // If the metadata is for a tombstone, the change is a delete if (!mappedKnowledge.Contains(Replica.ReplicaId, item.GlobalId, item.ChangeVersion)) { ItemChange itemChange = new ItemChange(IdFormats, Replica.ReplicaId, item.GlobalId, item.IsDeleted ? ChangeKind.Deleted : ChangeKind.Update, item.CreationVersion, item.ChangeVersion); // Change isn't known to the remote store, so add it to the batch retVal.Add(itemChange); } // If the batch is full, break // // N.B. Rest of changes will be detected in next batch. Current batch will not be // reenumerated (except in case destination doesn't successfully apply them) as // when destination applies the changes in this batch, they will add them to their // knowledge. if (retVal.Count == batchSize) break; } return retVal; }
public void SaveChangeWithChangeUnits(ItemChange change, SaveChangeWithChangeUnitsContext context) { throw new NotImplementedException("The method or operation is not implemented."); }
public void SaveChangeWithChangeUnits(ItemChange change, SaveChangeWithChangeUnitsContext context) { //Change units are not supported by this sample provider. throw new NotImplementedException(); }
public bool TryGetDestinationVersion(ItemChange sourceChange, out ItemChange destinationVersion) { ItemMetadata metadata = _metadataStore.Metadata.FindItemMetadataById(sourceChange.ItemId); if (metadata == null) { destinationVersion = null; return false; } else { destinationVersion = new ItemChange(_idFormats, _metadataStore.ReplicaId, sourceChange.ItemId, metadata.IsDeleted ? ChangeKind.Deleted : ChangeKind.Update, metadata.CreationVersion, metadata.ChangeVersion); return true; } }