This is an automated email from the ASF dual-hosted git repository. jakevin pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new c76a1401282 [fix](Nereids): log constraint editlog in lock scope (#30630) c76a1401282 is described below commit c76a14012824c7d81c467c2f41267306ce1ba7fa Author: 谢健 <jianx...@gmail.com> AuthorDate: Tue Feb 20 14:39:39 2024 +0800 [fix](Nereids): log constraint editlog in lock scope (#30630) --- .../java/org/apache/doris/catalog/TableIf.java | 113 +++++++++++++-------- .../trees/plans/commands/AddConstraintCommand.java | 13 +-- .../plans/commands/DropConstraintCommand.java | 5 +- .../java/org/apache/doris/persist/EditLog.java | 2 +- .../catalog/constraint/ConstraintPersistTest.java | 55 +++++++++- 5 files changed, 127 insertions(+), 61 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java index 7c1943c69a6..29c7d6b83e2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TableIf.java @@ -26,6 +26,7 @@ import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.DdlException; import org.apache.doris.common.MetaNotFoundException; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.persist.AlterConstraintLog; import org.apache.doris.statistics.AnalysisInfo; import org.apache.doris.statistics.BaseAnalysisTask; import org.apache.doris.statistics.ColumnStatistic; @@ -227,7 +228,7 @@ public interface TableIf { } // Note this function is not thread safe - default void checkConstraintNotExistence(String name, Constraint primaryKeyConstraint, + default void checkConstraintNotExistenceUnsafe(String name, Constraint primaryKeyConstraint, Map<String, Constraint> constraintMap) { if (constraintMap.containsKey(name)) { throw new RuntimeException(String.format("Constraint name %s has existed", name)); @@ -240,87 +241,108 @@ public interface TableIf { } } - default Constraint addUniqueConstraint(String name, ImmutableList<String> columns) { + default void addUniqueConstraint(String name, ImmutableList<String> columns, boolean replay) { writeLock(); try { Map<String, Constraint> constraintMap = getConstraintsMapUnsafe(); UniqueConstraint uniqueConstraint = new UniqueConstraint(name, ImmutableSet.copyOf(columns)); - checkConstraintNotExistence(name, uniqueConstraint, constraintMap); + checkConstraintNotExistenceUnsafe(name, uniqueConstraint, constraintMap); constraintMap.put(name, uniqueConstraint); - return uniqueConstraint; + if (!replay) { + Env.getCurrentEnv().getEditLog().logAddConstraint( + new AlterConstraintLog(uniqueConstraint, this)); + } } finally { writeUnlock(); } } - default Constraint addPrimaryKeyConstraint(String name, ImmutableList<String> columns) { + default void addPrimaryKeyConstraint(String name, ImmutableList<String> columns, boolean replay) { writeLock(); try { Map<String, Constraint> constraintMap = getConstraintsMapUnsafe(); PrimaryKeyConstraint primaryKeyConstraint = new PrimaryKeyConstraint(name, ImmutableSet.copyOf(columns)); - checkConstraintNotExistence(name, primaryKeyConstraint, constraintMap); + checkConstraintNotExistenceUnsafe(name, primaryKeyConstraint, constraintMap); constraintMap.put(name, primaryKeyConstraint); - return primaryKeyConstraint; + if (!replay) { + Env.getCurrentEnv().getEditLog().logAddConstraint( + new AlterConstraintLog(primaryKeyConstraint, this)); + } } finally { writeUnlock(); } } - default void updatePrimaryKeyForForeignKey(PrimaryKeyConstraint requirePrimaryKey, TableIf referencedTable) { - referencedTable.writeLock(); - try { - Optional<Constraint> primaryKeyConstraint = referencedTable.getConstraintsMapUnsafe().values().stream() - .filter(requirePrimaryKey::equals) - .findFirst(); - if (!primaryKeyConstraint.isPresent()) { - throw new AnalysisException(String.format( - "Foreign key constraint requires a primary key constraint %s in %s", - requirePrimaryKey.getPrimaryKeyNames(), referencedTable.getName())); - } - ((PrimaryKeyConstraint) (primaryKeyConstraint.get())).addForeignTable(this); - } finally { - referencedTable.writeUnlock(); + default PrimaryKeyConstraint tryGetPrimaryKeyForForeignKeyUnsafe( + PrimaryKeyConstraint requirePrimaryKey, TableIf referencedTable) { + Optional<Constraint> primaryKeyConstraint = referencedTable.getConstraintsMapUnsafe().values().stream() + .filter(requirePrimaryKey::equals) + .findFirst(); + if (!primaryKeyConstraint.isPresent()) { + throw new AnalysisException(String.format( + "Foreign key constraint requires a primary key constraint %s in %s", + requirePrimaryKey.getPrimaryKeyNames(), referencedTable.getName())); } + return ((PrimaryKeyConstraint) (primaryKeyConstraint.get())); } - default Constraint addForeignConstraint(String name, ImmutableList<String> columns, - TableIf referencedTable, ImmutableList<String> referencedColumns) { + default void addForeignConstraint(String name, ImmutableList<String> columns, + TableIf referencedTable, ImmutableList<String> referencedColumns, boolean replay) { writeLock(); + referencedTable.writeLock(); try { Map<String, Constraint> constraintMap = getConstraintsMapUnsafe(); ForeignKeyConstraint foreignKeyConstraint = new ForeignKeyConstraint(name, columns, referencedTable, referencedColumns); - checkConstraintNotExistence(name, foreignKeyConstraint, constraintMap); - PrimaryKeyConstraint requirePrimaryKey = new PrimaryKeyConstraint(name, + checkConstraintNotExistenceUnsafe(name, foreignKeyConstraint, constraintMap); + PrimaryKeyConstraint requirePrimaryKeyName = new PrimaryKeyConstraint(name, foreignKeyConstraint.getReferencedColumnNames()); - updatePrimaryKeyForForeignKey(requirePrimaryKey, referencedTable); + PrimaryKeyConstraint primaryKeyConstraint = + tryGetPrimaryKeyForForeignKeyUnsafe(requirePrimaryKeyName, referencedTable); + primaryKeyConstraint.addForeignTable(this); constraintMap.put(name, foreignKeyConstraint); - return foreignKeyConstraint; + if (!replay) { + Env.getCurrentEnv().getEditLog().logAddConstraint( + new AlterConstraintLog(foreignKeyConstraint, this)); + } } finally { + referencedTable.writeUnlock(); writeUnlock(); } } default void replayAddConstraint(Constraint constraint) { - if (constraint instanceof UniqueConstraint) { - UniqueConstraint uniqueConstraint = (UniqueConstraint) constraint; - this.addUniqueConstraint(constraint.getName(), - ImmutableList.copyOf(uniqueConstraint.getUniqueColumnNames())); - } else if (constraint instanceof PrimaryKeyConstraint) { - PrimaryKeyConstraint primaryKeyConstraint = (PrimaryKeyConstraint) constraint; - this.addPrimaryKeyConstraint(primaryKeyConstraint.getName(), - ImmutableList.copyOf(primaryKeyConstraint.getPrimaryKeyNames())); - } else if (constraint instanceof ForeignKeyConstraint) { - ForeignKeyConstraint foreignKey = (ForeignKeyConstraint) constraint; - this.addForeignConstraint(foreignKey.getName(), - ImmutableList.copyOf(foreignKey.getForeignKeyNames()), - foreignKey.getReferencedTable(), - ImmutableList.copyOf(foreignKey.getReferencedColumnNames())); + // Since constraints are not indispensable, we only log when replay fails + try { + if (constraint instanceof UniqueConstraint) { + UniqueConstraint uniqueConstraint = (UniqueConstraint) constraint; + this.addUniqueConstraint(constraint.getName(), + ImmutableList.copyOf(uniqueConstraint.getUniqueColumnNames()), true); + } else if (constraint instanceof PrimaryKeyConstraint) { + PrimaryKeyConstraint primaryKeyConstraint = (PrimaryKeyConstraint) constraint; + this.addPrimaryKeyConstraint(primaryKeyConstraint.getName(), + ImmutableList.copyOf(primaryKeyConstraint.getPrimaryKeyNames()), true); + } else if (constraint instanceof ForeignKeyConstraint) { + ForeignKeyConstraint foreignKey = (ForeignKeyConstraint) constraint; + this.addForeignConstraint(foreignKey.getName(), + ImmutableList.copyOf(foreignKey.getForeignKeyNames()), + foreignKey.getReferencedTable(), + ImmutableList.copyOf(foreignKey.getReferencedColumnNames()), true); + } + } catch (Exception e) { + LOG.error(e.getMessage()); } } - default Constraint dropConstraint(String name) { - Constraint dropConstraint; + default void replayDropConstraint(String name) { + try { + dropConstraint(name, true); + } catch (Exception e) { + LOG.error(e.getMessage()); + } + } + + default void dropConstraint(String name, boolean replay) { writeLock(); try { Map<String, Constraint> constraintMap = getConstraintsMapUnsafe(); @@ -334,11 +356,12 @@ public interface TableIf { ((PrimaryKeyConstraint) constraint).getForeignTables() .forEach(t -> t.dropFKReferringPK(this, (PrimaryKeyConstraint) constraint)); } - dropConstraint = constraint; + if (!replay) { + Env.getCurrentEnv().getEditLog().logDropConstraint(new AlterConstraintLog(constraint, this)); + } } finally { writeUnlock(); } - return dropConstraint; } default void dropFKReferringPK(TableIf table, PrimaryKeyConstraint constraint) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java index 8c90bc0f914..38bf71133c0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AddConstraintCommand.java @@ -17,7 +17,6 @@ package org.apache.doris.nereids.trees.plans.commands; -import org.apache.doris.catalog.Env; import org.apache.doris.catalog.TableIf; import org.apache.doris.common.Pair; import org.apache.doris.nereids.NereidsPlanner; @@ -30,7 +29,6 @@ import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; -import org.apache.doris.persist.AlterConstraintLog; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.StmtExecutor; @@ -63,19 +61,16 @@ public class AddConstraintCommand extends Command implements ForwardWithSync { @Override public void run(ConnectContext ctx, StmtExecutor executor) throws Exception { Pair<ImmutableList<String>, TableIf> columnsAndTable = extractColumnsAndTable(ctx, constraint.toProject()); - org.apache.doris.catalog.constraint.Constraint catalogConstraint = null; if (constraint.isForeignKey()) { Pair<ImmutableList<String>, TableIf> referencedColumnsAndTable = extractColumnsAndTable(ctx, constraint.toReferenceProject()); - catalogConstraint = columnsAndTable.second.addForeignConstraint(name, columnsAndTable.first, - referencedColumnsAndTable.second, referencedColumnsAndTable.first); + columnsAndTable.second.addForeignConstraint(name, columnsAndTable.first, + referencedColumnsAndTable.second, referencedColumnsAndTable.first, false); } else if (constraint.isPrimaryKey()) { - catalogConstraint = columnsAndTable.second.addPrimaryKeyConstraint(name, columnsAndTable.first); + columnsAndTable.second.addPrimaryKeyConstraint(name, columnsAndTable.first, false); } else if (constraint.isUnique()) { - catalogConstraint = columnsAndTable.second.addUniqueConstraint(name, columnsAndTable.first); + columnsAndTable.second.addUniqueConstraint(name, columnsAndTable.first, false); } - Env.getCurrentEnv().getEditLog().logAddConstraint( - new AlterConstraintLog(catalogConstraint, columnsAndTable.second)); } private Pair<ImmutableList<String>, TableIf> extractColumnsAndTable(ConnectContext ctx, LogicalPlan plan) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java index 84143f234c3..9878b0e9263 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/DropConstraintCommand.java @@ -17,7 +17,6 @@ package org.apache.doris.nereids.trees.plans.commands; -import org.apache.doris.catalog.Env; import org.apache.doris.catalog.TableIf; import org.apache.doris.nereids.NereidsPlanner; import org.apache.doris.nereids.exceptions.AnalysisException; @@ -28,7 +27,6 @@ import org.apache.doris.nereids.trees.plans.commands.ExplainCommand.ExplainLevel import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; -import org.apache.doris.persist.AlterConstraintLog; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.StmtExecutor; @@ -58,8 +56,7 @@ public class DropConstraintCommand extends Command implements ForwardWithSync { @Override public void run(ConnectContext ctx, StmtExecutor executor) throws Exception { TableIf table = extractTable(ctx, plan); - org.apache.doris.catalog.constraint.Constraint catalogConstraint = table.dropConstraint(name); - Env.getCurrentEnv().getEditLog().logDropConstraint(new AlterConstraintLog(catalogConstraint, table)); + table.dropConstraint(name, false); } private TableIf extractTable(ConnectContext ctx, LogicalPlan plan) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java index 7f343f94692..88675d5cca3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java @@ -992,7 +992,7 @@ public class EditLog { } case OperationType.OP_DROP_CONSTRAINT: { final AlterConstraintLog log = (AlterConstraintLog) journal.getData(); - log.getTableIf().dropConstraint(log.getConstraint().getName()); + log.getTableIf().replayDropConstraint(log.getConstraint().getName()); break; } case OperationType.OP_ALTER_USER: { diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/constraint/ConstraintPersistTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/constraint/ConstraintPersistTest.java index 782073d4ac3..07c7abf7ce0 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/catalog/constraint/ConstraintPersistTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/constraint/ConstraintPersistTest.java @@ -24,6 +24,7 @@ import org.apache.doris.catalog.PrimitiveType; import org.apache.doris.catalog.Table; import org.apache.doris.catalog.TableIf; import org.apache.doris.common.Config; +import org.apache.doris.common.Pair; import org.apache.doris.datasource.ExternalTable; import org.apache.doris.datasource.es.EsExternalCatalog; import org.apache.doris.datasource.es.EsExternalDatabase; @@ -53,6 +54,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; class ConstraintPersistTest extends TestWithFeService implements PlanPatternMatchSupported { @@ -144,6 +146,52 @@ class ConstraintPersistTest extends TestWithFeService implements PlanPatternMatc Assertions.assertTrue(tableIf.getConstraintsMap().isEmpty()); } + @Test + void replayDropConstraintLogTest() throws Exception { + Config.edit_log_type = "local"; + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + DataOutput output = new DataOutputStream(outputStream); + List<Pair<Short, AlterConstraintLog>> logs = new CopyOnWriteArrayList<>(); + EditLog editLog = new EditLog(""); + new MockUp<EditLog>() { + @Mock + public void logAddConstraint(AlterConstraintLog log) { + logs.add(Pair.of(OperationType.OP_ADD_CONSTRAINT, log)); + } + + @Mock + public void logDropConstraint(AlterConstraintLog log) { + logs.add(Pair.of(OperationType.OP_DROP_CONSTRAINT, log)); + } + }; + new MockUp<Env>() { + @Mock + public EditLog getEditLog() { + return editLog; + } + }; + addConstraint("alter table t1 add constraint pk primary key (k1)"); + addConstraint("alter table t2 add constraint pk primary key (k1)"); + addConstraint("alter table t1 add constraint uk unique (k1)"); + addConstraint("alter table t1 add constraint fk foreign key (k1) references t2(k1)"); + TableIf tableIf = RelationUtil.getTable( + RelationUtil.getQualifierName(connectContext, Lists.newArrayList("test", "t1")), + connectContext.getEnv()); + Assertions.assertEquals(3, tableIf.getConstraintsMap().size()); + dropConstraint("alter table t1 drop constraint uk"); + dropConstraint("alter table t1 drop constraint pk"); + dropConstraint("alter table t2 drop constraint pk"); + Assertions.assertEquals(0, tableIf.getConstraintsMap().size()); + for (Pair<Short, AlterConstraintLog> log : logs) { + JournalEntity journalEntity = new JournalEntity(); + journalEntity.setData(log.second); + journalEntity.setOpCode(log.first); + journalEntity.write(output); + } + Assertions.assertEquals(0, tableIf.getConstraintsMap().size()); + Assertions.assertEquals(0, tableIf.getConstraintsMap().size()); + } + @Test void constraintWithTablePersistTest() throws Exception { addConstraint("alter table t1 add constraint pk primary key (k1)"); @@ -169,8 +217,11 @@ class ConstraintPersistTest extends TestWithFeService implements PlanPatternMatc @Test void externalTableTest() throws Exception { ExternalTable externalTable = new ExternalTable(); - externalTable.addPrimaryKeyConstraint("pk", ImmutableList.of("col")); - + try { + externalTable.addPrimaryKeyConstraint("pk", ImmutableList.of("col"), false); + } catch (Exception ignore) { + // ignore + } ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutput output = new DataOutputStream(outputStream); externalTable.write(output); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org