Skip to content

Commit 2cccd8f

Browse files
author
Marcus Sorensen
authored
db: Add index on cluster_details.name for FirstFitPlanner speedup (#7922)
1 parent 439d70f commit 2cccd8f

4 files changed

Lines changed: 102 additions & 1 deletion

File tree

engine/schema/src/main/java/com/cloud/upgrade/dao/DatabaseAccessObject.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.sql.Connection;
2020
import java.sql.PreparedStatement;
21+
import java.sql.ResultSet;
2122
import java.sql.SQLException;
2223

2324
import org.apache.log4j.Logger;
@@ -84,6 +85,33 @@ public boolean columnExists(Connection conn, String tableName, String columnName
8485
return columnExists;
8586
}
8687

88+
public String generateIndexName(String tableName, String columnName) {
89+
return String.format("i_%s__%s", tableName, columnName);
90+
}
91+
92+
public boolean indexExists(Connection conn, String tableName, String indexName) {
93+
try (PreparedStatement pstmt = conn.prepareStatement(String.format("SHOW INDEXES FROM %s where Key_name = \"%s\"", tableName, indexName))) {
94+
ResultSet result = pstmt.executeQuery();
95+
if (result.next()) {
96+
return true;
97+
}
98+
} catch (SQLException e) {
99+
s_logger.debug(String.format("Index %s doesn't exist, ignoring exception:", indexName, e.getMessage()));
100+
}
101+
return false;
102+
}
103+
104+
public void createIndex(Connection conn, String tableName, String columnName, String indexName) {
105+
String stmt = String.format("CREATE INDEX %s on %s (%s)", indexName, tableName, columnName);
106+
s_logger.debug("Statement: " + stmt);
107+
try (PreparedStatement pstmt = conn.prepareStatement(stmt)) {
108+
pstmt.execute();
109+
s_logger.debug(String.format("Created index %s", indexName));
110+
} catch (SQLException e) {
111+
s_logger.warn(String.format("Unable to create index %s", indexName), e);
112+
}
113+
}
114+
87115
protected static void closePreparedStatement(PreparedStatement pstmt, String errorMessage) {
88116
try {
89117
if (pstmt != null) {
@@ -93,5 +121,4 @@ protected static void closePreparedStatement(PreparedStatement pstmt, String err
93121
s_logger.warn(errorMessage, e);
94122
}
95123
}
96-
97124
}

engine/schema/src/main/java/com/cloud/upgrade/dao/DbUpgradeUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ public class DbUpgradeUtils {
2323

2424
private static DatabaseAccessObject dao = new DatabaseAccessObject();
2525

26+
public static void addIndexIfNeeded(Connection conn, String tableName, String columnName) {
27+
String indexName = dao.generateIndexName(tableName, columnName);
28+
29+
if (!dao.indexExists(conn, tableName, indexName)) {
30+
dao.createIndex(conn, tableName, columnName, indexName);
31+
}
32+
}
33+
2634
public static void addForeignKey(Connection conn, String tableName, String tableColumn, String foreignTableName, String foreignColumnName) {
2735
dao.addForeignKey(conn, tableName, tableColumn, foreignTableName, foreignColumnName);
2836
}

engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41800to41810.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public void performDataMigration(Connection conn) {
6969
copyGuestOsMappingsToVMware80u1();
7070
addForeignKeyToAutoscaleVmprofiles(conn);
7171
mergeDuplicateGuestOSes();
72+
addIndexes(conn);
7273
}
7374

7475
private void mergeDuplicateGuestOSes() {
@@ -242,4 +243,8 @@ private void fixForeignKeyNames(Connection conn) {
242243
private void addForeignKeyToAutoscaleVmprofiles(Connection conn) {
243244
DbUpgradeUtils.addForeignKey(conn, "autoscale_vmprofiles", "user_data_id", "user_data", "id");
244245
}
246+
247+
private void addIndexes(Connection conn) {
248+
DbUpgradeUtils.addIndexIfNeeded(conn, "cluster_details", "name");
249+
}
245250
}

engine/schema/src/test/java/com/cloud/upgrade/dao/DatabaseAccessObjectTest.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package com.cloud.upgrade.dao;
1818

19+
import static org.mockito.Matchers.startsWith;
1920
import static org.mockito.Matchers.any;
2021
import static org.mockito.Matchers.anyString;
2122
import static org.mockito.Matchers.contains;
@@ -27,9 +28,11 @@
2728

2829
import java.sql.Connection;
2930
import java.sql.PreparedStatement;
31+
import java.sql.ResultSet;
3032
import java.sql.SQLException;
3133

3234
import org.apache.log4j.Logger;
35+
import org.junit.Assert;
3336
import org.junit.Before;
3437
import org.junit.Test;
3538
import org.junit.runner.RunWith;
@@ -49,6 +52,9 @@ public class DatabaseAccessObjectTest {
4952
@Mock
5053
private Logger loggerMock;
5154

55+
@Mock
56+
private ResultSet resultSetMock;
57+
5258
private final DatabaseAccessObject dao = new DatabaseAccessObject();
5359

5460
@Before
@@ -83,6 +89,61 @@ public void testDropKeyWhenConnectionIsNull() throws Exception {
8389
dao.dropKey(conn, tableName, key, isForeignKey);
8490
}
8591

92+
@Test
93+
public void generateIndexNameTest() {
94+
String indexName = dao.generateIndexName("mytable","mycolumn");
95+
Assert.assertEquals( "i_mytable__mycolumn", indexName);
96+
}
97+
98+
@Test
99+
public void indexExistsFalseTest() throws Exception {
100+
when(resultSetMock.next()).thenReturn(false);
101+
when(connectionMock.prepareStatement(startsWith("SHOW INDEXES FROM"))).thenReturn(preparedStatementMock);
102+
when(preparedStatementMock.executeQuery()).thenReturn(resultSetMock);
103+
104+
Connection conn = connectionMock;
105+
String tableName = "mytable";
106+
String indexName = "myindex";
107+
108+
Assert.assertFalse(dao.indexExists(conn, tableName, indexName));
109+
verify(connectionMock, times(1)).prepareStatement(anyString());
110+
verify(preparedStatementMock, times(1)).executeQuery();
111+
verify(preparedStatementMock, times(1)).close();
112+
}
113+
114+
@Test
115+
public void indexExistsTrueTest() throws Exception {
116+
when(resultSetMock.next()).thenReturn(true);
117+
when(connectionMock.prepareStatement(startsWith("SHOW INDEXES FROM"))).thenReturn(preparedStatementMock);
118+
when(preparedStatementMock.executeQuery()).thenReturn(resultSetMock);
119+
120+
Connection conn = connectionMock;
121+
String tableName = "mytable";
122+
String indexName = "myindex";
123+
124+
Assert.assertTrue(dao.indexExists(conn, tableName, indexName));
125+
verify(connectionMock, times(1)).prepareStatement(anyString());
126+
verify(preparedStatementMock, times(1)).executeQuery();
127+
verify(preparedStatementMock, times(1)).close();
128+
}
129+
130+
@Test
131+
public void createIndexTest() throws Exception {
132+
when(connectionMock.prepareStatement(startsWith("CREATE INDEX"))).thenReturn(preparedStatementMock);
133+
when(preparedStatementMock.execute()).thenReturn(true);
134+
135+
Connection conn = connectionMock;
136+
String tableName = "mytable";
137+
String columnName = "mycolumn";
138+
String indexName = "myindex";
139+
140+
dao.createIndex(conn, tableName, columnName, indexName);
141+
verify(connectionMock, times(1)).prepareStatement(anyString());
142+
verify(preparedStatementMock, times(1)).execute();
143+
verify(preparedStatementMock, times(1)).close();
144+
verify(loggerMock, times(1)).debug("Created index myindex");
145+
}
146+
86147
@Test
87148
public void testDropKeyWhenTableNameIsNull() throws Exception {
88149
SQLException sqlException = new SQLException();

0 commit comments

Comments
 (0)