Skip to content

PUBLISH leaks a TransactionExecution on every call (txm never committed/aborted) #505

@liunyl

Description

@liunyl

RedisServiceImpl::Publish creates a transaction via NewTxm() but the engine handler for PublishTxRequest only finishes the request result — it never transitions the txm to Finished. Since an external txm is returned to the free list only when Forward() reports Finished, the publish txm is leaked on every PUBLISH.

Evidence

src/redis_service.cpp:6451-6461:

int RedisServiceImpl::Publish(std::string_view chan, std::string_view msg) {
    TransactionExecution *txm = NewTxm(IsolationLevel::ReadCommitted, CcProtocol::OccRead);
    PublishTxRequest req(chan, msg, txm);
    SendTxRequestAndWaitResult(txm, &req, nullptr);   // success path never commits/aborts
    return eloqkv_pub_sub_mgr.Publish(chan, msg);     // txm pointer dropped here
}

Engine handler data_substrate/tx_service/src/tx_execution.cpp:1074-1084 (ProcessTxRequest(PublishTxRequest)):

for (uint32_t ng_id : *all_node_groups) cc_handler_->PublishMessage(...);
req.tx_result_.Finish(Void{});     // finishes the RESULT, not the txm; no commit, no status=Finished

Forward() (tx_execution.cpp:509-516) returns Idle (not Finished) since tx_status_ was never set to Finished; external txms are reclaimed only via RemoveExternActiveTxm, called only on Finished (tx_service.h:702, 797). SendTxRequestAndWaitResult commits/aborts only on the TX_INIT_FAIL error path. Every other NewTxm call site in the codebase pairs with CommitTx/AbortTx; PUBLISH is the only one that does not.

Impact

One TransactionExecution (a large object) leaks per PUBLISH → unbounded memory growth on pub/sub workloads (keyspace notifications make this hot). Also ext_active_tx_cnt_ never returns to zero, so AllTxFinished() never holds — can block graceful shutdown.

Fix: commit/abort the txm after the publish (or give PublishTxRequest a handler that drives the txm to Finished).


Found during a code audit (docs PR #492). Verified full path against source.

🤖 Found with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions