void MAMACALLTYPE subscriptionOnMsg (mamaSubscription subscription, mamaMsg msg, void *closure, void *itemClosure) { pubCache* cache = (pubCache*) closure; switch (mamaMsgType_typeForMsg (msg)) { case MAMA_MSG_TYPE_DELETE: case MAMA_MSG_TYPE_EXPIRE: mamaSubscription_destroy (subscription); mamaSubscription_deallocate (subscription); if (cache->pub) mamaDQPublisher_send(cache->pub, msg); cache->sub = NULL; return; default: break; } switch (mamaMsgStatus_statusForMsg (msg)) { case MAMA_MSG_STATUS_BAD_SYMBOL: case MAMA_MSG_STATUS_EXPIRED: case MAMA_MSG_STATUS_TIMEOUT: mamaSubscription_destroy (subscription); mamaSubscription_deallocate (subscription); if (cache->pub) mamaDQPublisher_send(cache->pub, msg); cache->sub = NULL; return; default: break; } mamaMsg_applyMsg(cache->cachedMsg, msg); if (cache->pub) { mamaDQPublisher_setStatus(cache->pub, mamaMsgStatus_statusForMsg (msg)); mamaDQPublisher_send(cache->pub, msg); } fflush(stdout); }
static void processMsg( mamaDictionary dictionary, const mamaMsg msg ) { mamaMsgStatus msgStatus = -1; mamaMsgType msgType = -1; msgStatus = mamaMsgStatus_statusForMsg( msg ); msgType = mamaMsgType_typeForMsg( msg ); if( msgStatus == MAMA_MSG_STATUS_TIMEOUT ) { self->mCallbackSet.onTimeout( dictionary, self->mClosure ); return; } if( msgStatus != MAMA_MSG_STATUS_OK && msgType != MAMA_MSG_TYPE_DDICT_SNAPSHOT && msgType != MAMA_MSG_TYPE_UPDATE ) { char errBuf[1024]; snprintf( errBuf, 1023, "Error: mamaDictionary: unexpected " "MsgType/MsgStatus: %s/%s\n", mamaMsgType_stringForType(msgType), mamaMsgStatus_stringForStatus(msgStatus)); self->mCallbackSet.onError( dictionary, errBuf, self->mClosure ); return; } mamaDictionary_buildDictionaryFromMessage( dictionary, msg ); mamaSubscription_destroy (self->mSubscription); mamaSubscription_deallocate (self->mSubscription); self->mSubscription = NULL; /* do this last in case the dictionary transport is destroyed in the callback */ self->mCallbackSet.onComplete( dictionary, self->mClosure ); }
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; }