Skip to content

Let the source location's data processor copy pulled data to the location it targets - #2876

Open
SylvainSenechal wants to merge 1 commit into
development/9.6from
improvement/BB-913/pull-from-source-location
Open

SylvainSenechal wants to merge 1 commit into
development/9.6from
improvement/BB-913/pull-from-source-location

Conversation

@SylvainSenechal

@SylvainSenechal SylvainSenechal commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

With pull replication, the sink copies each object's data from a remote source location (for example dr-source) into a local location (for example us-east-1). The copy is a copyLocation action with fromLocation = the source and toLocation = the local target.

Two problems in the data processor:

The copy was never performed. Backbeat has one data processor per replication site (a remote location such as dr-source, or a cloud location), and each data processor only performs the copies whose target is its own site. Here the target is the local location (us-east-1). A local location is not a replication site, so it has no data processor, and no data processor performed the copy. The data processor that should perform it is the one of the source location (dr-source): it's the only one with that location's address and credentials, so the only one able to read the data.

Once given to the data processor of dr-source, the copy would go to the wrong place. A data processor always writes the copied data to its own site, because until now its own site was always the target of the copy. With pull replication that's no longer true: the data processor of dr-source performs the copy, but the target is us-east-1. Writing "to its own site" would send the data back to dr-source instead of us-east-1. Cloudserver also needs the storage type of the location it writes to, and that type wasn't sent. So the data processor must write to the target of the copy (us-east-1), with that location's type.

Issue: BB-913

@bert-e

bert-e commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Hello sylvainsenechal,

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.

@codecov

codecov Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.58%. Comparing base (cf55ec7) to head (d6bc359).
⚠️ Report is 4 commits behind head on development/9.6.

Files with missing lines Patch % Lines
extensions/replication/tasks/CopyLocationTask.js 82.35% 6 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

Files with missing lines Coverage Δ
extensions/lifecycle/tasks/LifecycleTask.js 94.24% <100.00%> (+<0.01%) ⬆️
extensions/replication/ReplicationAPI.js 91.87% <100.00%> (+0.15%) ⬆️
...xtensions/replication/ReplicationQueuePopulator.js 96.29% <100.00%> (+0.01%) ⬆️
...sions/replication/queueProcessor/QueueProcessor.js 79.28% <100.00%> (+0.48%) ⬆️
extensions/replication/tasks/CopyLocationTask.js 76.66% <82.35%> (+0.18%) ⬆️

... and 4 files with indirect coverage changes

Components Coverage Δ
Bucket Notification 85.42% <ø> (ø)
Core Library 87.07% <ø> (-0.43%) ⬇️
Ingestion 83.32% <ø> (ø)
Lifecycle 86.24% <100.00%> (+<0.01%) ⬆️
Oplog Populator 94.27% <ø> (ø)
Replication 68.76% <85.36%> (+0.11%) ⬆️
Bucket Scanner 89.37% <ø> (ø)
@@                 Coverage Diff                 @@
##           development/9.6    #2876      +/-   ##
===================================================
- Coverage            81.74%   81.58%   -0.16%     
===================================================
  Files                  217      217              
  Lines                45569    45593      +24     
===================================================
- Hits                 37250    37199      -51     
- Misses                8319     8394      +75     
Flag Coverage Δ
api:retry 14.25% <0.00%> (-0.01%) ⬇️
api:routes 14.27% <0.00%> (-0.01%) ⬇️
bucket-scanner 89.37% <ø> (ø)
ft_test:queuepopulator 17.85% <4.76%> (-0.77%) ⬇️
ingestion 20.16% <4.76%> (-0.01%) ⬇️
lib 12.64% <0.00%> (-0.01%) ⬇️
lifecycle 26.10% <9.52%> (-0.02%) ⬇️
notification 1.85% <0.00%> (-0.01%) ⬇️
oplogPopulator 0.57% <0.00%> (-0.01%) ⬇️
replication 24.64% <64.28%> (-0.04%) ⬇️
unit 68.52% <69.04%> (+0.01%) ⬆️

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.

@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch from c8a6160 to 030ca9f Compare October 16, 2026 13:17
@scality scality deleted a comment from bert-e Oct 16, 2026
@bert-e

bert-e commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Waiting for approval

The following approvals are needed before I can proceed with the merge:

  • the author

  • 2 peers

@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch 2 times, most recently from 26f607b to d43e81a Compare October 16, 2026 16:16
@SylvainSenechal
SylvainSenechal marked this pull request as ready for review October 16, 2026 16:45
@SylvainSenechal
SylvainSenechal requested review from a team, benzekrimaha, delthas and francoisferrand and removed request for benzekrimaha October 16, 2026 16:45
@SylvainSenechal SylvainSenechal changed the title Improvement/bb 913/pull from source location Let the source location's data processor copy pulled data to the location it targets Oct 19, 2026
@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch 2 times, most recently from bab8486 to 2f1f046 Compare October 19, 2026 08:28

@francoisferrand francoisferrand left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not sure about this PR :

  • if we keep using the current way the code works, the message shoudl be processed by the "default/standard" location queue processor (like transitions to that location) - which we probably don't have
  • here you tweak every place where we use 'location', to work around it...and need to introduce fromLocatin.

2 things:

  • should we process pullReplication in the destination processor or the source one? even if it worked, I agree we should probably keep it in the processor dedicated to that location
  • instead of "reversing" the parameters everywhere, maybe we could just fix the message that is sent: set toLocation to the "source" location, so everything works naturally. And we keep one difference in one place, i.e. where we do the copy and which is already different (and may need to tweak the followup message we send to "update" the storage class)

Both your approach and the one I draft most likely work, but not sure why I am a bit unconfortable with the one you implemented :-/ (the other has one straightforward and explicit inconsistency -i.e. we field is not named correctly- but seems to follow the code more naturally, for afar...)

What do you think?

// Each data processor performs the copies to its own site, plus the copies
// from its site when that site is remote (pull replication): it is the only
// one that can read from there.
const fromLocation = actionEntry.getAttribute('fromLocation');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we have already in the message an information which explicitely indicates if this is pull-replication or transition:

originLabel: PULL_REPLICATION // 'pullReplication'
originLabel: 'lifecycle'

Should we not use this condition instead?

Suggested change
const fromLocation = actionEntry.getAttribute('fromLocation');
const loc = actionEntry.getAttribute('origin') === 'pullReplication' ? actionEntry.getAttribute('fromLocation') : actionEntry.getAttribute('toLocation')

@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch from 2f1f046 to bcb4671 Compare November 11, 2026 02:04
Comment thread lib/models/ActionQueueEntry.js Resolved
Comment thread lib/models/ActionQueueEntry.js Resolved
@SylvainSenechal

Copy link
Copy Markdown
Contributor Author

not sure about this PR :

  • if we keep using the current way the code works, the message shoudl be processed by the "default/standard" location queue processor (like transitions to that location) - which we probably don't have
  • here you tweak every place where we use 'location', to work around it...and need to introduce fromLocatin.

2 things:

  • should we process pullReplication in the destination processor or the source one? even if it worked, I agree we should probably keep it in the processor dedicated to that location
  • instead of "reversing" the parameters everywhere, maybe we could just fix the message that is sent: set toLocation to the "source" location, so everything works naturally. And we keep one difference in one place, i.e. where we do the copy and which is already different (and may need to tweak the followup message we send to "update" the storage class)

Both your approach and the one I draft most likely work, but not sure why I am a bit unconfortable with the one you implemented :-/ (the other has one straightforward and explicit inconsistency -i.e. we field is not named correctly- but seems to follow the code more naturally, for afar...)

What do you think?

I applied your two suggestions, using PULL_REPLICATION to check if we are in a pull replication scenario, and also the refactoring with a new isPullReplication method on the Action class.
I think the current design is quite simple though, not sure about your suggestion. With your suggestion we would have both toLocation/fromLocation = dr-source, so no need for the dispatch change in the queue processor, but then there are quite a lot of stuff we need to add : A new field in the message to pass the location we want to write to even though we already have toLocation, and I think there are still some other corner case in the code where we would need special logic

@scality scality deleted a comment from bert-e Nov 11, 2026
@bert-e

bert-e commented Nov 11, 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.

attempt: params.attempt,
lastModified: params.lastModified,
})
.setAttribute('fromLocation', params.fromLocation)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

instead of fromLocation, we should add a site attribute which is either equal to fromLocation (for pull replication) or toLocation (for transition)
→ allows to easily filter in QueuePopulator, and can be used in metrics

(needs a fallback to toLocation attribute, for "old" messages)

actionEntry.getAttribute('metrics');
ReplicationMetrics.onReplicationProcessed(
origin, fromLocation, this.site, contentLength,
origin, fromLocation, this._getDestination(actionEntry).location, contentLength,

@francoisferrand francoisferrand Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

getattribute("toLocatoin")

@@ -318,7 +334,7 @@ class CopyLocationTask extends BackbeatTask {
const { origin, fromLocation, contentLength } =
actionEntry.getAttribute('metrics');
ReplicationMetrics.onReplicationProcessed(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the Lifecycle metrics (for PullReplication) should probably use the "site" attribute (i.e. fromLocation in pull replication) : let's create a followup ticket to address this thoroughly (if affects not only CopyLocationTask, but also QueueProcessor and TransitionStatusProcessor)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah I created a ticket

if (actionEntry.getAttribute('toLocation') === this.site) {
// Each data processor performs the copies to its own site, plus the pull
// replications from its site: it is the only one that can read from there.
const siteInCharge = actionEntry.isPullReplication() ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

route based on site attribute (fallback to toLocation attribute)

Comment thread lib/models/ActionQueueEntry.js Outdated
Comment on lines +202 to +211
/**
* A pull replication copies data from a remote location (fromLocation) to a
* location of this Zenko (toLocation)
*
* @return {boolean} true if the action is a pull replication
*/
isPullReplication() {
return this.getContextAttribute('origin') === pullReplicationOrigin;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should not be needed : metrics.origin is not used for "deciding", but only to set on metrics

Suggested change
/**
* A pull replication copies data from a remote location (fromLocation) to a
* location of this Zenko (toLocation)
*
* @return {boolean} true if the action is a pull replication
*/
isPullReplication() {
return this.getContextAttribute('origin') === pullReplicationOrigin;
}

Comment thread lib/constants.js Outdated
// extra round-trip is a bigger overhead than the bandwidth saved
replicationExpectContinueThreshold: 1024 * 1024, // 1 mb
// origin of the actions that copy data pulled from a remote location
pullReplicationOrigin: 'pullReplication',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

may not be needed anymore (and keep the PULL_REPLICATION metrics)

Comment on lines +51 to +55
const location = actionEntry.getAttribute('toLocation');
if (actionEntry.isPullReplication()) {
return { location, storageType: locations[location]?.type };
}
return { location, storageType: this.destType };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
const location = actionEntry.getAttribute('toLocation');
if (actionEntry.isPullReplication()) {
return { location, storageType: locations[location]?.type };
}
return { location, storageType: this.destType };
const location = actionEntry.getAttribute('toLocation');
if (location == this.site) {
return { location, storageType: this.destType };
}
return { location, storageType: locations[location]?.type };

@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch from 9afd940 to 2bae062 Compare November 13, 2026 15:39
eTag: params.eTag,
lastModified: params.lastModified,
toLocation: params.site,
site: params.site,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This isnt 100$ mandatory but I added it because otherwise, in createCopyLocationAction, we would've had to use a fallback site = params.site || params.toLocation, instead of site = params.site which I prefer

@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch from 2bae062 to a0a99db Compare November 13, 2026 15:51
@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch from a0a99db to c68f2a2 Compare November 13, 2026 16:24
@@ -39,6 +39,21 @@ class CopyLocationTask extends BackbeatTask {
return this.destConfig?.replicationEndpoint?.type;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this function should probably be fixed (less changes) or dropped (you replaced multiple -hopefully all- calls)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah I'm inlining it

@SylvainSenechal
SylvainSenechal force-pushed the improvement/BB-913/pull-from-source-location branch from c68f2a2 to d6bc359 Compare November 13, 2026 16:52

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.

3 participants