/// <summary> /// Gets the peer metadata engine. /// </summary> /// <param name="engine">The engine.</param> /// <param name="peer">The peer.</param> /// <returns></returns> private IPersistenceEngine GetPeerMetadataEngine(SyncEngine engine, Peer peer) { if (engine.SecondaryMetadataEngine == null || peer == Peer.Client) return engine.MetadataEngine; return engine.SecondaryMetadataEngine; }
/// <summary> /// Gets the last connection information for a given client /// </summary> /// <param name="clientId">The Id of the client the connection should be returns</param> /// <param name="server">The SyncEngine instance for reading connection information </param> /// <returns>The last connection information for a given client</returns> private Entity GetConnection(string clientId, SyncEngine server) { Entity connection = null; IList<Entity> connections = GetPeerMetadataEngine(server, Peer.Server).Load(String.Format("Evaluant:Uss:Sync:Connection[ClientId = '{0}']", clientId)); if (connections.Count > 0) connection = connections[0]; else { connection = new Entity(SyncUtils.CONNECTION); connection[SyncUtils.CLIENTID].Value = clientId; connection[SyncUtils.TRANSACTION].Value = 0; } return connection; }
public SyncCommandProcessor(SyncEngine engine, Transaction transaction, int transactionId) { this.transaction = transaction; this.transactionId = transactionId; this.engine = engine; }
/// <summary> /// Determines whether the specified engine is a central node . /// </summary> /// <param name="engine">The engine.</param> /// <returns> /// <c>true</c> if the specified engine is a central node; otherwise, <c>false</c>. /// </returns> private bool IsCentralNode(SyncEngine engine) { return engine.MetadataEngine != null && engine.SecondaryMetadataEngine != null; }
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 }
private void SmartUpload(SyncEngine client, IPersistenceEngine server) { if (server == null) throw new ArgumentException("The server engine must be not null"); if (client == null) throw new ArgumentException("The client engine must be not null and a SyncProvider"); IList<Entity> commands = GetPeerMetadataEngine(client, Peer.Client).Load("from " + SyncUtils.COMMAND + " c orderby c.Processed, c.Number select c", 1, 0); EntitySet commandsToRemove = ((EntitySet)commands).Clone(); Command[] optimized = OptimizeCommands(client, commands); Transaction t = new Transaction(client.MetadataEngine.Factory.Model); foreach (Command c in optimized) { c.ClientId = client.ClientId; CompoundCreateCommand ccc = c as CompoundCreateCommand; if (ccc != null) foreach (Command cmd in ccc.InnerCommands) cmd.ClientId = client.ClientId; t.PushCommand(c); } t.Commit(server, false); // Deletes the metadata once they are processed t = new Transaction(client.MetadataEngine.Factory.Model); t.Delete(commandsToRemove); t.Commit(client.MetadataEngine, false); }
private void SmartDownload(IPersistenceEngine client, SyncEngine server, string clientId) { if (client == null) throw new ArgumentException("The client engine must be not null"); if (server == null) throw new ArgumentException("The server engine must be not null and a SyncProvider"); Entity connection = GetConnection(clientId, server); int lastSync = connection.GetInt32(SyncUtils.TRANSACTION); Command[] commands = OptimizeCommands((SyncEngine)client, GetPeerMetadataEngine(server, Peer.Server).Load("from Evaluant.Uss.Sync.Command c where (c.ClientId!='" + client + "' || c.ClientId==null) and c.Transaction>" + lastSync.ToString() + " orderby c.Processed, c.Number", 1, 0) ); 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)); Transaction t = new Transaction(client.Factory.Model); foreach (Command c in commands) { 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); if (key != null && key != string.Empty && filters.Count > 0 && !dataToProcess.Contains(key)) continue; c.IgnoreMetadata = true; t.PushCommand(c); } t.Commit(client, false); Entity info = GetPeerMetadataEngine(server, Peer.Server).Load(SyncUtils.INFO)[0]; connection[SyncUtils.TRANSACTION].Value = info.GetInt32(SyncUtils.TRANSACTION); IPersistenceEngine peerMetadataEngine = GetPeerMetadataEngine(server, Peer.Server); t = new Transaction(peerMetadataEngine.Factory.Model); t.Serialize(connection); t.Commit(peerMetadataEngine, false); }
/// <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; }