Skip to content

Copy pulled data on the data processor of the location pulled from - #2933

Draft
francoisferrand wants to merge 4 commits into
development/9.6from
improvement/BB-913/pull-from-source-location-v3
Draft

francoisferrand wants to merge 4 commits into
development/9.6from
improvement/BB-913/pull-from-source-location-v3

Conversation

@francoisferrand

Copy link
Copy Markdown
Contributor

Alternative to #2876 and #2931, keeping the change as local as possible.

Data processors only take the copies whose toLocation is their own site, and only the processor of the remote location (e.g. dr-source) can read the data to pull. So rather than changing how messages are routed, the populator now sends pull replications "reversed": toLocation is the location pulled from, and the actual target goes in fromLocation. Routing, credentials and reads then work as for any other copy.

In CopyLocationTask, two things differ for a pull:

  • the data is written to the location the object data points to (targetLocation of the location part), not to the processor's own site; this is detected from the object metadata (data on a CRR location), like the read side already does
  • when publishing the result to the transition processor, toLocation and fromLocation are swapped back, so LifecycleUpdateTransitionTask is unchanged

Issue: BB-913

@bert-e

bert-e commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Hello francoisferrand,

My role is to assist you with the merge of this
pull request. Please type @bert-e help to get information
on this process, or consult the user documentation.

Available options
name description privileged authored
/after_pull_request Wait for the given pull request id to be merged before continuing with the current one.
/bypass_author_approval Bypass the pull request author's approval ⭐
/bypass_build_status Bypass the build and test status ⭐
/bypass_commit_size Bypass the check on the size of the changeset TBA ⭐
/bypass_incompatible_branch Bypass the check on the source branch prefix ⭐
/bypass_jira_check Bypass the Jira issue check ⭐
/bypass_peer_approval Bypass the pull request peers' approval ⭐
/bypass_leader_approval Bypass the pull request leaders' approval ⭐
/bypass_source_branch_lineage Bypass the cross-branch contamination check ⭐
/approve Instruct Bert-E that the author has approved the pull request. ✍️
/create_pull_requests Allow the creation of integration pull requests.
/create_integration_branches Allow the creation of integration branches.
/no_octopus Prevent Wall-E from doing any octopus merge and use multiple consecutive merge instead
/unanimity Change review acceptance criteria from one reviewer at least to all reviewers
/wait Instruct Bert-E not to run until further notice.
Available commands
name description privileged
/help Print Bert-E's manual in the pull request.
/status Print Bert-E's current status in the pull request.
/clear Remove all comments from Bert-E from the history TBA
/retry Re-start a fresh build TBA
/build Re-start a fresh build TBA
/force_reset Delete integration branches & pull requests, and restart merge process from the beginning.
/reset Try to remove integration branches unless there are commits on them which do not appear on the source branch.

Status report is not available.

@bert-e

bert-e commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

Request integration branches

Waiting for integration branch creation to be requested by the user.

To request integration branches, please comment on this pull request with the following command:

/create_integration_branches

Alternatively, the /approve and /create_pull_requests commands will automatically
create the integration branches.

if (!locations[objMD.getDataStoreName()]?.isCRR) {
return { StorageType: this.destType, StorageClass: this.site };
}
const { targetLocation } = objMD.getLocation()[0];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This re-derives the target from location[0].targetLocation, which differs from what the populator resolved in _getPullReplicationTarget:

  • empty object without location (explicitly allowed by the populator): objMD.getLocation() is null/[], so destructuring throws a TypeError (first hit in _checkObjectState, inside the waterfall).
  • invalid targetLocation (populator falls back to defaultLocalLocation): data is written to a non-existent location, and StorageType is undefined.

Pass actionEntry and use the target the populator already carries in metrics.fromLocation when metrics.origin === PULL_REPLICATION, rather than inferring from object state.

}
}
if (objMD.getDataStoreName() === actionEntry.getAttribute('toLocation')) {
if (objMD.getDataStoreName() === this._getDestStorage(objMD).StorageClass) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate pull entries are expected (see populator doc). Once the first one completes, dataStoreName is the local target (not isCRR), so _getDestStorage falls back to this.site (the CRR location) and this check no longer skips: the task copies the data from the local location back to the CRR location, then publishes a result claiming it went to the target. Before this PR, toLocation === target made it skip.

Base the check on the action, e.g. for pull compare against metrics.fromLocation (or skip whenever the data is no longer on toLocation).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still applies with the reworked _setupDestination: on a replayed pull entry the data is already on the local target (not isCRR), so this.site stays the CRR location, _checkObjectState passes, and the task copies the data back to the CRR location, then publishes toLocation = the CRR location, which LifecycleUpdateTransitionTask writes into the metadata. For metrics.origin === PULL_REPLICATION with data no longer on a CRR location, return InvalidObjectState ("already pulled") from _setupDestination.

}

_publishCopyLocationStatus(err, actionEntry, kafkaEntry, log) {
if (actionEntry.getAttribute('metrics.origin') === PULL_REPLICATION) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics now get the wrong labels for pull: processQueueEntry calls onReplicationProcessed(origin, fromLocation, this.site, ...), and this.site is now the CRR location rather than the target, so it no longer matches onReplicationQueued(PULL_REPLICATION, source, targetLocation) in the populator (the backlog never drains). Same for onLifecycleStarted, which reports the reversed toLocation. Use actionEntry.getAttribute('toLocation') (after this swap) instead of this.site, and the real target for onLifecycleStarted.

@codecov

codecov Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.83%. Comparing base (21682a2) to head (37d8fb3).

Additional details and impacted files

Impacted file tree graph

Files with missing lines Coverage Δ
...s/lifecycle/tasks/LifecycleUpdateTransitionTask.js 95.13% <100.00%> (+0.01%) ⬆️
...xtensions/replication/ReplicationQueuePopulator.js 95.63% <100.00%> (-1.33%) ⬇️
extensions/replication/tasks/CopyLocationTask.js 78.25% <100.00%> (+1.78%) ⬆️

... and 5 files with indirect coverage changes

Components Coverage Δ
Bucket Notification 85.42% <ø> (ø)
Core Library 87.06% <ø> (-0.54%) ⬇️
Ingestion 83.32% <ø> (ø)
Lifecycle 86.24% <100.00%> (+<0.01%) ⬆️
Oplog Populator 94.27% <ø> (ø)
Replication 68.73% <100.00%> (+0.12%) ⬆️
Bucket Scanner 89.37% <ø> (ø)
@@                 Coverage Diff                 @@
##           development/9.6    #2933      +/-   ##
===================================================
- Coverage            82.04%   81.83%   -0.21%     
===================================================
  Files                  217      217              
  Lines                45409    45451      +42     
===================================================
- Hits                 37255    37196      -59     
- Misses                8154     8255     +101     
Flag Coverage Δ
api:retry 14.29% <0.00%> (-0.02%) ⬇️
api:routes 14.31% <0.00%> (-0.02%) ⬇️
bucket-scanner 89.37% <ø> (ø)
ft_test:queuepopulator 17.86% <0.95%> (-1.20%) ⬇️
ingestion 20.18% <0.95%> (-0.06%) ⬇️
lib 12.67% <0.00%> (-0.05%) ⬇️
lifecycle 26.19% <0.00%> (-0.04%) ⬇️
notification 1.86% <0.00%> (-0.01%) ⬇️
oplogPopulator 0.57% <0.00%> (-0.01%) ⬇️
replication 24.75% <46.66%> (+0.01%) ⬆️
unit 68.72% <98.09%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

* @return {null|Error} error if there is no location to pull the data to
*/
_setupDestination(actionEntry, objMD, log) {
if (!locations[objMD.getDataStoreName()]?.isCRR) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This retargets any copy of data that sits on a CRR location, not only pull replication. A lifecycle transition (toLocation: aws-loc) of an object still on dr-source is now written to targetLocation/us-east-1. _publishCopyLocationStatus keeps toLocation: aws-loc for non-pull origins, so the metadata names aws-loc while the data is elsewhere. Gate on the action origin, the same way the publish side does.

Suggested change
if (!locations[objMD.getDataStoreName()]?.isCRR) {
if (actionEntry.getAttribute('metrics.origin') !== PULL_REPLICATION) {

Data processors only take the copies whose toLocation is their own site,
and only the processor of the remote location can read the data to pull.
So the populator now sends pull replications with toLocation set to the
location pulled from (and the actual target in fromLocation): routing and
the rest of the copy work as for any other copy.

The copy task only needs to write the data to the location the object
data points to rather than to its own site, and to restore the actual
direction when publishing the result to the transition processor.

Issue: BB-913
Rather than picking the destination in each write command, set the site
and its type once the object metadata is known: a task handles a single
action. The processed and started metrics then report the actual target.

Issue: BB-913
The copy task now decides where pulled data goes, so resolve the target
there, with the fallback the populator used to apply: objects without
location, or naming a location which does not exist anymore, are pulled
to the default local location. The populator just routes the action to
the processor of the location pulled from.

Issue: BB-913
@francoisferrand
francoisferrand force-pushed the improvement/BB-913/pull-from-source-location-v3 branch from f3e3ae7 to 077c7e5 Compare November 13, 2026 08:33
}
const sourceLocation = queueEntry.getDataStoreName();
// for metrics only: the copy task resolves where the data actually goes
const { targetLocation } = locations?.[0] ?? {};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The populator now uses the raw targetLocation, but CopyLocationTask may fall back to the default local location. When the target is unknown or missing, onReplicationQueued (and onLifecycleTriggered) get labelled with undefined/the deleted location, while onReplicationProcessed reports the fallback. That backlog series then never drains. Either label both sides with the same value (e.g. move the fallback into a shared helper used here for metrics only), or record the queued bytes in the task once the target is resolved.

Pull replication is tracked per location it pulls from, so the triggered
and completed lifecycle metrics use that location like the started one,
instead of the local location the data is copied to.

Issue: BB-913
@francoisferrand

Copy link
Copy Markdown
Contributor Author

Abandoned in favor of #2876

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants