Problem/Motivation

When translations are enabled for content with data, and index is added to the content_translation_uid field. However, the stored entity schema for that type is not updated, triggering a need to run automatic entity updates. When those are run however, since the index already exists, this uncaught exception is thrown:

Cannot add index taxonomy_term__1a0c187e9a to table taxonomy_term_field_data: index already exists

The only recent issue I could find that may have caused this is #2472621: Translatable entity 'created' and 'uid' fields not initialized properly during content translation 'Add'.

Steps to reproduce

  1. Add some term data
  2. Enable the content_translation module
  3. Enable translations on taxonomy terms at admin/config/regional/content-language
  4. Attempt to run updates
  5. See the exception

Proposed resolution

Make SqlContentEntityStorageSchema consistent in checking for pre-existing indexes before trying to create them. Add test coverage. We have additional implicit test coverage through #2555183: Fix the filled update tests, they are broken too.

Remaining tasks

n/a

User interface changes

n/a

API changes

n/a

Data model changes

n/a

Comments

jhedstrom created an issue. See original summary.

jhedstrom’s picture

Issue summary: View changes
jhedstrom’s picture

Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new2.95 KB

Elsewhere in SqlContentEntityStorageSchema there are already checks for pre-existing indexes, so this approach just makes that consistent. With this patch, the number of exceptions thrown in #2555183-12: Fix the filled update tests, they are broken is greatly reduced.

stefan.r’s picture

This looks like a reasonable way to fix this, would a new addIndexIfNotExists() method make sense here? Or alternatively is there an easy way to persist whether the index has been updated during the earlier entity type update event?

jhedstrom’s picture

StatusFileSize
new4.12 KB
new4.02 KB

This adds the new method to simplify the code a bit.

Or alternatively is there an easy way to persist whether the index has been updated during the earlier entity type update event?

Before the approach in #3, I tried to determine where/when the index was added (it is at some point after translation is enabled for a given entity type, via the ContentTranslationUpdatesManager), but I couldn't pinpoint exactly when the index was added.

stefan.r’s picture

Status: Needs review » Reviewed & tested by the community

Looks good!

stefan.r’s picture

Just to add to that, this issue fixes a bug in our upgrade path and is blocking a critical: #2555183: Fix the filled update tests, they are broken

stefan.r’s picture

Issue tags: +blocker
catch’s picture

Assigned: Unassigned » plach

Giving plach a chance to take a look.

plach’s picture

It's a bit late here and I'd like to have a look to this with a fresh mind, but I'm not seeing additional test coverage: is this assuming implicit test coverage is provided by #2555183: Fix the filled update tests, they are broken?

jhedstrom’s picture

This patch resolved some 150+ fails in #2555183: Fix the filled update tests, they are broken, so perhaps the implicit coverage is enough?

jhedstrom’s picture

Sorry, I misspoke above. This patch only resolved a handful of fails, the vast majority were schema mismatches addressed by other patches.

gábor hojtsy’s picture

Priority: Major » Critical
Issue tags: +D8MI, +language-content, +sprint

Elevating to critical because #2555183: Fix the filled update tests, they are broken is a critical and is dependent on this being fixed.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 5: content-translation-uid-index-2555665-05.patch, failed testing.

stefan.r’s picture

Issue tags: +Needs reroll
stefan.r’s picture

stefan.r’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

It's the parent that needed an IS update, not this one...

plach’s picture

Can you please explain the following sentence?

When translations are enabled for content with data, and index is added to the content_translation_uid field.

That field is defined by the Content Translation module, so when translations are enabled for a certain bundle already having data, the field should either exist or not exist. If I'm looking at the code right, it seems the ContentTranslationUpdatesManager only triggers updates for newly added fields, so what's the scenario where only an index is added?

I assume the update op is applied to the content_translation_uid field, but it's not clear to me how that can happen. Anyway, if that's the case, how can be sure the old index specification perfectly matches the current one? Shouldn't we drop the index and re-create it as we do in the other cases?

xjm’s picture

Issue tags: +D8 upgrade path
gábor hojtsy’s picture

Status: Needs work » Needs review
StatusFileSize
new4.02 KB

At least a quick reroll for now.

gábor hojtsy’s picture

Issue tags: +Needs tests

So looks like this does not have tests on its own to prove when is the problem happening. BUT https://qa.drupal.org/pifr/test/1133538 exposes the issue with just running the filled database dump through updates. Fails on

Index users__id__default_langcode__langcode properly created on the user_field_data table in SqlContentEntityStorageSchemaIndexTest.php:44

Among other things.

penyaskito’s picture

+++ b/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema.php
@@ -1867,4 +1872,25 @@ protected function getColumnSchemaRelevantKeys() {
+  protected function addIndexIfNotExists($table, $name, array $fields, array $spec) {
+    if (!$this->database->schema()->indexExists($table, $name)) {
+      $this->database->schema()->addIndex($table, $name, $fields, $spec);
+    }
+  }
+

What happens if the fields indexed have changed? As @plach mentioned in #19, we need to alter the index instead.

stefan.r’s picture

Assigned: plach » Unassigned
stefan.r’s picture

Issue tags: -Needs reroll
jhedstrom’s picture

Assigned: Unassigned » jhedstrom

I'll work on checking for index changes. I think we'll have to drop and re-create indexes if a change is detected.

plach’s picture

Agreed

jhedstrom’s picture

Assigned: jhedstrom » Unassigned
StatusFileSize
new1.31 KB
new5.33 KB

After digging into this, we're already dropping existing indexes before updating them. From SqlContentEntityStorageSchema::updateSharedTableSchema():

            // Drop original indexes and unique keys.
            if (!empty($original_schema[$table_name]['indexes'])) {
              foreach ($original_schema[$table_name]['indexes'] as $name => $specifier) {
                $schema_handler->dropIndex($table_name, $name);
              }
            }

and from SqlContentEntityStorageSchema::onEntityTypeUpdate():

      // Drop original indexes and unique keys.
      foreach ($this->loadEntitySchemaData($entity_type) as $table_name => $schema) {
        if (!empty($schema['indexes'])) {
          foreach ($schema['indexes'] as $name => $specifier) {
            $schema_handler->dropIndex($table_name, $name);
          }
        }

I've added a test to illustrate this.

The reason this is an issue is that there is no record of the previous index (if there were, it would be dropped), so I still think the fix is reasonable to check if a newly added index has been added by another process (in this case the ContentTranslationUpdatesManager .

xjm’s picture

Issue tags: +Triaged D8 critical

Discussed with @webchick, @effulgentsia, @alexpott, and @catch. This issue is critical as a blocker for #2555183: Fix the filled update tests, they are broken and also independently a bug with entity update functionality.

effulgentsia’s picture

gábor hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

@jhedstrom: that makes sense. Thanks for the explicit test coverage, looks good to me. More implicit test coverage will be added in #2555183: Fix the filled update tests, they are broken.

gábor hojtsy’s picture

Issue summary: View changes
plach’s picture

Issue tags: -Needs tests

Looks ready to go.

I will have a another look to this anyway, but don't block commit on my further feedback.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Essentially, this is just adding a new method—addIndexIfNotExists()—and calling it in place of addIndex() to get around the problem. Looks straight-forward to me, and unblocks a blocker of a blocker. ;)

Committed and pushed to 8.0.x. Thanks!

  • webchick committed 410d838 on 8.0.x
    Issue #2555665 by jhedstrom, Gábor Hojtsy, stefan.r, plach: When index...
plach’s picture

@webchick:

I still don't get why the original problem manifests, but that's just the "Content Translation maintainer" inside me speaking.

The "release Drupal 8 for the love of God" guy inside me just says "yay, one sucker less!" ;)

catch’s picture

gábor hojtsy’s picture

Issue tags: -sprint

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.