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

Reply via email to