예제 #1
0
        /// <summary>
        /// Returns the most recent (TWEETS_PER_REQUEST) tweets
        /// that match a given state and that are older than a given id
        /// </summary>
        /// <param name="currentState">tweet state to be matched</param>
        /// <param name="olderThanThisNumber">Results should include only tweets that have an id older than this</param>
        /// <returns>Array of tweet ids and their respective states</returns>
        public TweetIdAndStateVM[] GetSelectedTweetsByState(PublishingState currentState, ulong olderThanThisNumber = ulong.MaxValue)
        {
            //1) define the filter: filter by state and date
            Func <SelectedTweet, bool> filter =
                (x) => x.CurrentState == currentState && ulong.Parse(x.TweetId) < olderThanThisNumber;

            //2) apply the filter and return results
            return(GetSelectedTweets(filter));
        }
예제 #2
0
        /// <summary>
        /// Checks the state of the subscriptions.
        /// </summary>
        public void PublishTimerExpired()
        {
            List <Subscription> subscriptionsToDelete = new List <Subscription>();

            lock (m_lock)
            {
                List <QueuedSubscription> liveSubscriptions = new List <QueuedSubscription>(m_queuedSubscriptions.Count);

                // check each available subscription.
                for (int ii = 0; ii < m_queuedSubscriptions.Count; ii++)
                {
                    QueuedSubscription subscription = m_queuedSubscriptions[ii];

                    PublishingState state = subscription.Subscription.PublishTimerExpired();

                    // check for expired subscription.
                    if (state == PublishingState.Expired)
                    {
                        subscriptionsToDelete.Add(subscription.Subscription);
                        ((SubscriptionManager)m_server.SubscriptionManager).SubscriptionExpired(subscription.Subscription);
                        continue;
                    }

                    liveSubscriptions.Add(subscription);

                    // check if idle.
                    if (state == PublishingState.Idle)
                    {
                        subscription.ReadyToPublish = false;
                        continue;
                    }

                    // do nothing if subscription has already been flagged as available.
                    if (subscription.ReadyToPublish)
                    {
                        if (subscription.ReadyToPublish && m_queuedRequests.Count == 0)
                        {
                            if (!m_subscriptionsWaiting)
                            {
                                m_subscriptionsWaiting = true;
                                // TraceState("SUBSCRIPTIONS WAITING");
                            }
                        }

                        continue;
                    }

                    // assign subscription to request if one is available.
                    if (!subscription.Publishing)
                    {
                        AssignSubscriptionToRequest(subscription);
                    }
                }

                // only keep the live subscriptions.
                m_queuedSubscriptions = liveSubscriptions;

                // schedule cleanup on a background thread.
                SubscriptionManager.CleanupSubscriptions(m_server, subscriptionsToDelete);
            }
        }
예제 #3
0
        /// <summary>
        /// Verifies the result of a publish
        /// </summary>
        private bool VerifyPublishResponse(
            ResponseHeader responseHeader,
            Subscription subscription,
            UInt32Collection availableSequenceNumbers,
            bool moreNotifications,
            NotificationMessage notificationMessage,
            StatusCodeCollection results,
            DiagnosticInfoCollection diagnosticInfos)
        {
            /*
            Utils.Trace(
                "PublishReceived: SubId={0} SeqNo={1}, PublishTime={2:mm:ss.fff}, Time={3:mm:ss.fff}",
                subscription.SubscriptionId,
                notificationMessage.SequenceNumber,
                notificationMessage.PublishTime,
                DateTime.UtcNow);
            */

            // check if there is an odd delay.
            if (responseHeader.Timestamp > notificationMessage.PublishTime.AddMilliseconds(100))
            {
                Log(
                    "WARNING. Unexpected delay between PublishTime and ResponseTime. SeqNo={0}, PublishTime={1:hh:mm:ss.fff}, ResponseTime={2:hh:mm:ss.fff}",
                    notificationMessage.SequenceNumber,
                    notificationMessage.PublishTime,
                    responseHeader.Timestamp);
            }

            // save results.
            subscription.AvailableSequenceNumbers = availableSequenceNumbers;

            if (notificationMessage.NotificationData.Count == 0)
            {
                // keep alives do not increment the sequence number.
                if (subscription.NextExpectedSequenceNumber != notificationMessage.SequenceNumber)
                {
                    Log(
                        "Incorrect sequence number for keep alive. SubscriptionId = {0}, Actual = {1}, Expected = {2}", 
                        subscription.SubscriptionId,
                        notificationMessage.SequenceNumber,
                        subscription.NextExpectedSequenceNumber);

                    subscription.Failed = true;
                    return false;
                }

                // save the message.                
                DateTime timestamp = responseHeader.Timestamp;
                DateTime start = subscription.States[subscription.States.Count - 1].Start;

                // check if this is an old request being processed late.
                if (start > timestamp && subscription.States.Count > 1)
                {
                    subscription.States[subscription.States.Count - 2].KeepAlives.Add(timestamp);
                }
                else
                {
                    subscription.States[subscription.States.Count - 1].KeepAlives.Add(timestamp);
                }
            }
            else
            {
                // check for replays.
                if (subscription.NextExpectedSequenceNumber > notificationMessage.SequenceNumber)
                {
                    // check for out of order responses.
                    bool found = false;

                    for (int ii = 0; ii < subscription.MissingSequenceNumbers.Count; ii++)
                    {
                        if (subscription.MissingSequenceNumbers[ii] == notificationMessage.SequenceNumber)
                        {
                            subscription.MissingSequenceNumbers.RemoveAt(ii);
                            found = true;
                            break;
                        }
                    }

                    // oops - duplicate.
                    if (!found)
                    {
                        Log(
                            "Duplicate sequence number for message. SubscriptionId = {0}, Actual = {1}, Expected = {2}",
                            subscription.SubscriptionId,
                            notificationMessage.SequenceNumber,
                            subscription.NextExpectedSequenceNumber);

                        subscription.Failed = true;
                        return false;
                    }
                }
                
                // increment message counter.
                if (notificationMessage.SequenceNumber >= subscription.NextExpectedSequenceNumber)
                {
                    for (uint ii = subscription.NextExpectedSequenceNumber; ii < notificationMessage.SequenceNumber; ii++)
                    {
                        if (!subscription.MissingSequenceNumbers.Contains(ii))
                        {
                            subscription.MissingSequenceNumbers.Add(ii);
                        }
                    }

                    subscription.NextExpectedSequenceNumber = notificationMessage.SequenceNumber+1;
                }
                                                        
                // save the largest received message number (gap exist because of client side threading issues).
                if (subscription.LastReceivedSequenceNumber < notificationMessage.SequenceNumber)
                {
                    subscription.LastReceivedSequenceNumber = notificationMessage.SequenceNumber;
                }

                // save the message.                
                DateTime timestamp = responseHeader.Timestamp;
                DateTime start = subscription.States[subscription.States.Count-1].Start;

                // check if this is an old request being processed late.
                if (start > timestamp && subscription.States.Count > 1)
                {
                    subscription.States[subscription.States.Count - 2].KeepAlives.Add(timestamp);
                }
                else
                {
                    subscription.States[subscription.States.Count - 1].KeepAlives.Add(timestamp);
                }

                subscription.NotificationMessages.Add(notificationMessage);
                subscription.ReceiveTimes.Add(responseHeader.Timestamp);

                // change to keep alive mode.
                if (subscription.StaticData)
                {
                    PublishingState state = new PublishingState();

                    state.KeepAliveCount = subscription.KeepAliveCount;
                    state.PublishingInterval = subscription.PublishingInterval;
                    state.Start = timestamp;
                    state.KeepAliveMode = true;

                    subscription.States[subscription.States.Count-1].End = state.Start;
                    subscription.States.Add(state);
                }

                // save the acknowlegements.
                SaveAcknowledgement(subscription.SubscriptionId, notificationMessage.SequenceNumber);
            }

            return true;
        }
예제 #4
0
        /// <summary>
        /// Creates a subscription.
        /// </summary>
        private bool CreateSubscription(
            double publishingInterval,
            uint lifetimeCount,
            uint keepAliveCount,
            uint maxNotificationsPerPublish,
            bool publishingEnabled,
            byte priority)
        {            
            try
            {
                uint subscriptionId;
                double revisedPublishingInterval;
                uint revisedLifetimeCount;
                uint revisedKeepAliveCount;
                
                Subscription subscription = new Subscription();

                subscription.MaxNotificationsPerPublish = maxNotificationsPerPublish;
                subscription.PublishingEnabled = publishingEnabled;
                subscription.Priority = priority;
                subscription.NextExpectedSequenceNumber = 1;
                subscription.StaticData = true;
                
                lock (m_subscriptions)
                {
                    m_subscriptions.Add(subscription);
                }

                DateTime start = DateTime.UtcNow;

                ResponseHeader responseHeader = Session.CreateSubscription(
                    null,
                    publishingInterval,
                    lifetimeCount,
                    keepAliveCount,
                    maxNotificationsPerPublish,
                    publishingEnabled,
                    priority,
                    out subscriptionId,
                    out revisedPublishingInterval,
                    out revisedLifetimeCount,
                    out revisedKeepAliveCount);

                double elapsedTime = (DateTime.UtcNow - start).TotalMilliseconds;

                if (elapsedTime > 300)
                {
                    Log("WARNING: CreateSubscription took {0}ms. Timing errors may occur.", (DateTime.UtcNow - start).TotalMilliseconds);
                }
                
                subscription.SubscriptionId = subscriptionId;
                subscription.PublishingInterval = revisedPublishingInterval;
                subscription.LifetimeCount = revisedLifetimeCount;
                subscription.KeepAliveCount = revisedKeepAliveCount;

                while (m_outstandingPublishRequests < m_publishPipelineDepth)
                {
                    BeginPublish();
                }
                                
                lock (subscription)
                {
                    PublishingState state = new PublishingState();

                    state.KeepAliveCount = subscription.KeepAliveCount;
                    state.PublishingInterval = subscription.PublishingInterval;
                    state.Start = responseHeader.Timestamp;
                    state.KeepAliveMode = true;

                    subscription.States.Add(state);
                }

                return true;
            }
            catch (Exception e)
            {
                Log(e, "Error creating subscription.", null);
                return false;
            }
        }
예제 #5
0
        /// <summary>
        /// Sets the publishing enable state for the subscriptions.
        /// </summary>
        private bool ModifySubscription(Subscription subscription, double publishingInterval)
        {   
            try
            {        
                double revisedPublishingInterval;
                uint revisedLifetimeCount;
                uint revisedKeepAliveCount;
          
                RequestHeader requestHeader = new RequestHeader();
                requestHeader.ReturnDiagnostics = 0;

                DateTime start = DateTime.UtcNow;

                ResponseHeader responseHeader = Session.ModifySubscription(
                    requestHeader,
                    subscription.SubscriptionId,
                    publishingInterval,
                    subscription.LifetimeCount,
                    subscription.KeepAliveCount,
                    subscription.MaxNotificationsPerPublish,
                    subscription.Priority,
                    out revisedPublishingInterval,
                    out revisedLifetimeCount,
                    out revisedKeepAliveCount);
                
                double elapsedTime = (DateTime.UtcNow - start).TotalMilliseconds;

                if (elapsedTime > 300)
                {
                    Log("WARNING: ModifySubscription took {0}ms. Timing errors may occur.", (DateTime.UtcNow - start).TotalMilliseconds);
                }               

                PublishingState state = new PublishingState();

                state.KeepAliveCount = revisedKeepAliveCount;
                state.PublishingInterval = revisedPublishingInterval;
                state.Start = responseHeader.Timestamp;
                state.KeepAliveMode = true;

                lock (subscription)
                {
                    subscription.PublishingInterval = revisedPublishingInterval;
                    subscription.KeepAliveCount = revisedKeepAliveCount;
                    subscription.LifetimeCount = revisedLifetimeCount;
                    subscription.States[subscription.States.Count-1].End = state.Start;
                    subscription.States.Add(state);
                }

                return true;
            }
            catch (Exception e)
            {
                Log(e, "Error modifying state of subscription {0}.", subscription.SubscriptionId);
                return false;
            } 
        }
예제 #6
0
        /// <summary>
        /// Verifies the keep alive test results.
        /// </summary>
        private bool VerifyKeepAliveTestResults(Subscription subscription, PublishingState state, bool isFirst)
        {
            double keepAlivePeriod = state.KeepAliveCount*state.PublishingInterval;
            double elaspedTime = CalculateInterval(state.Start, state.End);
            double referencePeriod = (state.KeepAliveMode)?keepAlivePeriod:state.PublishingInterval;

            bool success = true;
            DateTime start = state.Start;

            for (int ii = 0; ii < state.KeepAlives.Count; ii++)
            {
                double referencePeriodToUse = referencePeriod;

                // the first keep alive comes with the first publishing interval.
                if (isFirst && ii == 0)
                {
                    referencePeriodToUse = state.PublishingInterval;
                }

                double delta = CalculateInterval(start, state.KeepAlives[ii]);

                if (Math.Abs(referencePeriodToUse - delta) > m_idealTimingError && delta > m_idealTimingError)
                {
                    bool fatal = Math.Abs(referencePeriodToUse - delta) > (referencePeriodToUse + (double)((isFirst)?500:0));

                    Log(
                        "{0}: Notification received at the wrong time for subscription {1}. Index = {2}, Expected = {3}ms, Actual = {4}ms",
                        "TIMING ERROR",
                        subscription.SubscriptionId,
                        ii,
                        referencePeriodToUse,
                        delta);

                    if (fatal)
                    {
                        success = false;
                    }
                }             

                start = state.KeepAlives[ii];
            }

            if ((Math.Truncate(elaspedTime/keepAlivePeriod) > state.KeepAlives.Count))
            {
                double[] deltas = new double[state.KeepAlives.Count];

                for (int ii = 0; ii < state.KeepAlives.Count-1; ii++)
                {
                    deltas[ii] = CalculateInterval(state.KeepAlives[ii], state.KeepAlives[ii + 1]);
                }

                double timingError = Math.Abs((state.KeepAlives.Count + 1) * keepAlivePeriod - elaspedTime);

                // check if the keep alive is an exact multiple of the elapsed time.
                if (timingError > m_idealTimingError && timingError > state.PublishingInterval)
                {
                    bool fatal = Math.Truncate(elaspedTime/keepAlivePeriod) > state.KeepAlives.Count+1;

                    Log(
                        "{0}: Keep alives not received for subscription {1}. , Expected = {2}, Actual = {3}, TimingError={4}",
                        "TIMING ERROR",
                        subscription.SubscriptionId,
                        Math.Truncate(elaspedTime/keepAlivePeriod),
                        state.KeepAlives.Count,
                        timingError);

                    if (fatal)
                    {
                        success = false;
                    }
                }
            }

            return success;
        }