/// <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); } }
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; } }
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); }
// the node is suddenly out, remove it from database // (it was a concurrency delete attempt - we should restore the existing version) private void ForgetItem(SaveChangeContext context, ItemMetadata item, Exception e) { _metadataStore.Metadata.RemoveItemMetadata(new List <SyncId> { item.GlobalId }); OnDemandedResync(); context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); }
/// <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); } }
/// <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 void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { ItemMetadata item = null; T data = default(T); try { switch (saveChangeAction) { case SaveChangeAction.Create: try { //Do duplicate detection here item = _metaData.FindItemMetadataById(change.ItemId); if (item != null) { throw new SyncProviderException("SaveItemChange must not have Create action for existing items."); } item = _metaData.CreateItemMetadata(change.ItemId, change.CreationVersion); item.ChangeVersion = change.ChangeVersion; data = ConvertFromTransferData(context.ChangeData); CreateDataItem(change, item, data); SaveItemMetadata(item); } catch (Exception e) { throw new SyncProviderException(e, SaveChangeAction.Create); } break; case SaveChangeAction.UpdateVersionAndData: case SaveChangeAction.UpdateVersionOnly: try { item = _metaData.FindItemMetadataById(change.ItemId); if (null == item) { throw new SyncProviderException("Item Not Found in Store!?"); } item.ChangeVersion = change.ChangeVersion; if (saveChangeAction == SaveChangeAction.UpdateVersionOnly) { SaveItemMetadata(item); } else //Also update the data. { data = ConvertFromTransferData(context.ChangeData); UpdateDataItem(change, item, data); SaveItemMetadata(item); } } catch (Exception e) { throw new SyncProviderException(e, SaveChangeAction.UpdateVersionAndData); } break; case SaveChangeAction.DeleteAndStoreTombstone: try { 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 SyncProviderException("Invalid ChangeType"); } item.ChangeVersion = change.ChangeVersion; SaveItemMetadata(item); DeleteDataItem(change, item, data); //item.GlobalId.GetGuidId()); } catch (Exception e) { throw new SyncProviderException(e, SaveChangeAction.DeleteAndStoreTombstone); } 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: try { item = _metaData.FindItemMetadataById(change.ItemId); if (null == item) { throw new SyncProviderException("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... T dataItem = GetDataItem(item); if (dataItem == null) { throw new SyncProviderException("data item not found for merge"); } data = ConvertFromTransferData(context.ChangeData); data = MergeDataItem(dataItem, data); UpdateDataItem(change, item, data); SaveItemMetadata(item); } } catch (Exception e) { throw new SyncProviderException(e, SaveChangeAction.UpdateVersionAndMergeData); } break; case SaveChangeAction.DeleteAndRemoveTombstone: try { item = _metaData.FindItemMetadataById(change.ItemId); if (item != null) { _metaData.RemoveItemMetadata(new SyncId[] { item.GlobalId }); } data = ConvertFromTransferData(context.ChangeData); DeleteDataItem(change, item, data); } catch (Exception e) { throw new SyncProviderException(e, SaveChangeAction.DeleteAndRemoveTombstone); } break; } } catch (SyncProviderException e) { Exception exception = e.InnerException != null ? e.InnerException : e; string itemDescr = e.SaveChangeAction.ToString(); string errDescr = e.Message + "[" + e.InnerException != null?e.InnerException.ToString() : string.Empty + "]"; RecoverableErrorData recoverableError = new RecoverableErrorData(exception, itemDescr, errDescr); context.RecordRecoverableErrorForItem(recoverableError); } }
// the node is suddenly out, remove it from database // (it was a concurrency delete attempt - we should restore the existing version) private void ForgetItem(SaveChangeContext context, ItemMetadata item, Exception e) { _metadataStore.Metadata.RemoveItemMetadata(new List<SyncId> { item.GlobalId }); OnDemandedResync(); context.RecordRecoverableErrorForItem(new RecoverableErrorData(e)); }
/// <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)); } }
/// <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(); } }