Skip to content

Avoid the defensive key clone on the FetchRecord path #532

Description

@thweetkomputer

DataStoreServiceClient::FetchRecord clones the key on every fetch whose TxKey is not an owner:

// store_handler/data_store_service_client.cpp:4536
if (!fetch_cc->tx_key_.IsOwner())
{
    fetch_cc->tx_key_ = fetch_cc->tx_key_.Clone();
}

FetchSnapshot does the same at :4650.

The clone is defensive. The read it starts is asynchronous and tx_key_ is kept in CcShard::fetch_record_reqs_ until the callback, while several callers hand in a borrowing TxKey that points at a stack local. The clearest case is ObjectCcMap::Execute(ReplayLogCc &), where KeyT key is declared outside the loop and re-deserialized on every iteration:

// tx_service/include/cc/object_cc_map.h:2264
KeyT key;
while (offset < log_blob.size())
{
    key.Deserialize(log_blob.data(), offset, KeySchema());
    ...
    shard_->FetchRecord(..., TxKey(&key), ...);
}

Without the clone that borrow dangles as soon as the loop advances.

So the clone is needed for those callers, not for all of them. A key that lives in the entry's CcPage outlives the fetch on its own, because CcShard::FetchRecord pins the entry for the duration and the pin is only released in ObjectCcMap::BackFill. For such callers the clone is one heap allocation and one free per fetch, paid on the fetch path, which is exactly where allocation pressure hurts under high concurrency.

Worth exploring:

  • Give the callers that already hold a stable key a way to say so, so the client can skip the clone. A page-derived key is now available in a type-erased form through CcMap::KeyOfEntry, added in feat: partition-level reopen for buffered commands on standby #484.
  • Or push the ownership decision to the call sites: have the stack-local callers clone (or keep the key alive themselves) and let the client assume the key outlives the request.

Either way the contract should be written down at DataStoreHandler::FetchRecord, since today it is only implied by this one defensive copy.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions