Problem/Motivation
Using the the --sync when importing a migration that uses track_changes in the source plugin causes all records to be updated, not only the ones that change in the source. See original report for more context. Be aware that this behavior happens for all source plugins, not only CSV.
Original report
Hi ! First of all, first time publishing an issue. Sorry if I make any mistakes along the way. ^^"
When importing a CSV file using --sync with a migration yaml containing the Track Changes property, unchanged CSV files are still updated, wasting a lot of time.
My import of about 2000 rows using my computer took 13 minutes whereas using the proposed solution, time goes down to 40 seconds.
Steps to reproduce
Import a CSV file once with the track_changes:true parameter in the source part of the migration yml file.
Use drush mim --sync to import again the same CSV and see the rows are updated instead of being ignored.
Proposed resolution
--sync and track_changes are not compatible. The --sync flag will change the status of all source row to 'needs update' and therefor all rows are processed. See #8
-- original proposal --
Add a check before processRow( ) to skip if it doesn't need to be processed.
(note : I've made a patch for this but talking with my company boss about the best way to publish it. Again, never done this before.)
Remaining tasks
Review the code / Talk about best way to implement this / Get informed about best practice regarding Migrate ?
Thanks !
| Comment | File | Size | Author |
|---|---|---|---|
| #26 | TrackChangesNotWorking-3211358-26.patch | 1.65 KB | kenowax |
| #23 | TrackChangesNotWorking-3211358-23.patch | 1.62 KB | kenowax |
| #22 | TrackChangesNotWorking-3211358-20.patch | 1.62 KB | kenowax |
| #5 | migrate_plus.migration.kenowax_en.yml | 3.05 KB | kenowax |
Comments
Comment #2
kenowax commentedHere's the patch file I made.
Comment #3
quietone commented@KenowaX, thanks for the report and the patch. Can you upload the yml for the migration where track_changes wasn't working for you. Thanks.
Comment #4
kenowax commentedSure, I'll upload the yaml file as soon as I can.
Thanks for the help!
Comment #5
kenowax commentedHere's the YAML file. :)
Comment #6
kenowax commentedAdded the migration config .yml file.
Comment #7
quietone commented@KenowaX, thanks. I might be able to have a closer look on the weekend.
Comment #8
dinarcon commentedI did some testing with the
ud_migrations_csv_sourcemodule from https://github.com/dinarcon/ud_migrations Thetrack_changesworks as expected with CSV files. Records are updated only when the source data changes. From looking at the code in Drupal core and Migrate Tools, thetrack_changesconfiguration for source plugins and the--syncflag for themigrate:importDrush commands are not compatible. Or at least it will not provide the intended behavior which I understand to be only update records that have changed in the source CSV.As @huzooka pointed out in slack, the place to look at is
\Drupal\migrate\Plugin\migrate\source\SourcePluginBase::next. Specifically this check:When the
--syncflag is not used, the$this->rowChanged($row)is reached. This would call\Drupal\migrate\Row::changedand compared the original hash against the current hash from the source. Things would work as expected in this case.The incompatibility comes from setting the
--syncflag. In\Drupal\migrate_tools\EventSubscriber\MigrationImportSync::syncthere is a call to$id_map->prepareUpdate();. The implementation at\Drupal\migrate\Plugin\migrate\id_map\Sql::prepareUpdatechanges thesource_row_statusfor all source records toMigrateIdMapInterface::STATUS_NEEDS_UPDATE. So, when the check mentioned above is reached and$row->needsUpdate()is evaluated, the records will always be marked as needed to be imported. That is because\Drupal\migrate\Row::needsUpdatechecks if$this->idMap['source_row_status'] == MigrateIdMapInterface::STATUS_NEEDS_UPDATE. That will always be TRUE when using the--sync. So, the condition returns early and$this->rowChanged($row)never gets evaluated.I do not think this is a bug in Drupal core. It looks like a documentation issue. That is, the
--syncflag formigrate:importis not compatible withtrack_changesif you only want to limit the import operations to values that changed in the source.A few things I found interesting. The entity
changedkeeps the same value even if the report frommigrate:importsays that records have been updated. Also,\Drupal\migrate_tools\EventSubscriber\MigrationImportSync::syncgoes over all source records to determine if something needs to be deleted before\Drupal\migrate\MigrateExecutable::importis reached.For the record, I tested with:
Update: I wonder if this is related to CSV migrations at all. The way I understand it, this would be an issue with any source plugin. The "conflicting" settings are
track_changesfromSourcePluginBaseand the--syncflag from Migrate Tools'migrate:importcommand. I do not see how the CSV source plugin plays a role there.Comment #9
quietone commented@dinarcon, thank you for taking the time to look into this!
Ah, that explains it!
I've updated the IS with this information.
Now what next. I think this should be documented somewhere. How about at https://git.drupalcode.org/project/migrate_tools/-/blob/8.x-4.x/src/Comm.... Moving to Migrate Tools and attaching a patch.
Any other place to document?
Comment #10
dinarcon commented@quiteone thanks for the patch. A nit: It is missing a quote after
'track_changes. I think this is a good place to place to make note of the incompatibility.Also, is it possible to throw an error when
--syncis used with a migration that usestrack_changes? An error in the console right away would make it easier to spot the incompatibility. Something like the way\Drupal\migrate\Plugin\migrate\source\SourcePluginBase::__constructenforceshigh_water_propertyandtrack_changescannot be used at the same time.Update: Drush 10.4+ offers the
--deleteflag. I have not checked the implementation, but this is another place where documentation updates might be required.Comment #11
dinarcon commentedUpdating the issue title and summary.
Comment #12
dinarcon commentedUpdating issue summary.
Comment #13
quietone commentedChanging to NR for the patch in #9
Comment #14
heddnre #10
--deleteflag,I don't think the delete flag does anything. Or it sure doesn't look like it.
NW for #10:
Comment #15
kenowax commentedThis might be another issue, but shouldn't these options --sync, --update and --delete be separate commands altogether ?
This way, we could use something closer to a CRUD system and have parameters such as --force to force an update.
In this case, we'd have :
- Drush migrate:import
=> only imports new stuff (CREATE)
- Drush migrate:update
=> only updates (UPDATE - updates all, except if track_changes is used. updates all if --force used)
- Drush migrate:delete
=> only deletes stuff that doesn't exist anymore (DELETE - id --force is used, deletes everything from the given migration)
- Drush migrate:sync
=> Synchronises everything (does CREATE, UPDATE AND DELETE)
What d'you think ?
Comment #16
heddnThey could be separated, but then we'd have BC implications.
Comment #17
kenowax commentedFor anyone interested, I updated my patch to remove all the error logs that took a lot of space and only produce 1 error log containing the number of skipped migrations due to no changes being found at import.
Comment #18
kenowax commentedYeah, I think my previous upload bugged as the file is empty.
I re-uploaded it.
Comment #19
kenowax commentedOk, still not working. Trying one last time.
Sry for the spam. ^^"
Comment #20
gaëlgIt may be a duplicate of #3104105: sync option doesnt work with track_changes ?
Comment #21
kenowax commentedI had already tried the proposed solution in that issue but it did not work for me as it would throw errors and stop the migration altogether.
Comment #22
kenowax commentedNew patch.
Old one was missing a piece of code.
Comment #23
kenowax commentedThis version of the patch works with Drupal 8.9.
The other one was for Drupal 9.
Comment #24
kenowax commentedComment #25
kenowax commentedComment #26
kenowax commentedAdded fix for --update option of import that wasn't compatible.
Comment #27
bisonbleu commentedI know the current issue is about track_changes, but I'm seeing the same behavior with high_water_property.
The migration runs twice.
[update]: In Drupal Slack # migration, @mikelutz says this is a «Works as designed» since --sync flags all rows as needing an update so it can process them and see if they need to be removed.
Comment #28
kenowax commentedClosing as track_changes and sync work as designed.
Comment #29
phma commentedIsn't this rather a duplicate of https://www.drupal.org/project/migrate_tools/issues/3104105 than "works as designed"?