예제 #1
0
        public IList <IQueuedEvent> BatchEvents(IList <IQueuedEvent> eventItems)
        {
            List <IQueuedEvent> outputEvents;

            if (eventItems.Count == 0)
            {
                outputEvents = new List <IQueuedEvent>(0);
                return(outputEvents);
            }
            if (eventItems.Count == 1)
            {
                outputEvents = new List <IQueuedEvent>(1);
                IQueuedEvent soleEvent = eventItems[0];
                outputEvents.Add(soleEvent);
                return(outputEvents);
            }
            outputEvents = new List <IQueuedEvent>();
            IList <IQueuedEvent> currentBatchableEvents = new List <IQueuedEvent>();

            IList <IQueuedEvent> batchedEvents;
            IEventBatcher        currentEventBatcher = null;

            for (int i = 0, size = eventItems.Count; i < size; i++)
            {
                IQueuedEvent  queuedEvent  = eventItems[i];
                Object        eventObject  = queuedEvent.EventObject;
                IEventBatcher eventBatcher = typeToBatchersDict.GetExtension(eventObject.GetType());
                if (eventBatcher != null)
                {
                    if (currentEventBatcher != null && !eventBatcher.Equals(currentEventBatcher))
                    {
                        batchedEvents = BatchEventsIntern(currentBatchableEvents, currentEventBatcher);
                        if (batchedEvents != null)
                        {
                            outputEvents.AddRange(batchedEvents);
                        }
                        currentBatchableEvents.Clear();
                    }
                    currentEventBatcher = eventBatcher;
                    currentBatchableEvents.Add(queuedEvent);
                    continue;
                }
                batchedEvents = BatchEventsIntern(currentBatchableEvents, currentEventBatcher);
                if (batchedEvents != null)
                {
                    outputEvents.AddRange(batchedEvents);
                }
                currentBatchableEvents.Clear();
                currentEventBatcher = null;
                outputEvents.Add(queuedEvent);
            }
            batchedEvents = BatchEventsIntern(currentBatchableEvents, currentEventBatcher);
            if (batchedEvents != null)
            {
                outputEvents.AddRange(batchedEvents);
            }
            return(outputEvents);
        }
예제 #2
0
        public void FlushEventQueue()
        {
            IList <IList <IQueuedEvent> > eventQueueList = eventQueueTL.Value;

            if (eventQueueList == null)
            {
                return;
            }
            IList <IQueuedEvent> eventQueue = eventQueueList[eventQueueList.Count - 1];

            eventQueueList.RemoveAt(eventQueueList.Count - 1);
            if (eventQueueList.Count == 0)
            {
                eventQueueTL.Value = null;
                eventQueueList     = null;
            }
            if (eventQueueList != null)
            {
                // Current flush is not the top-most flush. So we have to re-insert the events
                // One level out of our current level. We maintain the order at which the events have been queued
                IList <IQueuedEvent> outerEventQueue = eventQueueList[eventQueueList.Count - 1];
                for (int a = 0, size = eventQueue.Count; a < size; a++)
                {
                    IQueuedEvent queuedEvent = eventQueue[a];
                    outerEventQueue.Add(queuedEvent);
                }
                return;
            }
            IList <IQueuedEvent> batchedEvents = BatchEvents(eventQueue);

            for (int a = 0, size = batchedEvents.Count; a < size; a++)
            {
                IQueuedEvent batchedEvent = batchedEvents[a];
                HandleEvent(batchedEvent.EventObject, batchedEvent.DispatchTime, batchedEvent.SequenceNumber);
            }
        }
예제 #3
0
        protected void BatchEventsIntern(IList <IQueuedEvent> batchableEvents, IList <IQueuedEvent> targetBatchedEvents)
        {
            if (batchableEvents.Count == 1)
            {
                targetBatchedEvents.Add(batchableEvents[0]);
                return;
            }
            if (batchableEvents.Count == 0)
            {
                return;
            }
            // Check if all datachanges are in the same localsource state so that we can group them

            IDictionary <IObjRef, IObjRef> touchedObjRefSet = new Dictionary <IObjRef, IObjRef>();

            ISet <IObjRef> touchedAsInsertObjRefDict = new HashSet <IObjRef>();
            ISet <IObjRef> touchedAsUpdateObjRefDict = new HashSet <IObjRef>();
            ISet <IObjRef> touchedAsDeleteObjRefDict = new HashSet <IObjRef>();

            int      splitIndex = -1;
            DateTime?lastDCETime = null, lastQueuedEventTime = null;
            long     lastSequenceNumber = -1;
            bool?    isLocalSource      = null;

            for (int a = 0, size = batchableEvents.Count; a < size; a++)
            {
                IQueuedEvent batchableEvent = batchableEvents[a];
                IDataChange  dataChange     = (IDataChange)batchableEvent.EventObject;

                if (isLocalSource.HasValue && isLocalSource.Value != dataChange.IsLocalSource)
                {
                    // IsLocalSource differs, we can not batch the events here
                    splitIndex = a;
                    break;
                }
                isLocalSource       = dataChange.IsLocalSource;
                lastQueuedEventTime = batchableEvent.DispatchTime;
                lastDCETime         = dataChange.ChangeTime;
                lastSequenceNumber  = batchableEvent.SequenceNumber;

                IList <IDataChangeEntry> insertsOfItem = dataChange.Inserts;
                IList <IDataChangeEntry> updatesOfItem = dataChange.Updates;
                IList <IDataChangeEntry> deletesOfItem = dataChange.Deletes;

                foreach (IDataChangeEntry insertOfItem in insertsOfItem)
                {
                    if (insertOfItem.EntityType == null)
                    {
                        continue;
                    }
                    IObjRef objRef = ExtractAndMergeObjRef(insertOfItem, touchedObjRefSet);

                    touchedAsInsertObjRefDict.Add(objRef);
                }
                foreach (IDataChangeEntry updateOfItem in updatesOfItem)
                {
                    if (updateOfItem.EntityType == null)
                    {
                        continue;
                    }
                    IObjRef objRef = ExtractAndMergeObjRef(updateOfItem, touchedObjRefSet);

                    if (touchedAsInsertObjRefDict.Contains(objRef))
                    {
                        // Object is still seen as new in this batch sequence
                        // So we ignore the update event for this item. The ObjRef already has the updated version
                        continue;
                    }
                    touchedAsUpdateObjRefDict.Add(objRef);
                }
                foreach (IDataChangeEntry deleteOfItem in deletesOfItem)
                {
                    if (deleteOfItem.EntityType == null)
                    {
                        continue;
                    }
                    IObjRef objRef = ExtractAndMergeObjRef(deleteOfItem, touchedObjRefSet);

                    // Object can be removed from the queue because it has been updated AND deleted within the same batched sequence
                    // From the entities point of view there is nothing we are interested in
                    touchedAsUpdateObjRefDict.Remove(objRef);

                    if (!touchedAsInsertObjRefDict.Remove(objRef))
                    {
                        // Object will only be stored as deleted if it existed BEFORE the batched sequence
                        touchedAsDeleteObjRefDict.Add(objRef);
                    }
                }
            }
            if (splitIndex != -1 && splitIndex < batchableEvents.Count - 1)
            {
                // Cleanup garbage
                touchedAsInsertObjRefDict.Clear();
                touchedAsUpdateObjRefDict.Clear();
                touchedAsDeleteObjRefDict.Clear();
                touchedObjRefSet.Clear();

                SplitDataChangeBatch(batchableEvents, splitIndex, targetBatchedEvents);
            }
            else
            {
                IList <IDataChangeEntry> inserts = touchedAsInsertObjRefDict.Count > 0 ? new List <IDataChangeEntry>(touchedAsInsertObjRefDict.Count) : EmptyList.Empty <IDataChangeEntry>();
                IList <IDataChangeEntry> updates = touchedAsUpdateObjRefDict.Count > 0 ? new List <IDataChangeEntry>(touchedAsUpdateObjRefDict.Count) : EmptyList.Empty <IDataChangeEntry>();
                IList <IDataChangeEntry> deletes = touchedAsDeleteObjRefDict.Count > 0 ? new List <IDataChangeEntry>(touchedAsDeleteObjRefDict.Count) : EmptyList.Empty <IDataChangeEntry>();
                foreach (IObjRef objRef in touchedAsInsertObjRefDict)
                {
                    inserts.Add(new DataChangeEntry(objRef.RealType, objRef.IdNameIndex, objRef.Id, objRef.Version));
                }
                foreach (IObjRef objRef in touchedAsUpdateObjRefDict)
                {
                    updates.Add(new DataChangeEntry(objRef.RealType, objRef.IdNameIndex, objRef.Id, objRef.Version));
                }
                foreach (IObjRef objRef in touchedAsDeleteObjRefDict)
                {
                    deletes.Add(new DataChangeEntry(objRef.RealType, objRef.IdNameIndex, objRef.Id, objRef.Version));
                }
                DataChangeEvent compositeDataChange = new DataChangeEvent(inserts, updates, deletes, lastDCETime.Value, isLocalSource.Value);
                targetBatchedEvents.Add(new QueuedEvent(compositeDataChange, lastQueuedEventTime.Value, lastSequenceNumber));
            }
        }