]> source.dussan.org Git - sonarqube.git/commitdiff
Make drop of db table re-entrant
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Sat, 12 May 2018 20:51:32 +0000 (22:51 +0200)
committerSonarTech <sonartech@sonarsource.com>
Mon, 14 May 2018 18:20:48 +0000 (20:20 +0200)
That allows to speed-up Oracle migrations by removing the call
to DatabaseUtils.tableExists(), which is super slow if many tables
are accessible to the JDBC user.

Signed-off-by: Simon Brandhof <simon.brandhof@sonarsource.com>
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/DropTableBuilder.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v62/DropIssueFiltersTables.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v62/DropMeasureFiltersTables.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v62/DropRelatedDashboardTables.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropLoadedTemplatesTable.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v71/DropTableProjectLinks.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/sql/DropTableBuilderTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v63/DropTableResourceIndexTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/DropTableAuthorsTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v71/DropTableProjectLinksTest.java

index eea230b89df3d8fa00ef3d4eb4e4b619a8b0b204..d145551368dc576eb8eee50ade0eebefee5a8787 100644 (file)
@@ -21,7 +21,11 @@ package org.sonar.server.platform.db.migration.sql;
 
 import java.util.List;
 import org.sonar.db.dialect.Dialect;
+import org.sonar.db.dialect.H2;
+import org.sonar.db.dialect.MsSql;
+import org.sonar.db.dialect.MySql;
 import org.sonar.db.dialect.Oracle;
+import org.sonar.db.dialect.PostgreSql;
 
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
@@ -39,41 +43,36 @@ public class DropTableBuilder {
   }
 
   public List<String> build() {
-    if (Oracle.ID.equals(dialect.getId())) {
-      return dropOracleSequenceAndTriggerAndTableStatements();
+    switch (dialect.getId()) {
+      case Oracle.ID:
+        return forOracle(tableName);
+      case H2.ID:
+      case MySql.ID:
+      case PostgreSql.ID:
+        return singletonList("drop table if exists " + tableName);
+      case MsSql.ID:
+        // "if exists" is supported only since MSSQL 2016.
+        return singletonList("drop table " + tableName);
+      default:
+        throw new IllegalStateException("Unsupported DB: " + dialect.getId());
     }
-    return singletonList(dropTableStatement());
   }
 
-  private String dropTableStatement() {
-    return "DROP TABLE " + tableName;
+  private static List<String> forOracle(String tableName) {
+    return asList(
+      dropIfExistsOnOracle("DROP SEQUENCE " + tableName + "_seq", -2289),
+      dropIfExistsOnOracle("DROP TRIGGER " + tableName + "_idt", -4080),
+      dropIfExistsOnOracle("DROP TABLE " + tableName, -942));
   }
 
-  private List<String> dropOracleSequenceAndTriggerAndTableStatements() {
-    return asList(dropSequenceFor(tableName), dropTriggerFor(tableName), dropTableStatement());
-  }
-
-  private static String dropSequenceFor(String tableName) {
+  private static String dropIfExistsOnOracle(String command, int codeIfNotExists) {
     return "BEGIN\n" +
-      "  EXECUTE IMMEDIATE 'DROP SEQUENCE " + tableName + "_seq';\n" +
+      "EXECUTE IMMEDIATE '" + command + "';\n" +
       "EXCEPTION\n" +
-      "  WHEN OTHERS THEN\n" +
-      "    IF SQLCODE != -2289 THEN\n" +
-      "      RAISE;\n" +
-      "    END IF;\n" +
+      "WHEN OTHERS THEN\n" +
+      "  IF SQLCODE != " + codeIfNotExists + " THEN\n" +
+      "  RAISE;\n" +
+      "  END IF;\n" +
       "END;";
   }
-
-  private static String dropTriggerFor(String tableName) {
-    return "BEGIN\n" +
-      "  EXECUTE IMMEDIATE 'DROP TRIGGER " + tableName + "_idt';\n" +
-      "EXCEPTION\n" +
-      "  WHEN OTHERS THEN\n" +
-      "    IF SQLCODE != -4080 THEN\n" +
-      "      RAISE;\n" +
-      "    END IF;\n" +
-      "END;";
-
-  }
-
 }
index 3cdc5c0ff114d93834e2f5e934d5471e81ef8102..6bbdf31d2999c7186c28fb38949c5fc6eb959beb 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v62;
 
-import com.google.common.collect.ImmutableList;
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.List;
-import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.db.Database;
-import org.sonar.db.DatabaseUtils;
 import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
 import org.sonar.server.platform.db.migration.step.DdlChange;
 
+import static java.util.Arrays.asList;
 import static org.sonar.core.util.stream.MoreCollectors.toList;
 
 public class DropIssueFiltersTables extends DdlChange {
 
-  private static final Logger LOGGER = Loggers.get(DropIssueFiltersTables.class);
-
-  private static final List<String> TABLES_TO_DROP = ImmutableList.of("issue_filters", "issue_filter_favourites");
-
-  private final Database db;
-
   public DropIssueFiltersTables(Database db) {
     super(db);
-    this.db = db;
   }
 
   @Override
   public void execute(Context context) throws SQLException {
-    List<String> tablesToDrop = getEffectiveTablesToDrop();
-    LOGGER.info("Removing tables {}", tablesToDrop);
-    context.execute(tablesToDrop
+    List<String> tables = asList("issue_filters", "issue_filter_favourites");
+    Loggers.get(getClass()).info("Removing tables {}", tables);
+    context.execute(tables
       .stream()
-      .flatMap(table -> new DropTableBuilder(db.getDialect(), table).build().stream())
+      .flatMap(table -> new DropTableBuilder(getDialect(), table).build().stream())
       .collect(toList()));
   }
-
-  private List<String> getEffectiveTablesToDrop() throws SQLException {
-    try (Connection connection = db.getDataSource().getConnection()) {
-      return TABLES_TO_DROP.stream()
-        .filter(table -> DatabaseUtils.tableExists(table, connection))
-        .collect(toList());
-    }
-  }
 }
index fc95556544dcdc6ac625a738d07f96499d8e408a..4aa4066e84ea500e19742ee0e1dcfcc4a300076b 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v62;
 
-import com.google.common.collect.ImmutableList;
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.List;
-import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.db.Database;
-import org.sonar.db.DatabaseUtils;
 import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
 import org.sonar.server.platform.db.migration.step.DdlChange;
 
+import static java.util.Arrays.asList;
 import static org.sonar.core.util.stream.MoreCollectors.toList;
 
 public class DropMeasureFiltersTables extends DdlChange {
 
-  private static final Logger LOGGER = Loggers.get(DropMeasureFiltersTables.class);
-
-  private static final List<String> TABLES_TO_DROP = ImmutableList.of("measure_filters", "measure_filter_favourites");
-
-  private final Database db;
-
   public DropMeasureFiltersTables(Database db) {
     super(db);
-    this.db = db;
   }
 
   @Override
   public void execute(Context context) throws SQLException {
-    List<String> tablesToDrop = getEffectiveTablesToDrop();
-    LOGGER.info("Removing tables {}", tablesToDrop);
-    context.execute(tablesToDrop
+    List<String> tables = asList("measure_filters", "measure_filter_favourites");
+    Loggers.get(getClass()).info("Removing tables {}", tables);
+    context.execute(tables
       .stream()
-      .flatMap(table -> new DropTableBuilder(db.getDialect(), table).build().stream())
+      .flatMap(table -> new DropTableBuilder(getDialect(), table).build().stream())
       .collect(toList()));
   }
-
-  private List<String> getEffectiveTablesToDrop() throws SQLException {
-    try (Connection connection = db.getDataSource().getConnection()) {
-      return TABLES_TO_DROP.stream()
-        .filter(table -> DatabaseUtils.tableExists(table, connection))
-        .collect(toList());
-    }
-  }
 }
index 411588e26b8f86d69770a45db8082742d1134438..1f1449f095155ac1f30ae851e1b1eb6a3605cdb2 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v62;
 
-import com.google.common.collect.ImmutableList;
-import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.List;
-import org.sonar.api.utils.log.Logger;
 import org.sonar.api.utils.log.Loggers;
 import org.sonar.db.Database;
-import org.sonar.db.DatabaseUtils;
 import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
 import org.sonar.server.platform.db.migration.step.DdlChange;
 
+import static java.util.Arrays.asList;
 import static org.sonar.core.util.stream.MoreCollectors.toList;
 
 public class DropRelatedDashboardTables extends DdlChange {
 
-  private static final Logger LOGGER = Loggers.get(DropRelatedDashboardTables.class);
-
-  private static final List<String> TABLES_TO_DROP = ImmutableList.of("widget_properties", "widgets", "active_dashboards", "dashboards");
-
-  private final Database db;
-
   public DropRelatedDashboardTables(Database db) {
     super(db);
-    this.db = db;
   }
 
   @Override
   public void execute(Context context) throws SQLException {
-    List<String> tablesToDrop = getEffectiveTablesToDrop();
-    LOGGER.info("Removing tables {}", tablesToDrop);
+    List<String> tablesToDrop = asList("widget_properties", "widgets", "active_dashboards", "dashboards");
+    Loggers.get(getClass()).info("Removing tables {}", tablesToDrop);
     context.execute(tablesToDrop
       .stream()
-      .flatMap(table -> new DropTableBuilder(db.getDialect(), table).build().stream())
+      .flatMap(table -> new DropTableBuilder(getDialect(), table).build().stream())
       .collect(toList()));
   }
 
-  private List<String> getEffectiveTablesToDrop() throws SQLException {
-    try (Connection connection = db.getDataSource().getConnection()) {
-      return TABLES_TO_DROP.stream()
-        .filter(table -> DatabaseUtils.tableExists(table, connection))
-        .collect(toList());
-    }
-  }
 }
index c1bc01f194428f951f5c68238899cb157fbc8e60..87fe876d319779ec0b4a661aa3c92e0b8bc60add 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v70;
 
-import java.sql.Connection;
 import java.sql.SQLException;
 import org.sonar.db.Database;
-import org.sonar.db.DatabaseUtils;
 import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
 import org.sonar.server.platform.db.migration.step.DdlChange;
 
 public class DropLoadedTemplatesTable extends DdlChange {
 
-  private static final String LOADED_TEMPLATES = "loaded_templates";
-  private final Database db;
-
   public DropLoadedTemplatesTable(Database db) {
     super(db);
-    this.db = db;
   }
 
   @Override
   public void execute(Context context) throws SQLException {
-    if (tableExists()) {
-      context.execute(new DropTableBuilder(db.getDialect(), LOADED_TEMPLATES).build());
-    }
-  }
-
-  private boolean tableExists() throws SQLException {
-    try (Connection connection = db.getDataSource().getConnection()) {
-      return DatabaseUtils.tableExists(LOADED_TEMPLATES, connection);
-    }
+    context.execute(new DropTableBuilder(getDialect(), "loaded_templates").build());
   }
 }
index ca2950b8bdbb7168d4bd26d9c1332ae56961de09..b5105e15e7809194307712d0dd12c28a6d16c80d 100644 (file)
@@ -26,15 +26,13 @@ import org.sonar.server.platform.db.migration.step.DdlChange;
 
 public class DropTableProjectLinks extends DdlChange {
 
-  private static final String TABLE_NAME = "project_links";
-
   public DropTableProjectLinks(Database db) {
     super(db);
   }
 
   @Override
   public void execute(Context context) throws SQLException {
-    context.execute(new DropTableBuilder(getDialect(), TABLE_NAME).build());
+    context.execute(new DropTableBuilder(getDialect(), "project_links").build());
   }
 
 }
index 34351b5791f1b2fefe5b301c3e85008c16b83c08..4bbd9e89e336062f0e5a39b4fae5fd9d1f0bf1f4 100644 (file)
@@ -38,25 +38,25 @@ public class DropTableBuilderTest {
   @Test
   public void drop_tables_on_mysql() {
     assertThat(new DropTableBuilder(new MySql(), "issues")
-      .build()).containsOnly("DROP TABLE issues");
+      .build()).containsOnly("drop table if exists issues");
   }
 
   @Test
   public void drop_tables_on_postgresql() {
     assertThat(new DropTableBuilder(new PostgreSql(), "issues")
-      .build()).containsOnly("DROP TABLE issues");
+      .build()).containsOnly("drop table if exists issues");
   }
 
   @Test
   public void drop_tables_on_mssql() {
     assertThat(new DropTableBuilder(new MsSql(), "issues")
-      .build()).containsOnly("DROP TABLE issues");
+      .build()).containsOnly("drop table issues");
   }
 
   @Test
   public void drop_tables_on_h2() {
     assertThat(new DropTableBuilder(new H2(), "issues")
-      .build()).containsOnly("DROP TABLE issues");
+      .build()).containsOnly("drop table if exists issues");
   }
 
   @Test
@@ -64,22 +64,29 @@ public class DropTableBuilderTest {
     assertThat(new DropTableBuilder(new Oracle(), "issues")
       .build()).containsExactly(
         "BEGIN\n" +
-          "  EXECUTE IMMEDIATE 'DROP SEQUENCE issues_seq';\n" +
+          "EXECUTE IMMEDIATE 'DROP SEQUENCE issues_seq';\n" +
           "EXCEPTION\n" +
-          "  WHEN OTHERS THEN\n" +
-          "    IF SQLCODE != -2289 THEN\n" +
-          "      RAISE;\n" +
-          "    END IF;\n" +
+          "WHEN OTHERS THEN\n" +
+          "  IF SQLCODE != -2289 THEN\n" +
+          "  RAISE;\n" +
+          "  END IF;\n" +
           "END;",
         "BEGIN\n" +
-          "  EXECUTE IMMEDIATE 'DROP TRIGGER issues_idt';\n" +
+          "EXECUTE IMMEDIATE 'DROP TRIGGER issues_idt';\n" +
           "EXCEPTION\n" +
-          "  WHEN OTHERS THEN\n" +
-          "    IF SQLCODE != -4080 THEN\n" +
-          "      RAISE;\n" +
-          "    END IF;\n" +
+          "WHEN OTHERS THEN\n" +
+          "  IF SQLCODE != -4080 THEN\n" +
+          "  RAISE;\n" +
+          "  END IF;\n" +
           "END;",
-        "DROP TABLE issues");
+        "BEGIN\n" +
+          "EXECUTE IMMEDIATE 'DROP TABLE issues';\n" +
+          "EXCEPTION\n" +
+          "WHEN OTHERS THEN\n" +
+          "  IF SQLCODE != -942 THEN\n" +
+          "  RAISE;\n" +
+          "  END IF;\n" +
+          "END;");
   }
 
   @Test
index 35f345d0cdac7830c011fe8c50066541468d66f3..e0602f3a74004f85611dfb4d6a9edf4e18f9de5c 100644 (file)
@@ -22,15 +22,10 @@ package org.sonar.server.platform.db.migration.version.v63;
 import java.sql.SQLException;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.utils.System2;
 import org.sonar.db.CoreDbTester;
 
 public class DropTableResourceIndexTest {
 
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
-
   @Rule
   public CoreDbTester db = CoreDbTester.createForSchema(DropTableResourceIndexTest.class, "schema.sql");
 
@@ -44,10 +39,10 @@ public class DropTableResourceIndexTest {
   }
 
   @Test
-  public void migration_is_not_re_entrant() throws Exception {
+  public void migration_is_reentrant() throws Exception {
     underTest.execute();
-
-    expectedException.expect(IllegalStateException.class);
     underTest.execute();
+
+    db.assertTableDoesNotExist("resource_index");
   }
 }
index 1963afa8018edff05c8aacbf6b1caeae24b3acd3..130f9c40905fdf7d298af9086729c7cfb6211f1b 100644 (file)
@@ -22,14 +22,11 @@ package org.sonar.server.platform.db.migration.version.v65;
 import java.sql.SQLException;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.sonar.db.CoreDbTester;
 
 public class DropTableAuthorsTest {
   @Rule
   public CoreDbTester db = CoreDbTester.createForSchema(DropTableAuthorsTest.class, "authors.sql");
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
 
   private DropTableAuthors underTest = new DropTableAuthors(db.database());
 
@@ -42,12 +39,11 @@ public class DropTableAuthorsTest {
   }
 
   @Test
-  public void execute_is_not_reentrant() throws Exception {
+  public void execute_is_reentrant() throws Exception {
     underTest.execute();
-
-    expectedException.expect(IllegalStateException.class);
-    
     underTest.execute();
+
+    db.assertTableDoesNotExist("authors");
   }
 
 }
index 09e78e36aa19e6b19903f7a9e53e97893b42dea7..2d51ff7ae9e29531211c8f7ac1e3238b5adf9d26 100644 (file)
@@ -23,15 +23,12 @@ package org.sonar.server.platform.db.migration.version.v71;
 import java.sql.SQLException;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.sonar.db.CoreDbTester;
 
 public class DropTableProjectLinksTest {
 
   @Rule
   public final CoreDbTester dbTester = CoreDbTester.createForSchema(DropTableProjectLinksTest.class, "project_links.sql");
-  @Rule
-  public ExpectedException expectedException = ExpectedException.none();
 
   private DropTableProjectLinks underTest = new DropTableProjectLinks(dbTester.database());
 
@@ -43,12 +40,11 @@ public class DropTableProjectLinksTest {
   }
 
   @Test
-  public void migration_is_not_reentrant() throws SQLException {
+  public void migration_is_reentrant() throws SQLException {
     underTest.execute();
-
-    expectedException.expect(IllegalStateException.class);
-
     underTest.execute();
+
+    dbTester.assertTableDoesNotExist("project_links");
   }
 
 }