Closed (fixed)
Project:
Migrate Tools
Version:
6.0.x-dev
Component:
Code
Priority:
Normal
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
2 Jan 2020 at 20:08 UTC
Updated:
8 Jul 2025 at 20:08 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
oxyc commentedComment #3
heddnSounds like the help/docs for sync should include this limitation.
Comment #4
oxyc commentedYeah it might be worth giving a warning. I had been running the early versions of the patch to core for more than a year and had around 3 million revisions when I ran out of disk space :) After switching to the lastest patch to migrate_tools I noticed it had the same issue.
I'll include a hacky patch I'm using as a quick fix. Unfortunately I rarely work with Drupal nowadays and I don't think I'll be able to contribute more
Comment #5
gaëlgDo you mean this limitation cannot be removed? If so, can you please explain why?
Comment #6
gaëlgSelf-answer: it's seems difficult to remove this limitation without some change to the migrate module (core), because:
* we need the source ids to be able to compare with previously imported,
* for that, we have to loop on the source,
* loops on the source call SourcePluginBase::next(),
* SourcePluginBase::next() only give rows that are new, flagged as needing update, have an updated highwater mark, or changed.
So it might be possible to do something not too hacky, but it would need changes to core. If I can't do without this feature (sync+track_changes), I may create a core issue/patch.
Comment #7
gaëlgComment #8
gaëlgI slept on it and now I see that I headed to the same approach as what was first being thought in #2809433: Migrate support for deleting items no longer in the incoming data. It adds a check in SourcePluginBase::next() to be able to loop over all the source rows (allRows mode).
But as it was decided that the core would not change (#2809433-88: Migrate support for deleting items no longer in the incoming data), @quietone tried to move the existing core patch to migrate_tools: #2809433-95: Migrate support for deleting items no longer in the incoming data.
It initially failed because of the core next() problem I explained above:
"Not working yet. failing to get any rows from the map."
"Your source plugin isn't returning rows because the rows are already imported, and source plugin base filters out rows that have already been processed by default."
"An idea from #2809433-81 was missing: the "all rows" source configuration option and the related changes over next(); that is the reason I think we cannot work-around sources not implementing the SyncableSourceInterface interface"
This was the start of two new approachs, discussed somewhat in parallel which makes it hard to read:
A) @Marvil07 suggested to extend SourcePluginBase to override the next() method: #2809433-110: Migrate support for deleting items no longer in the incoming data. It meant that all existing source sub-classes needed to be extended.
B) @mikelutz suggested the prepareUpdate() workaround (#2809433-109: Migrate support for deleting items no longer in the incoming data). He understood it would be a problem to keep all the id map rows in "needs update" status (and indeed, this is what breaks track_changes). So he suggested: "at the end resave all the idmap rows to reset their status to imported."
@heddn was more into this approach: "Can we get the super simple solution here addressed first?"
@quietone said: "I am not convinced we should set the row status to imported after this rollbackmissing operation since that would also change failed and skip status to imported." which is why he helped on approach A.
Then, people mainly worked on A, even if @heddn (migrate_tools maintainer) wanted B (at least as a first step): #2809433-160: Migrate support for deleting items no longer in the incoming data, #3067311: [meeting] Migrate Meeting 2019-07-11. So, @heddn published a patch for B: #2809433-181: Migrate support for deleting items no longer in the incoming data, and finally B was committed.
But: the problem mentioned at the very start of B (how to keep the id map rows statuses unchanged at the end of the loop?) remains (not to mention performance concerns), so that track_changes cannot work!
Now, I'm wondering how we could fix that, as I agree with @quietone (in italic above).
Comment #9
gaëlgI think I found a better workaround than prepareUpdate(): use hook_migrate_prepare_row(). Here's a POC patch that seems to work well for my needs. I can now use track_changes normally. :)
Comment #10
heddnNice! Instead of using drupal_static, could we use state instead? I think that would handle any batch resets or memory clean-up that might happen.
Comment #11
geek-merlinThis bit me too.
@GaëlG: A wholehearted "Wow!💪" for your research and work in #8.
Comment #12
peacog commentedThank you @GaëlG. I was stuck using the old patch on #2809433: Migrate support for deleting items no longer in the incoming data until I found your patch here and was able to upgrade the module.
It needed a re-roll for 8.x-5.x. Here it is.
Comment #13
heddnThe great gitlab migration is upon us. See https://gitlab.com/drupalspoons/migrate_tools/-/issues/94. The latest patch from #12 has been uploaded to https://gitlab.com/drupalspoons/migrate_tools/-/merge_requests/4
Comment #14
botanic_spark commented#9 solved issue for us! Thanks for working on this!
Comment #15
neelam.chaudhary commented#12 solved the issue for me. It's keeping the "track_changes: true"property while using --sync parameter.
The rows are getting updated only if there is update in the source data and if the rows are not available then the content is getting rollback.
Thanks
Comment #16
byrond commentedThe patch in #12 works for me as well, and it also resolves #3104268: Sync is too strict during id comparison and can roll back everything. I'm reopening this as "Needs work" as there are still some items from #10 to address. I assume this was only closed due to the detour to DrupalSpoons.
Comment #17
singularoThe patch in #12 gave the behaviour I was expecting, rolling back the things that were deleted on the source site. Thanks!
Comment #18
esolano commented#12 works for us as well, but source id (
ids) needs to be a string. This didn't work for us if the ids was an integer.Comment #19
phma commentedI've re-rolled the original patch for 6.0.x including the improvements by @csmdgl and @PCateNIH in GitLab.
I've updated the tests to run with and without the
--updateflag set. The behaviour of--syncwith--updateis identical to the default behaviour without this patch. So this is technically breaking BC or improving import performance, depending on how you see it.Comment #20
phma commentedTests run too fast to capture the full process output. I had to remove one assert.
Comment #21
phma commentedComment #22
phma commentedComment #23
heddnI'm not sure I like the use of a static public property on
MigrationImportSync. Could we use some other temp store instead to pass around data? It just seems brittle and icky. Still thinking what a better approach might look like.Comment #25
heddnI think we can use
\Drupal::state()->get/set('migrate_tools_sync'), where we key the values by the migration name. And the first thing we do when executing a sync is to reset the values. That lets us store/retrieve the values and have them reset when syncing the migration again. And it gets away from the more ugly feeling of using public statics.Comment #27
egruel commentedIn my case the patch #22 don't work, Everything is rollback and everything is reimported.
After some research i found i need to combine this patch with the logic implemented in this patch #4
But patch #4 work only with version 8.5.x so i make this patch to combine the both in one.
Comment #30
egruel commentedComment #32
egruel commentedComment #33
jaykandariSubscribe
Comment #34
j_drupalThe patch in #32 doesn't work for string IDs, such as UUIDs.
It currently parses the source IDs using
intval, which causes UUIDs like this "48b79c41-d97c-4076-8e2d-cbb6c0357b7b" to get converted to "48".Calling either
strvalorintvaldepending on the "type" defined ingetIds()seems like a more robust solution.I have created a new patch that works for both integer and string source IDs.
Comment #35
pcate commentedUploaded new patch. Is same as #34 but replaces the static
$source_id_valuespublic property with the State API per #25.Comment #36
pcate commentedComment #38
pcate commentedRe-roll of #35 patch to work with latest dev version.
Comment #39
vasikeI confirm the latest patches works ...
Note: #35 applies to. latest stable releases - 6.0.0.
Comment #40
heddnMinor feedback, will fix on commit.
$map_source_id[$id_key] = (string) $map_source_id[$id_key];
$map_source_id[$id_key] = (int) ($map_source_id[$id_key];
Comment #42
heddnComment #44
mogio_hh commentedI do not understand what this path is supposed to do?
I installed #35 on 6.0.0.
I expected that when changing a value of an item (in my case an xml item) it would be updated when using the sync option.
but this is not the case.
Is that not what the patch is supposed to do ?
Thanks for clarifying