public Replicator(IDataStore destination, ReplicationBehavior behavior, bool addIdentityToDestination) { if (behavior != ReplicationBehavior.ReplicateAndDelete) { throw new NotSupportedException("Only ReplicateAndDelete is currently supported"); } if (destination == null) { throw new ArgumentNullException(); } Registrations = new Registrations(); CreateIdentityFieldInReplicatedTable = addIdentityToDestination; Behavior = behavior; m_destination = destination; ReplicationPeriod = DefaultReplicationPeriod; MaxReplicationBatchSize = DefaultBatchSize; m_dataAvailable = new AutoResetEvent(false); m_typeCounts = new Dictionary <Type, int>(); m_nameCounts = new Dictionary <string, int>(); }
void m_source_AfterInsert(object sender, EntityInsertArgs e) { // if we have an insert on a replicated entity, don't wait for the full period, let the replication proc know immediately // TODO: add preemption? bool shouldRaise = false; lock (Registrations) { if (Registrations.Contains(e.EntityName)) { shouldRaise = true; } else if (Registrations.Contains(e.Item.GetType())) { shouldRaise = true; } } if (shouldRaise) { ThreadPool.QueueUserWorkItem(delegate { m_dataAvailable.Set(); }); } }
private bool DoReplicationForPriority(ReplicationPriority priority) { bool dataSent = false; // loop through all registered entities lock (Registrations) { foreach (var registration in Registrations.GetNameRegistrations(priority)) { var items = m_source.Select(registration.LocalName).Take(MaxReplicationBatchSize); foreach (var item in items) { item.EntityName = registration.ReplicatedName; m_destination.Insert(item); item.EntityName = registration.LocalName; m_source.Delete(item); // increment the count m_nameCounts[registration.LocalName]++; dataSent = true; // yield so we're not chewing up processor time Thread.Sleep(0); } } foreach (var registration in Registrations.GetTypeRegistrations(priority)) { var items = m_source.Select(registration.Type).Take(MaxReplicationBatchSize); foreach (var item in items) { m_destination.Insert(item); m_source.Delete(item); // increment the count m_typeCounts[registration.Type]++; dataSent = true; // yield so we're not chewing up processor time Thread.Sleep(0); } } return(dataSent); } }
public void RegisterEntity(Type entityType, ReplicationPriority priority) { lock (Registrations) { Registrations.AddType(entityType, priority); lock (m_typeCounts) { if (!m_typeCounts.ContainsKey(entityType)) { m_typeCounts.Add(entityType, 0); } } // TODO: look for failure and cache if it does (e.g. not connected scenarios) m_destination.AddType(entityType); } }
public void RegisterEntity(string entityName, string replicatedName, ReplicationPriority priority) { lock (Registrations) { Registrations.AddName(entityName, replicatedName, priority); lock (m_nameCounts) { if (!m_nameCounts.ContainsKey(entityName)) { m_nameCounts.Add(entityName, 0); } } // TODO: look for failure and cache if it does (e.g. not connected scenarios) var definition = m_source.DiscoverDynamicEntity(entityName); definition.EntityName = replicatedName; // the replicated entity cannot use the same auto-increment field as the local table or we'll end up with replication problems where local IDs don't match remote IDs if (CreateIdentityFieldInReplicatedTable) { var existing = definition.Fields.KeyField; if (existing != null) { existing.IsPrimaryKey = false; } definition.EntityAttribute.KeyScheme = KeyScheme.Identity; definition.Fields.Add(new FieldAttribute("ReplID", System.Data.DbType.Int32, true), true); } else { definition.EntityAttribute.KeyScheme = KeyScheme.None; } m_destination.RegisterDynamicEntity(definition, true); } }