private void SmartUploadDownload(SyncEngine client, SyncEngine server) { Transaction t; #region Download Entity connection = GetConnection(client.ClientId, server); int lastTransactionId = GetLastTransaction(connection); IList<Entity> serverCommands = GetPeerMetadataEngine(server, Peer.Server).Load(String.Format("from {2} c where (c.ClientId != '{0}' || c.ClientId==null)) && Transaction > {1} orderby c.Processed, c.Number", client.ClientId, lastTransactionId, SyncUtils.COMMAND), 1, 0); IList<Entity> clientCommands = GetPeerMetadataEngine(client, Peer.Client).Load("from " + SyncUtils.COMMAND + " c orderby Processed, Number select c", 1, 0); // Detecting ClientCreateOrUpdateClientDelete to delete the UpdateCommands which occured before a delete IPersistenceEngine peerMetadataEngine = GetPeerMetadataEngine(client, Peer.Client); t = new Transaction(peerMetadataEngine.Factory.Model); for (int i = clientCommands.Count - 1; i >= 0; i--) { Entity ce = clientCommands[i]; if (ce.Type == SyncUtils.DELETE_ENTITY) { for (int j = i - 1; j >= 0; j--) { { Entity se = clientCommands[j]; if (ApplyOnTheSameEntity(ce, se)) { clientCommands.RemoveAt(j); t.Delete(se); i--; if (se.Type == SyncUtils.CREATE_ENTITY) { clientCommands.Remove(ce); t.Delete(ce); i--; } } } } } } t.Commit(peerMetadataEngine, false); // Detecting ClientDeleteServerDelete to ignore the Delete commands from the Client for (int i = clientCommands.Count - 1; i >= 0; i--) { Entity ce = clientCommands[i]; if (ce.Type == SyncUtils.DELETE_ENTITY) { // A delete occured on the client, verify if this command is already on the server for (int j = serverCommands.Count - 1; j >= 0; j--) { Entity se = serverCommands[j]; if (se.Type == SyncUtils.DELETE_ENTITY && se.GetString(SyncUtils.PARENTID) == ce.GetString(SyncUtils.PARENTID)) { clientCommands.Remove(ce); serverCommands.Remove(se); } } } } // Detecting ClientDeleteServerUpdate to delete the UpdateCommands which occured later on the server t = new Transaction(GetPeerMetadataEngine(server, Peer.Server).Factory.Model); for (int i = clientCommands.Count - 1; i >= 0; i--) { Entity ce = clientCommands[i]; if (ce.Type == SyncUtils.DELETE_ENTITY) { // A delete occured on the client, verify no update command where set on the server for (int j = serverCommands.Count - 1; j >= 0; j--) { Entity se = serverCommands[j]; if (se.Type == SyncUtils.UPDATE_ATTRIBUTE && se.GetString(SyncUtils.PARENTID) == ce.GetString(SyncUtils.PARENTID)) { serverCommands.Remove(se); t.Delete(se); } } } } t.Commit(GetPeerMetadataEngine(server, Peer.Server), false); // Detecting ServerDeleteClientUpdate to delete the UpdateCommands which occured later on the client t = new Transaction(GetPeerMetadataEngine(server, Peer.Client).Factory.Model); for (int i = serverCommands.Count - 1; i >= 0; i--) { Entity se = serverCommands[i]; if (se.Type == SyncUtils.DELETE_ENTITY) { // A delete occured on the server, verify no update command where set on the client for (int j = clientCommands.Count - 1; j >= 0; j--) { Entity ce = clientCommands[j]; if (ce.Type == SyncUtils.UPDATE_ATTRIBUTE && ce.GetString(SyncUtils.PARENTID) == se.GetString(SyncUtils.PARENTID)) { clientCommands.Remove(ce); t.Delete(ce); } } } } t.Commit(GetPeerMetadataEngine(client, Peer.Client), false); // Detecting ServerUpdateClientUpdate to delete the UpdateCommands which occured later on the client Transaction ct = new Transaction(GetPeerMetadataEngine(server, Peer.Client).Factory.Model); Transaction st = new Transaction(GetPeerMetadataEngine(server, Peer.Server).Factory.Model); for (int i = serverCommands.Count - 1; i >= 0; i--) { Entity se = serverCommands[i]; if (se.Type == SyncUtils.UPDATE_ATTRIBUTE) { for (int j = clientCommands.Count - 1; j >= 0; j--) { Entity ce = clientCommands[j]; if (ce.Type == SyncUtils.UPDATE_ATTRIBUTE && ce.GetString(SyncUtils.PARENTID) == se.GetString(SyncUtils.PARENTID) && ce.GetString(SyncUtils.NAME) == se.GetString(SyncUtils.NAME)) { ConflictEventArgs args = new ConflictEventArgs(client.CreateCommand(ce), client.CreateCommand(se), SyncConflict.ClientUpdateServerUpdate); if (Conflict != null) Conflict(this, args); if (args.Resolution == ConflictResolution.ClientWins) { serverCommands.Remove(se); st.Delete(se); } else { clientCommands.Remove(ce); ct.Delete(ce); } } } } } ct.Commit(GetPeerMetadataEngine(client, Peer.Client), false); st.Commit(GetPeerMetadataEngine(server, Peer.Server), false); EntitySet clientCommandsToRemove = ((EntitySet)clientCommands).Clone(); EntitySet serverCommandsToRemove = ((EntitySet)serverCommands).Clone(); Command[] optimizedClientCommands = OptimizeCommands(client, clientCommands); Command[] optimizedServerCommands = OptimizeCommands(server, serverCommands); StringCollection dataToProcess = new StringCollection(); foreach (string filter in filters) foreach (Entity e in server.Load(filter)) dataToProcess.Add(string.Concat(e.Type, SEPARATOR, e.Id)); t = new Transaction(client.Factory.Model); foreach (Command c in optimizedServerCommands) { string key = string.Empty; CompoundCreateCommand ccc = c as CompoundCreateCommand; if (ccc != null) key = string.Concat(ccc.Type, SEPARATOR, ccc.ParentId); CompoundUpdateCommand cuc = c as CompoundUpdateCommand; if (cuc != null) key = string.Concat(cuc.ParentType, SEPARATOR, cuc.ParentId); DeleteEntityCommand dec = c as DeleteEntityCommand; if (dec != null) key = string.Concat(dec.Type, SEPARATOR, dec.ParentId); DeleteAttributeCommand dac = c as DeleteAttributeCommand; if (dac != null) key = string.Concat(dac.ParentType, SEPARATOR, dac.ParentId); CreateReferenceCommand crc = c as CreateReferenceCommand; if (crc != null) key = string.Concat(crc.ParentType, SEPARATOR, crc.ParentId); DeleteReferenceCommand drc = c as DeleteReferenceCommand; if (drc != null) key = string.Concat(drc.ParentType, SEPARATOR, drc.ParentId); if (key != null && key != string.Empty && filters.Count > 0 && !dataToProcess.Contains(key)) continue; c.IgnoreMetadata = true; t.PushCommand(c); } t.Commit(client, false); #endregion #region Upload if (optimizedClientCommands.Length > 0) { t = new Transaction(server.Factory.Model); t.PushCommand(optimizedClientCommands); t.Commit(server, false); } // Updates the last transaction id for the client Entity info = GetPeerMetadataEngine(server, Peer.Server).Load(SyncUtils.INFO)[0]; connection[SyncUtils.TRANSACTION].Value = info.GetInt32(SyncUtils.TRANSACTION); t = new Transaction(GetPeerMetadataEngine(server, Peer.Server).Factory.Model); t.Serialize(connection); t.Commit(GetPeerMetadataEngine(server, Peer.Server), false); // Deletes the metadata once they are processed if (clientCommands.Count > 0) { t = new Transaction(GetPeerMetadataEngine(server, Peer.Client).Factory.Model); t.Delete(clientCommandsToRemove); t.Commit(GetPeerMetadataEngine(client, Peer.Client), false); } // Deletes all tombstoned server commands if (tombstone != TimeSpan.MaxValue) { serverCommands = GetPeerMetadataEngine(server, Peer.Server).Load("from Evaluant.Uss.Sync.Command c where c.Processed > #" + DateTime.Now.Add(-tombstone) + "# select c"); t = new Transaction(GetPeerMetadataEngine(server, Peer.Server).Factory.Model); t.Delete(serverCommandsToRemove); t.Commit(GetPeerMetadataEngine(server, Peer.Server), false); } #endregion }
/// <summary> /// Creates Compound commands if necessary /// </summary> /// <param name="commands"></param> private Command[] OptimizeCommands(SyncEngine engine, IList<Entity> commands) { if (commands == null) throw new ArgumentNullException("commands"); if (commands.Count == 0) return new Command[0]; HashedList<Command> optimizedCommands = new HashedList<Command>(); System.Collections.Generic.List<CompoundCreateCommand> createdCommands = new System.Collections.Generic.List<CompoundCreateCommand>(); int j; for (int i = 0; i < commands.Count; i++) { Entity e = commands[i]; string currentId = e.GetString(SyncUtils.PARENTID); int transaction = e.GetInt32(SyncUtils.TRANSACTION); switch (e.Type) { case SyncUtils.CREATE_ENTITY: string createType = e.GetString(SyncUtils.TYPE); j = i + 1; CompoundCreateCommand ccc = new CompoundCreateCommand(currentId, createType, new List<AttributeCommand>()); CompoundCreateCommand actual = createdCommands.Find(delegate(CompoundCreateCommand toFind) { return toFind.ClientId == ccc.ClientId && toFind.ParentId == ccc.ParentId && toFind.Type == ccc.Type; }); if (actual == null) { createdCommands.Add(ccc); optimizedCommands.Add(ccc); while (j < commands.Count) { string subType = commands[j].GetString(SyncUtils.PARENTTYPE); string subId = commands[j].GetString(SyncUtils.PARENTID); int subTransaction = commands[j].GetInt32(SyncUtils.TRANSACTION); string subCommand = commands[j].Type; if (commands[j].Type == SyncUtils.CREATE_ATTRIBUTE && subId == currentId && subType == createType) { if (subTransaction != transaction) break; ccc.InnerCommands.Add((AttributeCommand)engine.CreateCommand(commands[j])); commands.RemoveAt(j); } else { j++; } } } else { optimizedCommands.Remove(actual); optimizedCommands.Add(ccc); createdCommands.Remove(actual); createdCommands.Add(ccc); } break; case SyncUtils.UPDATE_ATTRIBUTE: string updateType = e.GetString(SyncUtils.PARENTTYPE); j = i + 1; CompoundUpdateCommand cuc = new CompoundUpdateCommand(currentId, updateType, new List<AttributeCommand>()); cuc.InnerCommands.Add((AttributeCommand)engine.CreateCommand(commands[i])); optimizedCommands.Add(cuc); while (j < commands.Count) { string subType = commands[j].GetString(SyncUtils.PARENTTYPE); string subId = commands[j].GetString(SyncUtils.PARENTID); int subTransaction = commands[j].GetInt32(SyncUtils.TRANSACTION); string subCommand = commands[j].Type; if (commands[j].Type == SyncUtils.UPDATE_ATTRIBUTE && subId == currentId && subType == updateType) { if (subTransaction != transaction) break; cuc.InnerCommands.Add((AttributeCommand)engine.CreateCommand(commands[j])); commands.RemoveAt(j); } else { j++; } } break; default: optimizedCommands.Add(engine.CreateCommand(e)); break; } } Command[] result = new Command[optimizedCommands.Count]; for (int i = 0; i < result.Length; i++) result[i] = (Command)optimizedCommands[i]; return result; }