-
Notifications
You must be signed in to change notification settings - Fork 160
[ADDED] Atomic batch publish support #977
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1f56dc9
f648008
d313fe5
bad672e
6cfd23f
4665b44
0356ccf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -212,6 +212,10 @@ | |
|
|
||
| memset(ar, 0, sizeof(jsApiResponse)); | ||
|
|
||
| // Server can return zero length response | ||
| if (resp->dataLen == 0) | ||
| return NATS_OK; | ||
|
|
||
| s = nats_JSONParse(&json, natsMsg_GetData(resp), natsMsg_GetDataLength(resp)); | ||
| if (s != NATS_OK) | ||
| return NATS_UPDATE_ERR_STACK(s); | ||
|
|
@@ -547,7 +551,7 @@ | |
| IFOK_JSR(s, natsConnection_RequestMsg(&resp, js->nc, msg, ttl)); | ||
| if (s == NATS_OK) | ||
| s = js_unmarshalResponse(&ar, &json, resp); | ||
| if (s == NATS_OK) | ||
| if (s == NATS_OK && json != NULL) | ||
| { | ||
| if (js_apiResponseIsErr(&ar)) | ||
| { | ||
|
|
@@ -569,6 +573,8 @@ | |
| IFOK(s, nats_JSONGetULong(json, "seq", &(pa->Sequence))); | ||
| IFOK(s, nats_JSONGetBool(json, "duplicate", &(pa->Duplicate))); | ||
| IFOK(s, nats_JSONGetStr(json, "domain", &(pa->Domain))); | ||
| IFOK(s, nats_JSONGetStr(json, "batch", &(pa->Batch))); | ||
| IFOK(s, nats_JSONGetULong(json, "count", &(pa->Count))); | ||
|
|
||
| if (s == NATS_OK) | ||
| *new_puback = pa; | ||
|
|
@@ -579,6 +585,9 @@ | |
| js_freeApiRespContent(&ar); | ||
| nats_JSONDestroy(json); | ||
| } | ||
| else if ((s == NATS_OK) && (new_puback != NULL)) | ||
| *new_puback = NULL; | ||
|
|
||
| natsMsg_Destroy(resp); | ||
| return NATS_UPDATE_ERR_STACK(s); | ||
| } | ||
|
|
@@ -591,6 +600,7 @@ | |
|
|
||
| NATS_FREE(pa->Stream); | ||
| NATS_FREE(pa->Domain); | ||
| NATS_FREE(pa->Batch); | ||
| NATS_FREE(pa); | ||
| } | ||
|
|
||
|
|
@@ -637,10 +647,15 @@ | |
| else if (pa != NULL) | ||
| { | ||
| memset(pa, 0, sizeof(jsPubAck)); | ||
| s = nats_JSONGetStr(json, "stream", &(pa->Stream)); | ||
| IFOK(s, nats_JSONGetULong(json, "seq", &(pa->Sequence))); | ||
| IFOK(s, nats_JSONGetBool(json, "duplicate", &(pa->Duplicate))); | ||
| IFOK(s, nats_JSONGetStr(json, "domain", &(pa->Domain))); | ||
| if (json != NULL) | ||
| { | ||
| s = nats_JSONGetStr(json, "stream", &(pa->Stream)); | ||
| IFOK(s, nats_JSONGetULong(json, "seq", &(pa->Sequence))); | ||
| IFOK(s, nats_JSONGetBool(json, "duplicate", &(pa->Duplicate))); | ||
| IFOK(s, nats_JSONGetStr(json, "domain", &(pa->Domain))); | ||
| IFOK(s, nats_JSONGetStr(json, "batch", &(pa->Batch))); | ||
| IFOK(s, nats_JSONGetULong(json, "count", &(pa->Count))); | ||
| } | ||
| } | ||
|
|
||
| js_freeApiRespContent(&ar); | ||
|
|
@@ -3673,3 +3688,97 @@ | |
| js->onReleaseCbArg = arg; | ||
| js_unlock(js); | ||
| } | ||
|
|
||
| natsStatus | ||
| js_BatchPublishAdd(jsPubAck **new_puback, jsAtomicBatchCtx *ctx, natsMsg *msg, | ||
| jsPubOptions *opts, jsErrCode *errCode) | ||
| { | ||
| natsStatus s = NATS_OK; | ||
| char temp[64] = {'\0'}; | ||
|
|
||
AdamPayzant marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if ((ctx == NULL) || (msg == NULL)) | ||
| return nats_setDefaultError(NATS_INVALID_ARG); | ||
|
|
||
| natsMutex_Lock(ctx->mu); | ||
|
|
||
| s = natsMsgHeader_Set(msg, jsNatsBatchIdHdr, ctx->id); | ||
| if (s == NATS_OK) | ||
| { | ||
| if (snprintf(temp, sizeof(temp), "%" PRIu64, ctx->count+1) < 1) | ||
| s = nats_setDefaultError(NATS_NO_MEMORY); | ||
| else | ||
| s = natsMsgHeader_Set(msg, jsNatsBatchSequenceHdr, temp); | ||
| } | ||
| if (s == NATS_OK) | ||
| { | ||
| ctx->count++; | ||
| } | ||
|
|
||
| IFOK(s, js_PublishMsg(new_puback, ctx->js, msg, opts, errCode)); | ||
|
|
||
| natsMutex_Unlock(ctx->mu); | ||
| return NATS_UPDATE_ERR_STACK(s); | ||
| } | ||
|
|
||
| natsStatus | ||
| js_BatchPublishCommit(jsPubAck **new_puback, jsAtomicBatchCtx *ctx, natsMsg *msg, | ||
| jsPubOptions *opts, jsErrCode *errCode) | ||
| { | ||
| natsStatus s = NATS_OK; | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, not checking explicitly on parameters are ok because you are invoking public APIs that do already check for them (or should).
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went ahead and added them so that we don't manipulate the header unnecessarily |
||
| if ((ctx == NULL) || (msg == NULL)) | ||
| return nats_setDefaultError(NATS_INVALID_ARG); | ||
|
|
||
| s = natsMsgHeader_Set(msg, jsNatsBatchCommit, "1"); | ||
| IFOK(s, js_BatchPublishAdd(new_puback, ctx, msg, opts, errCode)); | ||
|
|
||
| return NATS_UPDATE_ERR_STACK(s); | ||
| } | ||
|
|
||
| natsStatus | ||
| js_BatchPublishStart(jsAtomicBatchCtx **ctx, jsPubAck **new_puback, jsCtx *js, | ||
| natsMsg *msg, jsPubOptions *opts, jsErrCode *errCode) | ||
| { | ||
| jsAtomicBatchCtx *batchCtx = NULL; | ||
| natsStatus s = NATS_OK; | ||
|
|
||
| if ((ctx == NULL) || (js == NULL) || (msg == NULL)) | ||
| return nats_setDefaultError(NATS_INVALID_ARG); | ||
AdamPayzant marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| batchCtx = NATS_CALLOC(1, sizeof(jsAtomicBatchCtx)); | ||
| if (batchCtx == NULL) | ||
| return nats_setDefaultError(NATS_NO_MEMORY); | ||
| batchCtx->id = NATS_MALLOC(NUID_BUFFER_LEN + 1); | ||
| if (batchCtx->id == NULL) | ||
| { | ||
| NATS_FREE(batchCtx); | ||
| return nats_setDefaultError(NATS_NO_MEMORY); | ||
| } | ||
|
|
||
| js_retain(js); | ||
| batchCtx->js = js; | ||
AdamPayzant marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| s = natsMutex_Create(&batchCtx->mu); | ||
| IFOK(s, natsNUID_Next(batchCtx->id, NUID_BUFFER_LEN + 1)); | ||
| if (s != NATS_OK) | ||
| { | ||
| jsAtomicBatchCtx_Destroy(batchCtx); | ||
| return NATS_UPDATE_ERR_STACK(s); | ||
| } | ||
|
|
||
| *ctx = batchCtx; | ||
| s = js_BatchPublishAdd(new_puback, *ctx, msg, opts, errCode); | ||
|
|
||
| return NATS_UPDATE_ERR_STACK(s); | ||
| } | ||
|
|
||
| void | ||
| jsAtomicBatchCtx_Destroy(jsAtomicBatchCtx *ctx) | ||
| { | ||
| if (ctx == NULL) | ||
| return; | ||
|
|
||
AdamPayzant marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| js_release(ctx->js); | ||
| natsMutex_Destroy(ctx->mu); | ||
| NATS_FREE(ctx->id); | ||
| NATS_FREE(ctx); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -280,6 +280,11 @@ typedef struct natsMetadata | |
| */ | ||
| typedef struct __jsCtx jsCtx; | ||
|
|
||
| /** | ||
| * The JetStream atomic batch context. Use for JetStream atomic batch publish. | ||
| */ | ||
| typedef struct __jsAtomicBatchCtx jsAtomicBatchCtx; | ||
|
|
||
| /** | ||
| * JetStream publish options. | ||
| * | ||
|
|
@@ -644,6 +649,8 @@ typedef struct jsStreamConfig { | |
| /// v2.12.0 or later. | ||
| jsPersistModeType PersistMode; | ||
|
|
||
| /// @brief Enables sending atomic batch publishing into the stream | ||
| bool AllowAtomic; | ||
| } jsStreamConfig; | ||
|
|
||
| /** | ||
|
|
@@ -1227,6 +1234,8 @@ typedef struct jsPubAck | |
| uint64_t Sequence; | ||
| char *Domain; | ||
| bool Duplicate; | ||
| char *Batch; | ||
| uint64_t Count; | ||
|
|
||
| } jsPubAck; | ||
|
|
||
|
|
@@ -7543,6 +7552,70 @@ js_PublishAsyncComplete(jsCtx *js, jsPubOptions *opts); | |
| NATS_EXTERN natsStatus | ||
| js_PublishAsyncGetPendingList(natsMsgList *pending, jsCtx *js); | ||
|
|
||
| /** \brief Starts an atomic batch publish. | ||
| * | ||
| * This call initializes an atomic batch publish and sends the first message. | ||
| * | ||
| * \note The returned context must be destroyed with #jsAtomicBatchCtx_Destroy | ||
| * after the publish is committed or aborted. | ||
| * \note The returned #jsPubAck object needs to be destroyed with #jsPubAck_Destroy | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: two |
||
| * when no longer needed. | ||
| * | ||
| * @param ctx Where to store the atomic batch context for subsequent publishes. | ||
| * @param new_puback Where to store the pub ack for the first message, or `NULL` if not needed. | ||
| * @param js the pointer to the #jsCtx object. | ||
| * @param msg the message to publish as part of this batch. | ||
| * @param opts the publish options, possibly `NULL`. | ||
| * @param errCode the location where to store the JetStream specific error code, possibly `NULL`. | ||
| */ | ||
| NATS_EXTERN natsStatus | ||
| js_BatchPublishStart(jsAtomicBatchCtx **ctx, jsPubAck **new_puback, jsCtx *js, | ||
| natsMsg *msg, jsPubOptions *opts, jsErrCode *errCode); | ||
|
|
||
| /** \brief Adds a message to the batch publish. | ||
| * | ||
| * This call adds a message to the batch publish initialized by #js_BatchPublishStart. | ||
| * | ||
| * \note The returned #jsPubAck object needs to be destroyed with #jsPubAck_Destroy. | ||
| * | ||
| * @param new_puback Where to store the pub ack for this message, or `NULL` if not needed. | ||
| * @param ctx the atomic batch context returned by #js_BatchPublishStart. | ||
| * @param msg the message to publish as part of this batch. | ||
| * @param opts the publish options, possibly `NULL`. | ||
| * @param errCode the location where to store the JetStream specific error code, possibly `NULL`. | ||
| */ | ||
| NATS_EXTERN natsStatus | ||
| js_BatchPublishAdd(jsPubAck **new_puback, jsAtomicBatchCtx *ctx, natsMsg *msg, | ||
| jsPubOptions *opts, jsErrCode *errCode); | ||
|
|
||
| /** \brief Commits the batch publish. | ||
| * | ||
| * This call commits the batch publish initialized by #js_BatchPublishStart | ||
| * and added to by #js_BatchPublishAdd. | ||
| * | ||
| * \note The returned #jsPubAck object needs to be destroyed with #jsPubAck_Destroy. | ||
| * \note After this call, the context should be destroyed with #jsAtomicBatchCtx_Destroy. | ||
| * | ||
| * @param new_puback Where to store the pub ack for the commit, or `NULL` if not needed. | ||
| * @param ctx the atomic batch context returned by #js_BatchPublishStart. | ||
| * @param msg the message to publish as part of this batch. | ||
| * @param opts the publish options, possibly `NULL`. | ||
| * @param errCode the location where to store the JetStream specific error code, possibly `NULL`. | ||
| */ | ||
| NATS_EXTERN natsStatus | ||
| js_BatchPublishCommit(jsPubAck **new_puback, jsAtomicBatchCtx *ctx, natsMsg *msg, | ||
| jsPubOptions *opts, jsErrCode *errCode); | ||
|
|
||
|
|
||
| /** \brief Destroys the atomic batch context object. | ||
| * | ||
| * Releases memory allocated for this atomic batch context object. | ||
| * | ||
| * @param ctx the pointer to the #jsAtomicBatchCtx object. | ||
| */ | ||
| NATS_EXTERN void | ||
| jsAtomicBatchCtx_Destroy(jsAtomicBatchCtx *ctx); | ||
|
|
||
| /** @} */ // end of jsPubGroup | ||
|
|
||
| /** \defgroup jsSubGroup Subscribing | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -306,6 +306,13 @@ typedef enum { | |
| JSMessageTTLInvalidErr = 10165, ///< Invalid per-message TTL | ||
| JSMessageTTLDisabledErr = 10166, ///< Per-message TTL is disabled | ||
| JSStreamTooManyRequestsErr = 10167, ///< Too many requests | ||
| JSBatchPublishNotEnabledErr = 10174, ///< Batch publish not enabled on stream | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not in this PR, but we may have to add missing ones since I am not sure this was updated with server additions. |
||
| JSBatchPublishIncompleteErr = 10176, ///< Batch publish is incomplete and was abandoned | ||
| JSBatchPublishInvalidIDErr = 10179, ///< Batch publish ID is invalid (exceeds 64 characters) | ||
| JSBatchPublishSequenceMissingErr = 10175, ///< Batch publish sequence is missing | ||
| JSBatchPublishSequenceExceedsLimitErr = 10199, ///< Batch publish sequence exceeds server limit (default 1000) | ||
| JSBatchPublishUnsupportedHeaderErr = 10177, ///< Batch publish unsupported header used (Nats-Expected-Last-Msg-Id) | ||
| JSBatchPublishDuplicateMessageIDErr = 10201, ///< Batch publish contains duplicate message id (Nats-Msg-Id) | ||
|
|
||
| } jsErrCode; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.