/* * (c) Copyright, Real-Time Innovations, 2002-2016. * All rights reserved. * No duplications, whole or partial, manual or electronic, may be made * without express written permission. Any such copies, or * revisions thereof, must display this notice unaltered. * This code contains trade secrets of Real-Time Innovations, Inc. */ #ifndef reda_sequenceNumber_h #define reda_sequenceNumber_h #include "osapi/osapi_type.h" #include "osapi/osapi_ntptime.h" #include "reda/reda_dll.h" #include "reda/reda_fastBuffer.h" #include "reda/reda_inlineList.h" #include "reda/reda_skiplist.h" #include "reda/reda_buffer.h" #ifdef __cplusplus extern "C" { #endif struct REDABuffer; /* forward declare to appease compiler */ /* Doxygen file & module documentation ==================================*/ /*e \file \brief Defines the REDASequenceNumber */ /* ----------------------------------------------------------------- */ /*e \defgroup REDASequenceNumberClass REDASequenceNumber \ingroup REDAModule \brief The functions in this module support the manipulation of 64-bit sequence numbers, including comparison and arithmetic operations. The implementation des not assume 64-bit processor architecture rather relies on 32-bit logic on the "low" and "high" part of the sequence number. */ /*e \ingroup REDASequenceNumberClass \brief The structure used to encode a 64-bit signed sequence number */ /*e 64-bit signed number. */ typedef struct REDASequenceNumber { /*e The most significant part of the sequence number */ RTI_INT32 high; /*e The least significant part of the sequence number */ RTI_UINT32 low; } REDASequenceNumber; /*e \ingroup REDASequenceNumberClass \brief Highest, most positive value for the high part of the seq num */ #define REDA_SEQUENCE_NUMBER_HIGH_MAX ((RTI_INT32) 0x7fffffff) /*e \ingroup REDASequenceNumberClass \brief Highest, most positive value for the low part of the seq num */ #define REDA_SEQUENCE_NUMBER_LOW_MAX ((RTI_UINT32) 0xffffffff) /*e \ingroup REDASequenceNumberClass \brief Highest, most positive value for the 64-bit sequence number Intended to be used as: \code struct REDASequenceNumber seqNum = REDA_SEQUENCE_NUMBER_MAX; \endcode */ #define REDA_SEQUENCE_NUMBER_MAX \ { \ REDA_SEQUENCE_NUMBER_HIGH_MAX, REDA_SEQUENCE_NUMBER_LOW_MAX \ } /*e \ingroup REDASequenceNumberClass \brief Zero value for the 64-bit sequence number Intended to be used as: \code struct REDASequenceNumber seqNum = REDA_SEQUENCE_NUMBER_ZERO; \endcode */ #define REDA_SEQUENCE_NUMBER_ZERO \ { \ 0, 0 \ } /*e \ingroup REDASequenceNumberClass \brief Value for the high part of unknown seq num */ #define REDA_SEQUENCE_NUMBER_HIGH_UNKNOWN ((RTI_INT32) 0xffffffff) /*e \ingroup REDASequenceNumberClass \brief Value for the high part of auto seq num */ #define REDA_SEQUENCE_NUMBER_HIGH_AUTO ((RTI_INT32) 0xffffffff) /*e \ingroup REDASequenceNumberClass \brief Value for the low part of unknown seq num */ #define REDA_SEQUENCE_NUMBER_LOW_UNKNOWN ((RTI_UINT32) 0xffffffff) /*e \ingroup REDASequenceNumberClass \brief Value for the low part of unknown seq num */ #define REDA_SEQUENCE_NUMBER_LOW_AUTO ((RTI_UINT32) 0xffffffff) /*e \ingroup REDASequenceNumberClass Unknown value (-1) for the 64-bit sequence number Intended to be used as: \code struct REDASequenceNumber seqNum = REDA_SEQUENCE_NUMBER_UNKNOWN; \endcode */ #define REDA_SEQUENCE_NUMBER_UNKNOWN \ { \ REDA_SEQUENCE_NUMBER_HIGH_UNKNOWN, REDA_SEQUENCE_NUMBER_LOW_UNKNOWN \ } /*e \ingroup REDASequenceNumberClass \brief AUTO value \code \endcode */ #define REDA_SEQUENCE_NUMBER_AUTO \ { \ REDA_SEQUENCE_NUMBER_HIGH_AUTO, REDA_SEQUENCE_NUMBER_LOW_AUTO \ } /*e \ingroup REDASequenceNumberClass @see REDAOrderedDataTypePrintFunction */ extern REDADllExport void REDASequenceNumber_print( const void *data, const char *desc, int indent); /*e \ingroup REDASequenceNumberClass * \brief Reset a sequence number to zero. * It is safer and more portable than setting the individual fields. * * @post sequenceNumber set to REDA_SEQUENCE_NUMBER_ZERO. * * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_setZero(struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Check if a sequence number is zero. * * @post sequenceNumber remains unchanged. * * @return * * * @note This function is implemented as a macro for performance reasons. */ RTIBool REDASequenceNumber_isZero(const struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Reset a sequence number to unknown. * It is safer and more portable than setting the individial fields. * * @post sequenceNumber set to REDA_SEQUENCE_NUMBER_UNKNOWN. * * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_setUnknown(struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Check if a sequence number is unknown. * * @post sequenceNumber remains unchanged. * * @return * * * @note This function is implemented as a macro for performance reasons. */ RTIBool REDASequenceNumber_isUnknown(const struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Check if a sequence number is AUTO * * @note This function is implemented as a macro for performance reasons. */ RTIBool REDASequenceNumber_isAuto(const struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Check if a sequence number is the maximum sequence number. * * @post sequenceNumber remains unchanged. * * @return * * * @note This function is implemented as a macro for performance reasons. */ RTIBool REDASequenceNumber_isMaximum(const struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Set a sequence number to the maximum value. * It is safer and more portable than setting the individial fields. * * @post sequenceNumber set to REDA_SEQUENCE_NUMBER_MAX. * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_setMaximum(struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Compare two sequence numbers. * * @pre Both sequence numbers are valid. * @post Both sequence numbers remain unchanged. * * @param sn \b In. Second sequence number to compare. * * @return * * * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ int REDASequenceNumber_compare( const struct REDASequenceNumber *me, const struct REDASequenceNumber *sn); /*e \ingroup REDASequenceNumberClass * \brief Add two sequence numbers. * * @post answer contains sn1 + sn2. sn1 and sn2 remain the same. * * @param answer \b Out. Sequence number to hold the sum. * @param sn1 \b In. First sequence number to add. * @param sn2 \b In. Second sequence number to add. * * @mtsafety ontThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_add( struct REDASequenceNumber *answer, const struct REDASequenceNumber *sn1, const struct REDASequenceNumber *sn2); /*e \ingroup REDASequenceNumberClass * \brief Subtract two sequence numbers. * * @post answer contains sn1 - sn2. sn1 and sn2 remain the same. * * @param answer \b Out. Sequence number to hold the difference. * @param sn1 \b In. number to subtract from. * @param sn2 \b In. number to subtract. * * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_subtract( struct REDASequenceNumber *answer, const struct REDASequenceNumber *sn1, const struct REDASequenceNumber *sn2); /*e \ingroup REDASequenceNumberClass * \brief Increment a sequence number by one. * * @post this incremented by 1. * * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_plusplus(struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Decrement a sequence number by one. * * @post sequenceNumber decremented by 1. * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_minusminus(struct REDASequenceNumber *me); /*e \ingroup REDASequenceNumberClass * \brief Increment a sequence number by another sequence number. * * @post answer is incremented by sn. * * @param sn \b In. Sequence number to increment by. * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_increment( struct REDASequenceNumber *me, const struct REDASequenceNumber *sn); /*e \ingroup REDASequenceNumberClass * \brief Decrement a sequence number by another sequence number. * * @post answer is decremented by sn. * * @param sn \b In. Sequence number to decrement by. * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_decrement( struct REDASequenceNumber *me, const struct REDASequenceNumber *sn); /*e \ingroup REDASequenceNumberClass * \brief Get the max of two sequence numbers. * * @post answer is set to the max of the two sequence numbers. * * @param answer \b InOut. Max sequence number of the two. * @param sn1 \b In. First sequence number. * @param sn2 \b In. Second sequence number. * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_max( struct REDASequenceNumber *answer, const struct REDASequenceNumber *sn1, const struct REDASequenceNumber *sn2); /*e \ingroup REDASequenceNumberClass * \brief Get the min of two sequence numbers. * * @post answer is set to the min of the two sequence numbers. * * @param answer \b InOut. Min sequence number of the two. * @param sn1 \b In. First sequence number. * @param sn2 \b In. Second sequence number. * @mtsafety oneThreadAtATime * * @note This function is implemented as a macro for performance reasons. */ void REDASequenceNumber_min( struct REDASequenceNumber *answer, const struct REDASequenceNumber *sn1, const struct REDASequenceNumber *sn2); double REDASequenceNumber_toDouble(struct REDASequenceNumber *sn); /**************************************************************/ /*e \ingroup REDASequenceNumberClass \brief Structure representing an interval between sequence numbers, and the optional associated user data. */ struct REDASequenceNumberInterval { struct REDAInlineListNode _node; const struct REDASkiplistNode *_skiplistNode; struct REDASequenceNumber firstSn; struct REDASequenceNumber lastSn; struct REDABuffer userData; RTIBool validUserData; struct RTINtpTime userDataExpirationTime; }; #define REDASequenceNumberInterval_INITIALIZER \ { \ REDAInlineListNode_INITIALIZER, /* _node */ \ NULL, /* _skiplistNode */ \ REDA_SEQUENCE_NUMBER_ZERO, /* firstSn */ \ REDA_SEQUENCE_NUMBER_ZERO, /* lastSn */ \ REDA_BUFFER_INVALID, /* userData */ \ RTI_FALSE, /* validUserData */ \ RTI_NTP_TIME_ZERO /* userDataExpirationTime */ \ } /*e \ingroup REDASequenceNumberClass @brief The assert mode of a sequence number interval list indicates how the assert sequence number operation works. */ typedef int REDASequenceNumberIntervalListAssertMode; /*e \ingroup REDASequenceNumberClass @brief Indicates that the assert operation must include the exact specified sequence number every time it is called */ #define REDA_SEQUENCE_NUMBER_INTERVAL_LIST_EXPLICIT_ASSERT (0) /*e \ingroup REDASequenceNumberClass @brief Indicates that the assert operation must include the sequence number specified and all the sequence numbers below it down to 1. */ #define REDA_SEQUENCE_NUMBER_INTERVAL_LIST_ORDERED_ASSERT (1) #define REDA_SEQUENCE_NUMBER_INTERVAL_LIST_MAGIC_NUMBER 0x7344L /**e \ingroup REDASequenceNumberClass * @brief Indicates how to handle the user data history * when a sequence number is asserted with user data. */ typedef int REDASequenceNumberIntervalListPayloadHistory; /**e \ingroup REDASequenceNumberClass * @brief Indicates that all user data provided when asserting * sequence numbers must be kept until it expires. */ #define REDA_SEQUENCE_NUMBER_INTERVAL_LIST_PAYLOAD_HISTORY_KEEP_ALL (0) /**e \ingroup REDASequenceNumberClass * @brief Indicates that only the most-recent user data provided * when asserting the last sequence number must be kept until it * expires. */ #define REDA_SEQUENCE_NUMBER_INTERVAL_LIST_PAYLOAD_HISTORY_KEEP_LAST (1) /*e \ingroup REDASequenceNumberClass \brief Structure representing a list of sequence number intervals. */ struct REDASequenceNumberIntervalList { struct REDASkiplist list; int _list_init; struct REDAInlineList _expirationList; struct REDAFastBufferPool *intervalPool; struct REDAFastBufferPool *userDataPool; const struct REDASkiplistNode *iterNode; REDASequenceNumberIntervalListAssertMode _assertMode; /** * Indicates how to handle the user data history * when a sequence number is asserted with user data. */ REDASequenceNumberIntervalListPayloadHistory _payloadHistory; /** * Keep track of the most-recent interval with a payload that was * introduced. */ struct REDASequenceNumberInterval *_mostRecentIntervalWithPayload; }; /*e \ingroup REDASequenceNumberClass \brief Creates a list of sequence number intervals. */ extern REDADllExport struct REDASequenceNumberIntervalList * REDASequenceNumberIntervalList_new( const struct REDASkiplistDescription *listDes, struct REDAFastBufferPool *intervalPool, struct REDAFastBufferPool *userDataPool, REDASequenceNumberIntervalListAssertMode assertMode, REDASequenceNumberIntervalListPayloadHistory payloadHistory); /*e \ingroup REDASequenceNumberClass \brief Deletes a list of sequence number intervals. */ extern REDADllExport void REDASequenceNumberIntervalList_delete( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Initializes a list of sequence number intervals. */ extern REDADllExport RTIBool REDASequenceNumberIntervalList_initialize( struct REDASequenceNumberIntervalList *self, const struct REDASkiplistDescription *listDes, struct REDAFastBufferPool *intervalPool, struct REDAFastBufferPool *userDataPool, REDASequenceNumberIntervalListAssertMode assertMode, REDASequenceNumberIntervalListPayloadHistory payloadHistory); /*e \ingroup REDASequenceNumberClass \brief Finalizes a list of sequence number intervals. */ extern REDADllExport void REDASequenceNumberIntervalList_finalize( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Searches for a sequence number */ extern REDADllExport RTIBool REDASequenceNumberIntervalList_containsSequenceNumber( struct REDASequenceNumberIntervalList *self, const struct REDASequenceNumber *sn); /*e \ingroup REDASequenceNumberClass \brief Asserts a sequence number in a list of sequence number intervals. @param sn The sequence number @param userData An optional payload to be associated to this sequence number If the sn already exists in the list with a different userData the older userData prevails. @post If the list is configured with REDA_SEQUENCE_NUMBER_INTERVAL_LIST_EXPLICIT_ASSERT sn is contained in one interval. If the list is configured with REDA_SEQUENCE_NUMBER_INTERVAL_LIST_ORDERED_ASSERT the interval [1, sn] is present (or contained in a larger one) in the list \see REDASequenceNumberIntervalListAssertMode */ extern REDADllExport struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_assertExplicitSequenceNumberWithUserData( struct REDASequenceNumberIntervalList *self, RTIBool *alreadyExists, const struct REDASequenceNumber *sn, const struct REDABuffer *userData, const struct RTINtpTime *userDataExpirationTime); extern REDADllExport struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_assertOrderedSequenceNumberWithUserData( struct REDASequenceNumberIntervalList *self, RTIBool *alreadyExists, const struct REDASequenceNumber *sn, const struct REDABuffer *userData, const struct RTINtpTime *userDataExpirationTime); #define REDASequenceNumberIntervalList_assertSequenceNumber(self, sn) \ REDASequenceNumberIntervalList_assertSequenceNumberWithUserData( \ self, \ NULL, \ sn, \ NULL, \ NULL) #define REDASequenceNumberIntervalList_assertSequenceNumberWithUserDataMacro( \ self, \ alreadyExists, \ sn, \ data, \ expiration) \ ((self)->_assertMode == REDA_SEQUENCE_NUMBER_INTERVAL_LIST_EXPLICIT_ASSERT \ ? REDASequenceNumberIntervalList_assertExplicitSequenceNumberWithUserData( \ self, \ alreadyExists, \ sn, \ data, \ expiration) \ : REDASequenceNumberIntervalList_assertOrderedSequenceNumberWithUserData( \ self, \ alreadyExists, \ sn, \ data, \ expiration)) #ifndef RTI_PRECONDITION_TEST #define REDASequenceNumberIntervalList_assertSequenceNumberWithUserData \ REDASequenceNumberIntervalList_assertSequenceNumberWithUserDataMacro #else extern REDADllExport struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_assertSequenceNumberWithUserData( struct REDASequenceNumberIntervalList *self, RTIBool *alreadyExists, const struct REDASequenceNumber *sn, const struct REDABuffer *userData, const struct RTINtpTime *userDataExpirationTime); #endif /*e \ingroup REDASequenceNumberClass * \brief Asserts an interval in a list of sequence number intervals. * If an interval with the same firstSn and lastSn already exists, then the * userData, userDataExpirationTime, and validUserData flag are not updated, * and modified is set to false. modified is set to true if self is modified. * * @param modified whether or not self is modified * @param firstSn the first sequence number of the interval * @param lastSn the last sequence number of the interval * @param userData the payload for the interval * @param userDataExpirationTime the expiration time for the interval * @return RTI_TRUE if the interval is successfully asserted */ extern REDADllExport RTIBool REDASequenceNumberIntervalList_assertInterval( struct REDASequenceNumberIntervalList *self, RTIBool *modified, const struct REDASequenceNumber *firstSn, const struct REDASequenceNumber *lastSn, const struct REDABuffer *userData, const struct RTINtpTime *userDataExpirationTime); /*e \ingroup REDASequenceNumberClass * \brief Updates the userData and userDataExpirationTime of an existing * interval by deleting and reasserting the interval. * * @param listInterval the interval to update. This will be deleted. * @param newUserData the new payload for the interval * @param newUserDataExpirationTime the new expiration time for the interval * @return NULL if the interval doesn't exist, a pointer to the new interval if * the old interval exists and is successfully deleted. */ /*e \ingroup REDASequenceNumberClass * \brief */ extern REDADllExport struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_updateIntervalUserData( struct REDASequenceNumberIntervalList *self, struct REDASequenceNumberInterval *listInterval, const struct REDABuffer *newUserData, const struct RTINtpTime *newUserDataExpirationTime); extern REDADllExport RTIBool REDASequenceNumberIntervalList_mergeWithUserData( struct REDASequenceNumberIntervalList *self, RTIBool *modified, const struct REDASequenceNumberIntervalList *srcLst, const struct REDABuffer *userData, const struct RTINtpTime *userDataExpirationTime); extern REDADllExport RTIBool REDASequenceNumberIntervalList_merge( struct REDASequenceNumberIntervalList *self, RTIBool *modified, const struct REDASequenceNumberIntervalList *srcLst); /*e \ingroup REDASequenceNumberClass \brief Gets the number of intervals in a sequence number interval list. */ extern REDADllExport int REDASequenceNumberIntervalList_getIntervalCount( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Gets the number of samples in the interval list. */ extern REDADllExport RTI_UINT64 REDASequenceNumberIntervalList_getSampleCount( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Gets the number of samples in an interval */ extern REDADllExport RTI_UINT64 REDASequenceNumberInterval_getSampleCount( struct REDASequenceNumberInterval *self); /*e \ingroup REDASequenceNumberClass \brief Gets the first interval in a sequence number interval list. */ extern REDADllExport const struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_getFirstInterval( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Gets the last interval. */ extern REDADllExport const struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_getLastInterval( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Gets the next interval in a sequence number interval list. */ extern REDADllExport const struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_getNextInterval( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Invalidates the payloads of intervals with expiration time before "now" Invalidate means: mark as invalid user data, free that memory and possibly merge with adjacent intervals if those have expired too */ extern REDADllExport void REDASequenceNumberIntervalList_invalidateExpiredUserData( struct REDASequenceNumberIntervalList *self, const struct RTINtpTime *now); /*e \ingroup REDASequenceNumberClass * \brief Gets the first interval that has expiration time * before "now" * * Returns NULL if no intervals have expired. */ extern REDADllExport struct REDASequenceNumberInterval * REDASequenceNumberIntervalList_getFirstExpiredInterval( struct REDASequenceNumberIntervalList *self, const struct RTINtpTime *now); extern REDADllExport void REDASequenceNumberIntervalList_clear( struct REDASequenceNumberIntervalList *self); /*e \ingroup REDASequenceNumberClass \brief Finds x such us [1, x][y,z] (with x+1