You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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.
DataStoreServiceClient::FetchRecordclones the key on every fetch whoseTxKeyis not an owner:FetchSnapshotdoes the same at:4650.The clone is defensive. The read it starts is asynchronous and
tx_key_is kept inCcShard::fetch_record_reqs_until the callback, while several callers hand in a borrowingTxKeythat points at a stack local. The clearest case isObjectCcMap::Execute(ReplayLogCc &), whereKeyT keyis declared outside the loop and re-deserialized on every iteration: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
CcPageoutlives the fetch on its own, becauseCcShard::FetchRecordpins the entry for the duration and the pin is only released inObjectCcMap::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:
CcMap::KeyOfEntry, added in feat: partition-level reopen for buffered commands on standby #484.Either way the contract should be written down at
DataStoreHandler::FetchRecord, since today it is only implied by this one defensive copy.