public string GetDbState() { JObject state = new JObject(); var knowledge = GenerateLocalKnowledge().OrderBy((ri) => { return(ri.ReplicaId + ri.ReplicaTickCount.ToString()); }); state.Add("knowledge", SyncUtil.KnowledgeToJson(knowledge)); foreach (var itemType in GetItemTypes()) { var handler = HandlerForItemType(itemType); JArray items = new JArray(); IDbCommand selectCommand = _connection.CreateCommand(); selectCommand.CommandText = String.Format("SELECT CreatedReplica, CreatedTickCount, ModifiedReplica, ModifiedTickCount FROM {0}", handler.DbTable); IList <ISyncableItemInfo> itemInfos = new List <ISyncableItemInfo>(); using (IDataReader reader = selectCommand.ExecuteReader()) { while (reader.Read()) { IReplicaInfo createdReplicaInfo = ReplicaInfoFromDataReader(reader, "Created"); IReplicaInfo modifiedReplicaInfo = ReplicaInfoFromDataReader(reader, "Modified"); itemInfos.Add(new SyncableItemInfo { ItemType = handler.TypeName, Created = createdReplicaInfo, Modified = modifiedReplicaInfo, Deleted = false }); } } var sortedItemInfos = itemInfos.OrderBy((ii) => { return(ii.Created.ReplicaId + ii.Created.ReplicaTickCount.ToString()); }); foreach (var syncItemInfo in sortedItemInfos) { JObject builder = SyncUtil.JsonItemFromSyncableItemInfo(syncItemInfo); BuildItemData(syncItemInfo, builder); items.Add(builder); } state.Add(itemType, items); } return(state.ToString()); }
private async Task PushChanges() { ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.FindingLocalChanges, PercentComplete = 0, Message = "Finding local changes" }); var request = new JObject { { "sessionID", _remoteSessionId } }; var localKnowledge = _store.GenerateLocalKnowledge(); var changedItemInfos = _store.LocateChangedItems(_remoteKnowledge).ToList(); int totalChanges = changedItemInfos.Count(); request.Add(new JProperty("knowledge", SyncUtil.KnowledgeToJson(localKnowledge))); request.Add(new JProperty("changeCount", totalChanges)); await _transport.TransportAsync(SyncEndpoint.PutChanges, request); ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.FindingLocalChanges, PercentComplete = 100, Message = String.Format("Found {0} local changes", totalChanges) }); ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.UploadingLocalChanges, PercentComplete = 0, Message = String.Format("Uploading {0} local changes", totalChanges) }); int maxBatchCount = PushMaxBatchCount; int maxBatchSize = PushMaxBatchSize; long startTick = Environment.TickCount; int previousPercentComplete = -1; int i = 0; var batchArray = new JArray(); int batchSize = 0; foreach (ISyncableItemInfo syncItemInfo in changedItemInfos) { i++; int percentComplete = ((i * 100) / totalChanges); if (percentComplete != previousPercentComplete) { ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.UploadingLocalChanges, PercentComplete = 100, Message = String.Format("Uploading local changes, {0}% complete ({1})", percentComplete, String.Format("Averaging {0}ms/item over {1} items", (Environment.TickCount - startTick) / i, i)) }); } previousPercentComplete = percentComplete; var builder = SyncUtil.JsonItemFromSyncableItemInfo(syncItemInfo); if (!syncItemInfo.Deleted) { _store.BuildItemData(syncItemInfo, builder); } var singleItemRequest = new JObject { { "changeNumber", i }, { "item", builder } }; batchSize += singleItemRequest.ToString().Length; batchArray.Add(singleItemRequest); if (i == totalChanges || (i % maxBatchCount) == 0 || batchSize >= maxBatchSize) { var batchRequest = new JObject { { "sessionID", _remoteSessionId }, { "batch", batchArray } }; await _transport.TransportAsync(SyncEndpoint.PutItemDataBatch, batchRequest); batchArray = new JArray(); batchSize = 0; } } ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.UploadingLocalChanges, PercentComplete = 100, Message = String.Format("Uploaded {0} local changes", totalChanges) }); await ApplyChanges(totalChanges); }
private async Task <IEnumerable <SyncConflict> > PullChanges() { ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.FindingRemoteChanges, PercentComplete = 0, Message = "Looking for remote changes" }); var request = new JObject { { "sessionID", _remoteSessionId } }; var localKnowledge = _store.GenerateLocalKnowledge().ToList(); request.Add(new JProperty("knowledge", SyncUtil.KnowledgeToJson(localKnowledge))); JObject response = await _transport.TransportAsync(SyncEndpoint.GetChanges, request); _remoteKnowledge = SyncUtil.KnowledgeFromJson(response["knowledge"]); var totalChanges = (int)response["totalChanges"]; ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.FindingRemoteChanges, PercentComplete = 100, Message = String.Format("Found {0} remote changes", totalChanges) }); ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.DownloadingRemoteChanges, PercentComplete = 0, Message = String.Format("Downloading {0} remote changes", totalChanges) }); using (var connection = _syncSessionDbConnectionProvider.GetSyncSessionDbConnection(_localSessionId)) { connection.ExecuteNonQuery("BEGIN"); SessionDbHelper.ClearSyncItems(connection); long startTick = Environment.TickCount; int previousPercentComplete = -1; for (int i = 1; i <= totalChanges;) { i += await SaveChangesBatch(connection, localKnowledge, i); int percentComplete = ((i * 100) / totalChanges); if (percentComplete != previousPercentComplete) { ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.DownloadingRemoteChanges, PercentComplete = percentComplete, Message = String.Format("Downloading remote changes, {0}% complete ({1})", percentComplete, String.Format("Averaging {0}ms/item over {1} items", (Environment.TickCount - startTick) / i, i)) }); } previousPercentComplete = percentComplete; } connection.ExecuteNonQuery("COMMIT"); ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.DownloadingRemoteChanges, PercentComplete = 100, Message = String.Format("Downloaded all {0} remote changes", totalChanges) }); ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.CheckingForConflicts, PercentComplete = 0, Message = "Looking for conflicts" }); var conflicts = new List <SyncConflict>(); conflicts.AddRange(CheckForDuplicates(connection)); conflicts.AddRange(LoadConflicts(connection)); ReportProgressAndCheckCacellation(new SyncProgress { Stage = SyncStage.CheckingForConflicts, PercentComplete = 100, Message = String.Format("Found {0} conflicts", conflicts.Count) }); return(conflicts); } }