コード例 #1
0
ファイル: dqstrategy.c プロジェクト: OpenMAMA/OpenMAMA
/*
    Responding to a message with a sender id different to the previous one
    received is now straightforward.

    We simply accept that this is the next expected message and reset the
    context state - all is OK
 */
static mama_status
handleFTTakeover (dqStrategy        strategy,
                  mamaMsg           msg,
                  int               msgType,
                  mamaDqContext*    ctx,
                  mama_seqnum_t     seqNum,
                  mama_u64_t        senderId,
                  int               recoverOnRecap)
{
    const char*         symbol  = NULL;
    mamaSubscription_getSymbol (self->mSubscription, &symbol);

    mama_log (MAMA_LOG_LEVEL_NORMAL, "Detected FT takeover. "
            "Original SenderId: %llu. New SenderId: %llu. "
            "Previous SeqNum: %u. New SeqNum: %u. [%s]",
            ctx->mSenderId, senderId, ctx->mSeqNum, seqNum, symbol);

    if (recoverOnRecap)
    {
        ctx->mSeqNum = seqNum;
        ctx->mDQState = DQ_STATE_WAITING_FOR_RECAP_AFTER_FT;
    }
    else
    {
    resetDqState (strategy, ctx);
    
    /*In all cases we reset the data quality context*/
    dqStrategyImpl_resetDqContext (ctx, seqNum, senderId);
    
    }
    return MAMA_STATUS_OK;
}
コード例 #2
0
ファイル: dqstrategy.c プロジェクト: OpenMAMA/OpenMAMA
static void
resetDqState (dqStrategy     strategy,
              mamaDqContext* ctx)
{
    if (ctx->mDQState != DQ_STATE_OK &&
            ctx->mDQState != DQ_STATE_NOT_ESTABLISHED)
    {
        void*             closure   =   NULL;
        mamaMsgCallbacks* cb        =   NULL;

        mamaSubscription_getClosure (self->mSubscription, &closure);

        /* Callback last in the event that client destroys */ 
        cb = mamaSubscription_getUserCallbacks (self->mSubscription);
        if (cb != NULL && cb->onQuality != NULL)
        {
            const char* symbol = NULL;
            short       cause;
            const void* platformInfo = NULL;
            mamaSubscription_getSymbol (self->mSubscription, &symbol);
            mamaSubscription_getAdvisoryCauseAndPlatformInfo (
                                                        self->mSubscription,
                                                        &cause, &platformInfo);
            cb->onQuality (self->mSubscription, MAMA_QUALITY_OK, symbol,
                           cause, platformInfo, closure);
        }
    }
    ctx->mDQState = DQ_STATE_OK;
}
コード例 #3
0
/*
 * Call this routine when subscription error occurs
 */
void onError(mamaSubscription subscription, mama_status status, 
        void * platformError, const char * subject, void * closure)
{
    const char * topicName = NULL;
    if (mamaSubscription_getSymbol(subscription, &topicName) == MAMA_STATUS_OK)
    printf("Error occured with subscription to topic \"%s\", error code: %s\n",
            topicName, mamaStatus_stringForStatus(status));
}
コード例 #4
0
/*
 * Call this routine when subscription is created
 */
void onCreate(mamaSubscription subscription, void * closure)
{
    const char * topicName = NULL;
    if (mamaSubscription_getSymbol(subscription, &topicName) == MAMA_STATUS_OK)
    {
        printf("Created subscription to topic \"%s\"\n", topicName);
    }
}
コード例 #5
0
static void MAMACALLTYPE
mamaDictionaryDefaultCallback_onError ( mamaDictionary dict,
                                        const char* errorStr,
                                        void *closure )
{
    mamaDictionaryImpl* impl = (mamaDictionaryImpl*)dict;
    const char*         userSymbol = NULL;

    mamaSubscription_getSymbol (impl->mSubscription, &userSymbol);
    mama_log (MAMA_LOG_LEVEL_NORMAL, "%s%s %s",
              userSymbolFormatted, errorStr != NULL ? errorStr : "" );
}
コード例 #6
0
/* These are the default callback methods. Users may specify an alternative
 * set of callbacks by calling the mamaDictionary_setXXXCallback()
 * methods.
 */
static void MAMACALLTYPE
mamaDictionaryDefaultCallback_onTimeout( mamaDictionary dict,
                                             void *closure )
{
    mamaDictionaryImpl* impl = (mamaDictionaryImpl*)dict;
    const char*         userSymbol = NULL;

    mamaSubscription_getSymbol (impl->mSubscription, &userSymbol);
    mama_log (MAMA_LOG_LEVEL_NORMAL,
              "%s%s Error: mamaDictionary: timed out waiting for data dictionary.",
              userSymbolFormatted);
}
コード例 #7
0
ファイル: dqstrategy.c プロジェクト: OpenMAMA/OpenMAMA
static mama_status
handleStaleData (dqStrategy     strategy,
                 mamaMsg        msg,
                 mamaDqContext* ctx)
{
    const char*  symbol = NULL;
    mamaSubscription_getSymbol (self->mSubscription, &symbol);

    if (gMamaLogLevel >= MAMA_LOG_LEVEL_FINER)
    {
        symbol = symbol == NULL ? "" : symbol;
        mama_log (MAMA_LOG_LEVEL_FINER, "%s : stale data", symbol);
    }

    msgUtils_setStatus (msg, MAMA_MSG_STATUS_STALE);

    if (ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP &&
        ctx->mDQState != DQ_STATE_POSSIBLY_STALE)
    {
        void*               closure = NULL;
        mamaMsgCallbacks*   cb      = NULL;

        dqStrategy_sendRecapRequest (self, msg, ctx);

        /* Callback last in the event that client destroys */ 
        mamaSubscription_getClosure (self->mSubscription, &closure);
        cb = mamaSubscription_getUserCallbacks (self->mSubscription);

        if (cb != NULL && cb->onQuality != NULL)
        {
            short       cause;
            const void* platformInfo = NULL;
            mamaSubscription_getAdvisoryCauseAndPlatformInfo (
                                                        self->mSubscription,
                                                        &cause, &platformInfo);
            cb->onQuality (self->mSubscription, MAMA_QUALITY_STALE, symbol, 
                           cause, platformInfo, closure);
        }
    }
    else if (ctx->mDQState == DQ_STATE_POSSIBLY_STALE &&
             ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP)
    {
        dqStrategy_sendRecapRequest (self, msg, ctx);
    }

    return MAMA_STATUS_OK;
}
コード例 #8
0
/*
 * Call this routine when a message is received
 */
void onMessage(mamaSubscription subscription, mamaMsg message, void * closure, void * itemClosure)
{
    const char * topicName = NULL;
    if (mamaSubscription_getSymbol(subscription, &topicName) == MAMA_STATUS_OK)
    {
        printf("Message of type %s received on topic \"%s\"\n", mamaMsgType_stringForMsg(message), topicName);
    }
    // extract from the message our own custom field (see topicPublisherMultiple.c)
    const char * const MY_FIELD_NAME = "MdMyTimestamp";
    const int MY_FIELD_ID = 99, BUFFER_SIZE = 32;
    char buffer[BUFFER_SIZE];
    if (mamaMsg_getFieldAsString(message, MY_FIELD_NAME, MY_FIELD_ID, buffer, BUFFER_SIZE) 
            == MAMA_STATUS_OK)
    {
        printf("This message has a field \"%s\" with value: %s", MY_FIELD_NAME, buffer);
    }
}
コード例 #9
0
static void 
determineMaxFid (mamaDictionary dictionary, mamaMsg msg)
{
    const char* userSymbol;

    /* Determine the maximum field id */
    mamaMsg_iterateFields (msg, maxIterator, NULL, self);

    if (dictionary->mSubscription)
    {
        mamaSubscription_getSymbol (dictionary->mSubscription, &userSymbol);
        mama_log (MAMA_LOG_LEVEL_FINE, "%s%s DICT maxFid: %d",
              userSymbolFormatted, self->mMaxFid);
    }
    else
    {
        mama_log (MAMA_LOG_LEVEL_FINE, "DICT maxFid: %d", self->mMaxFid);
    }
}
コード例 #10
0
ファイル: dqstrategy.c プロジェクト: OpenMAMA/OpenMAMA
mama_status
dqContext_applyPreInitialCache (mamaDqContext*      ctx,
                                mamaSubscription    subscription)
{
    /*We looking for the next sequence number in the cache*/
    mama_seqnum_t expectedSeqNum = ctx->mSeqNum + 1; 
    int currentMessageindex = 0;
    const char* symbol = NULL;

    /*Ensure we have a cahce to iterate*/
    if (ctx->mCache == NULL) return MAMA_STATUS_OK;

    mamaSubscription_getSymbol (subscription, &symbol);

    mama_log (MAMA_LOG_LEVEL_NORMAL, 
              "%s: Attempting to apply pre initial cache after initial.",
              symbol);
    
    /*Loop from start to last added message - may have looped over*/
    while (currentMessageindex<ctx->mCurCacheIdx)
    {
        mama_seqnum_t cachedMessageSeqNum = 0;

        /*just in case*/
        if (!ctx->mCache[currentMessageindex]) return MAMA_STATUS_OK;
        
        mamaMsg_getSeqNum (ctx->mCache[currentMessageindex], 
                           &cachedMessageSeqNum);
        mama_log (MAMA_LOG_LEVEL_NORMAL, 
                  "%s: Found cached msg withseqNum: %d Current [%d]", 
                  symbol, cachedMessageSeqNum, ctx->mSeqNum);

        if (expectedSeqNum==cachedMessageSeqNum)
        {
            mama_log (MAMA_LOG_LEVEL_NORMAL, 
                     "%s: Applying cached message after initial", symbol);
            /*Next expected - pass it on!*/
            mamaSubscription_forwardMsg(subscription,
                                        ctx->mCache[currentMessageindex]);

            /*this is now the latest sequence number for the context*/
            ctx->mSeqNum   = cachedMessageSeqNum;
            expectedSeqNum = cachedMessageSeqNum+1;
            
            /*Lets see if there are any more in the cache*/
        }
        else /*Not the expected message - have a couple of options*/
        {
            /*Bomb out - we can't apply this or any subsequent messages
             as they are stored in arrival order*/
            if (cachedMessageSeqNum>expectedSeqNum)
            {
                mama_log (MAMA_LOG_LEVEL_NORMAL, 
                          "%s: Can't apply cached message", symbol);
                break;
            }
        }
        currentMessageindex++;
    }
    
    return MAMA_STATUS_OK;
}
コード例 #11
0
ファイル: dqstrategy.c プロジェクト: OpenMAMA/OpenMAMA
mama_status 
dqStrategy_checkSeqNum (dqStrategy      strategy, 
                        mamaMsg         msg, 
                        int             msgType, 
                        mamaDqContext*  ctx)
{
    mama_seqnum_t    seqNum         = 0;
    mama_seqnum_t    ctxSeqNum      = ctx->mSeqNum;
    mama_u64_t       senderId       = 0;
    mama_u64_t       ctxSenderId    = ctx->mSenderId;
    dqState          ctxDqState     = ctx->mDQState;
    mamaSubscription subscription   = self->mSubscription;
    mama_u16_t       conflateCnt    = 1;
    wombat_subscriptionGapCB onGap  = NULL;
    mamaTransport    transport; 
    mamaStatsCollector transportStatsCollector = NULL;
    wombat_subscriptionQualityCB onQuality = NULL;
    mamaMsgStatus    msgStatus      = MAMA_MSG_STATUS_UNKNOWN;
    mamaTransport    tport        = NULL;

    mamaSubscription_getTransport (self->mSubscription, &tport);
    
    mamaMsg_getSeqNum (msg, &seqNum);

    ctx->mDoNotForward = 0;
    if (mamaMsg_getU64 (msg, MamaFieldSenderId.mName, MamaFieldSenderId.mFid, 
                        &senderId) != MAMA_STATUS_OK)
    {
        /* We just ignore it as we might be running against an older FH */
        senderId = 0;
    }

    /*Special case for dealing with a fault tolerant takeover*/
    if (ctxSenderId != 0 && senderId != 0 && ctxSenderId != senderId)
    {
        /* Only record FT Takeovers per transport and globally */
        if (gGenerateTransportStats)
        {
            mamaSubscription_getTransport (subscription, &transport);
            transportStatsCollector = mamaTransport_getStatsCollector (transport);

            mamaStatsCollector_incrementStat (transportStatsCollector, 
                                              MamaStatFtTakeovers.mFid);
        }
        if (mamaInternal_getGlobalStatsCollector() != NULL)
        {
            mamaStatsCollector_incrementStat (mamaInternal_getGlobalStatsCollector(), 
                                              MamaStatFtTakeovers.mFid);
        }
        if (DQ_FT_WAIT_FOR_RECAP==mamaTransportImpl_getFtStrategyScheme(tport))
        {
            ctx->mDoNotForward = 1;
            handleFTTakeover (strategy, msg, msgType, ctx, seqNum, senderId, 1);
        }
        else
        {
            return handleFTTakeover (strategy, msg, msgType, ctx, seqNum, senderId, 0);
        }
    }

    if (gMamaLogLevel >= MAMA_LOG_LEVEL_FINEST)
    {
        const char*  symbol = NULL;
        mamaSubscription_getSymbol (subscription, &symbol);
        symbol = symbol == NULL ? "" : symbol;
        mama_log (MAMA_LOG_LEVEL_FINEST,
                  "dqStrategy_checkSeqNum(): %s : seq# %ld",
                  symbol, 
                  seqNum);
    }

    switch (msgType)
    {
    case MAMA_MSG_TYPE_QUOTE:
    case MAMA_MSG_TYPE_TRADE:
    case MAMA_MSG_TYPE_UPDATE:
    default:
        if (MAMA_STATUS_OK != mamaMsg_getU16 (msg,
                          MamaFieldConflateCount.mName, 
                          MamaFieldConflateCount.mFid, 
                          &conflateCnt))
        {
            /*Need to set conflateCnt=1 as mamaMsg_getU16 sets conflateCnt=0 
            if not found */
            conflateCnt = 1;
        }
    /* Deliberate fallthrough.  Only the types above can be conflated, so only 
       try to extract the conflate count field for those types. */
    case MAMA_MSG_TYPE_SEC_STATUS:
    case MAMA_MSG_TYPE_BOOK_UPDATE:
        if (((ctxDqState == DQ_STATE_NOT_ESTABLISHED) ||
             (seqNum == 0) ||
             (seqNum == (ctxSeqNum + conflateCnt))) &&
             ((ctxDqState != DQ_STATE_WAITING_FOR_RECAP) ||
             (ctxDqState != DQ_STATE_WAITING_FOR_RECAP_AFTER_FT)))
        {
            /* No gap */
            if (self->mTryToFillGap)
            {
                self->mTryToFillGap = 0;
                dqContext_clearCache (ctx, 0);
            }

            /* It is no longer the case that all subscriptions are possibly
               stale. */
            mamaSubscription_unsetAllPossiblyStale (subscription);
            /* If the sequence numbers for a message are correct then the
               subscription is OK. */
                
            msgStatus = mamaMsgStatus_statusForMsg (msg);
            /* Check the status of the message.  If it is stale,
               do not request a recap and do not set status OK. */
            if (msgStatus == MAMA_MSG_STATUS_OK) 
		    {
                resetDqState (strategy, ctx);

                ctx->mSeqNum = seqNum; 
                return MAMA_STATUS_OK;
            }
        }

        /* For late joins or middlewares that support a publish cache, it is possible that you will get old updates
           in this case take no action */
        if (DQ_SCHEME_INGORE_DUPS == mamaTransportImpl_getDqStrategyScheme(tport))
        {
            if ((seqNum <= ctxSeqNum) && ((ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP) &&
                                          (ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP_AFTER_FT)))
            {
                ctx->mDoNotForward = 1;
                return MAMA_STATUS_OK;
            }
        }

        if ((seqNum == ctxSeqNum) && (ctxDqState != DQ_STATE_WAITING_FOR_RECAP_AFTER_FT))
        {
            /* Duplicate data - set DQQuality to DUPLICATE, invoke quality callback */
            ctx->mDQState = DQ_STATE_DUPLICATE; 
            if ((onQuality = (mamaSubscription_getUserCallbacks (subscription))->onQuality))
            {
                void*               closure = NULL;
                const char* symbol = NULL;
                short       cause;
                const void* platformInfo = NULL;
                mamaSubscription_getClosure (subscription, &closure);
                mamaSubscription_getSymbol (subscription, &symbol);
                mamaSubscription_getAdvisoryCauseAndPlatformInfo (
                                                            subscription,
                                                            &cause, &platformInfo);
                onQuality (subscription, MAMA_QUALITY_DUPLICATE, symbol,
                           cause, platformInfo, closure);
            }
            msgUtils_setStatus (msg, MAMA_MSG_STATUS_DUPLICATE);
            return MAMA_STATUS_OK;
        }
      
        if (ctxDqState == DQ_STATE_WAITING_FOR_RECAP_AFTER_FT)
        {
            ctx->mDoNotForward = 1;
            return MAMA_STATUS_OK;
        }
        else
        {
        /* If we get here, we missed a sequence number. */
         if ((PRE_INITIAL_SCHEME_ON_GAP==mamaTransportImpl_getPreInitialScheme(tport))
                &&(self->mTryToFillGap))
        {
            self->mTryToFillGap = 0;
            if (dqContext_fillGap (ctx, seqNum, subscription))
            {
                /* we filled it */
                dqContext_clearCache (ctx, 0);
                ctx->mSeqNum = seqNum;
                return MAMA_STATUS_OK;
            }
            dqContext_clearCache (ctx, 0);
        }

        if (gMamaLogLevel >= MAMA_LOG_LEVEL_FINE)
        {
            const char*  symbol = NULL;
            mamaSubscription_getSymbol (subscription, &symbol);
            symbol = symbol == NULL ? "" : symbol;
            mama_log (MAMA_LOG_LEVEL_FINE, "%s : SeqNum gap (%ld-%ld)",
                      symbol, ctxSeqNum+1, seqNum-1);
        }

        if ((onGap = 
            (mamaSubscription_getUserCallbacks (subscription)->onGap)))
        {
            void* closure = NULL;
            mamaSubscription_getClosure (subscription, &closure);
            onGap (subscription, closure);
        }

        handleStaleData (self, msg, ctx);
        }
        break;
    case MAMA_MSG_TYPE_INITIAL      :
    case MAMA_MSG_TYPE_BOOK_INITIAL :
        msgStatus = MAMA_MSG_STATUS_UNKNOWN;

        self->mTryToFillGap = 1;

        msgStatus = mamaMsgStatus_statusForMsg (msg);
        /* Check the status of the message.  If it is stale,
           do not request a recap and do not set status OK. */
        if ((msgStatus == MAMA_MSG_STATUS_POSSIBLY_STALE) ||
            (msgStatus == MAMA_MSG_STATUS_STALE))
        {
            ctx->mDQState = DQ_STATE_STALE_NO_RECAP; 
            dqStrategyImpl_resetDqContext (ctx, seqNum, senderId); 
            return MAMA_STATUS_OK; 
        }
    case MAMA_MSG_TYPE_RECAP        :
    case MAMA_MSG_TYPE_BOOK_RECAP   :
    /* For late joins or middlewares that support a publish cache, it is possible that you will get old updates
       in this case take no action */
        if (DQ_SCHEME_INGORE_DUPS == mamaTransportImpl_getDqStrategyScheme(tport))
        {
            if (MAMA_MSG_TYPE_RECAP == msgType)
            {
                /* Feed-handlers maintain sequence number for a Record FT Recap. */
                if ((seqNum <= ctxSeqNum) && ((ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP) &&
                                              (ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP_AFTER_FT)))
                {
                    ctx->mDoNotForward = 1;
                    return MAMA_STATUS_OK;
                }
            }
            else if (MAMA_MSG_TYPE_BOOK_RECAP == msgType)
            {
                if (0 == seqNum && ctxSeqNum > 0)
                {
                    /* Special case of an FT Order Book Recap where a SeqNum of 0 is used. */
                    if (ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP_AFTER_FT)
                    {
                        ctx->mDoNotForward = 1;
                        return MAMA_STATUS_OK;
                    }
                }
                /* Solicited Recap from Feed-Handler or
                 * solicited / unsolicited Recap from mid-tier. */
                else if ((seqNum <= ctxSeqNum) && ((ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP) &&
                                                   (ctx->mDQState != DQ_STATE_WAITING_FOR_RECAP_AFTER_FT)))
                {
                    ctx->mDoNotForward = 1;
                    return MAMA_STATUS_OK;
                }
            }
        }

        if (mamaTransportImpl_preRecapCacheEnabled (tport))
        {
            self->mTryToFillGap = 1;
        }
        mamaSubscription_unsetAllPossiblyStale (subscription);
        resetDqState (strategy, ctx);
        dqStrategyImpl_resetDqContext (ctx, seqNum, senderId);
        ctx->mDoNotForward = 0;
        return MAMA_STATUS_OK;
    case MAMA_MSG_TYPE_DDICT_SNAPSHOT : /*No DQ checking for Datadictionary*/
        return MAMA_STATUS_OK;
    }
    return MAMA_STATUS_OK;
}