http://git-wip-us.apache.org/repos/asf/phoenix/blob/15a54d55/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
----------------------------------------------------------------------
diff --git
a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
index 9b744e1..b5945d0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
@@ -36,15 +36,19 @@ import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.INDEX_DISABLE_TIME
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.INDEX_STATE;
import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_VIEW_REFERENCED;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.KEY_SEQ;
+import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LAST_STATS_UPDATE_TIME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MULTI_TENANT;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.NULLABLE;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ORDINAL_POSITION;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PHYSICAL_NAME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PK_NAME;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.REGION_NAME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SORT_ORDER;
import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA;
import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE;
+import static
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_STATS_TABLE;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SEQ_NUM;
@@ -59,8 +63,10 @@ import static
org.apache.phoenix.query.QueryServicesOptions.DEFAULT_DROP_METADAT
import static org.apache.phoenix.schema.PDataType.VARCHAR;
import java.io.IOException;
+import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
+import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
@@ -113,6 +119,8 @@ import org.apache.phoenix.parse.NamedTableNode;
import org.apache.phoenix.parse.ParseNodeFactory;
import org.apache.phoenix.parse.PrimaryKeyConstraint;
import org.apache.phoenix.parse.TableName;
+import org.apache.phoenix.parse.UpdateStatisticsStatement;
+import org.apache.phoenix.query.KeyRange;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.query.QueryServices;
import org.apache.phoenix.query.QueryServicesOptions;
@@ -122,6 +130,7 @@ import org.apache.phoenix.util.ByteUtil;
import org.apache.phoenix.util.IndexUtil;
import org.apache.phoenix.util.MetaDataUtil;
import org.apache.phoenix.util.PhoenixRuntime;
+import org.apache.phoenix.util.ScanUtil;
import org.apache.phoenix.util.SchemaUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -450,6 +459,55 @@ public class MetaDataClient {
return connection.getQueryServices().updateData(plan);
}
+ public MutationState updateStatistics(UpdateStatisticsStatement
updateStatisticsStmt) throws SQLException {
+ // Check before updating the stats if we have reached the configured
time to reupdate the stats once again
+ long minTimeForStatsUpdate = connection.getQueryServices().getProps()
+ .getLong(QueryServices.STATS_UPDATE_FREQ_MS_ATTRIB,
QueryServicesOptions.DEFAULT_STATS_UPDATE_FREQ_MS);
+ ColumnResolver resolver =
FromCompiler.getResolver(updateStatisticsStmt, connection);
+ PTable table = resolver.getTables().get(0).getTable();
+ PName physicalName = table.getPhysicalName();
+ byte[] tenantIdBytes = ByteUtil.EMPTY_BYTE_ARRAY;
+ KeyRange analyzeRange = KeyRange.EVERYTHING_RANGE;
+ if (connection.getTenantId() != null && table.isMultiTenant()) {
+ tenantIdBytes = connection.getTenantId().getBytes();
+ // TODO remove this inner if once PHOENIX-1259 is fixed.
+ if (table.getBucketNum() == null) {
+ List<List<KeyRange>> tenantIdKeyRanges =
Collections.singletonList(Collections.singletonList(KeyRange
+ .getKeyRange(tenantIdBytes)));
+ byte[] lowerRange =
ScanUtil.getMinKey(table.getRowKeySchema(), tenantIdKeyRanges,
+ ScanUtil.SINGLE_COLUMN_SLOT_SPAN);
+ byte[] upperRange =
ScanUtil.getMaxKey(table.getRowKeySchema(), tenantIdKeyRanges,
+ ScanUtil.SINGLE_COLUMN_SLOT_SPAN);
+ analyzeRange = KeyRange.getKeyRange(lowerRange, upperRange);
+ }
+ }
+ Long scn = connection.getSCN();
+ // Always invalidate the cache
+ long clientTS = connection.getSCN() == null ?
HConstants.LATEST_TIMESTAMP : scn;
+ connection.getQueryServices().clearCacheForTable(tenantIdBytes,
table.getSchemaName().getBytes(),
+ table.getTableName().getBytes(), clientTS);
+ // Clear the cache also. So that for cases like major compaction also
we would be able to use the stats
+ updateCache(table.getSchemaName().getString(),
table.getTableName().getString(), true);
+ String query = "SELECT CURRENT_DATE(),"+ LAST_STATS_UPDATE_TIME + "
FROM " + SYSTEM_CATALOG_SCHEMA
+ + "." + SYSTEM_STATS_TABLE + " WHERE " + PHYSICAL_NAME + "='"
+ physicalName.getString() + "' AND " + COLUMN_FAMILY
+ + " IS NULL AND " + REGION_NAME + " IS NULL";
+ ResultSet rs = connection.createStatement().executeQuery(query);
+ long lastUpdatedTime = 0;
+ if (rs.next() && rs.getDate(2) != null) {
+ lastUpdatedTime = rs.getDate(1).getTime() -
rs.getDate(2).getTime();
+ }
+ if (minTimeForStatsUpdate > lastUpdatedTime) {
+ // We need to update the stats table
+ connection.getQueryServices().updateStatistics(analyzeRange,
physicalName.getBytes());
+ connection.getQueryServices().clearCacheForTable(tenantIdBytes,
table.getSchemaName().getBytes(),
+ table.getTableName().getBytes(), clientTS);
+ updateCache(table.getSchemaName().getString(),
table.getTableName().getString(), true);
+ return new MutationState(1, connection);
+ } else {
+ return new MutationState(0, connection);
+ }
+ }
+
private MutationState buildIndexAtTimeStamp(PTable index, NamedTableNode
dataTableNode) throws SQLException {
// If our connection is at a fixed point-in-time, we need to open a new
// connection so that our new index table is visible.
@@ -1320,7 +1378,8 @@ public class MetaDataClient {
return dropTable(schemaName, tableName, parentTableName,
PTableType.INDEX, statement.ifExists(), false);
}
- private MutationState dropTable(String schemaName, String tableName,
String parentTableName, PTableType tableType, boolean ifExists, boolean
cascade) throws SQLException {
+ private MutationState dropTable(String schemaName, String tableName,
String parentTableName, PTableType tableType,
+ boolean ifExists, boolean cascade) throws SQLException {
connection.rollback();
boolean wasAutoCommit = connection.getAutoCommit();
try {
@@ -1385,6 +1444,7 @@ public class MetaDataClient {
for (PTable index: table.getIndexes()) {
tableRefs.add(new TableRef(null, index, ts,
false));
}
+ deleteFromStatsTable(tableRefs, ts);
MutationPlan plan = new
PostDDLCompiler(connection).compile(tableRefs, null, null,
Collections.<PColumn>emptyList(), ts);
return
connection.getQueryServices().updateData(plan);
}
@@ -1396,6 +1456,41 @@ public class MetaDataClient {
connection.setAutoCommit(wasAutoCommit);
}
}
+
+ private void deleteFromStatsTable(List<TableRef> tableRefs, long ts)
throws SQLException {
+ Properties props = new Properties(connection.getClientInfo());
+ props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB,
Long.toString(ts));
+ Connection conn = DriverManager.getConnection(connection.getURL(),
props);
+ conn.setAutoCommit(true);
+ boolean success = false;
+ SQLException sqlException = null;
+ try {
+ StringBuilder buf = new StringBuilder("DELETE FROM SYSTEM.STATS
WHERE PHYSICAL_NAME IN (");
+ for (TableRef ref : tableRefs) {
+ buf.append("'" + ref.getTable().getName().getString() + "',");
+ }
+ buf.setCharAt(buf.length() - 1, ')');
+ conn.createStatement().execute(buf.toString());
+ success = true;
+ } catch (SQLException e) {
+ sqlException = e;
+ } finally {
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ if (sqlException == null) {
+ // If we're not in the middle of throwing another exception
+ // then throw the exception we got on close.
+ if (success) {
+ sqlException = e;
+ }
+ } else {
+ sqlException.setNextException(e);
+ }
+ }
+ if (sqlException != null) { throw sqlException; }
+ }
+ }
private MutationCode processMutationResult(String schemaName, String
tableName, MetaDataMutationResult result) throws SQLException {
final MutationCode mutationCode = result.getMutationCode();