PHOENIX-2707 Differentiate between a table+family have zero guideposts from not having collected guideposts
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/c25f8879 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/c25f8879 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/c25f8879 Branch: refs/heads/calcite Commit: c25f88791c86cd65ea21810406eec199403d78aa Parents: dbc9ee9 Author: James Taylor <jtay...@salesforce.com> Authored: Tue Feb 23 14:53:11 2016 -0800 Committer: James Taylor <jtay...@salesforce.com> Committed: Tue Feb 23 14:53:11 2016 -0800 ---------------------------------------------------------------------- .../org/apache/phoenix/end2end/IndexToolIT.java | 3 +- .../phoenix/end2end/MutableIndexToolIT.java | 1 + .../end2end/StatsCollectionDisabledIT.java | 21 ++- .../phoenix/end2end/StatsCollectorIT.java | 57 +++++++- .../phoenix/iterate/BaseResultIterators.java | 140 +++++++++++-------- .../apache/phoenix/query/QueryConstants.java | 2 +- .../org/apache/phoenix/query/QueryServices.java | 1 + .../phoenix/query/QueryServicesOptions.java | 7 + .../stats/DefaultStatisticsCollector.java | 33 ++--- .../phoenix/schema/stats/GuidePostsInfo.java | 2 +- .../schema/stats/GuidePostsInfoBuilder.java | 6 - .../phoenix/schema/stats/PTableStatsImpl.java | 5 +- .../phoenix/schema/stats/StatisticsUtil.java | 23 +-- .../phoenix/schema/stats/StatisticsWriter.java | 60 ++++---- .../apache/phoenix/util/PrefixByteCodec.java | 37 ++--- .../phoenix/query/QueryServicesTestImpl.java | 2 + 16 files changed, 246 insertions(+), 154 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java index aba9c11..fe95470 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/IndexToolIT.java @@ -108,7 +108,8 @@ public class IndexToolIT extends BaseOwnClusterHBaseManagedTimeIT { final String fullTableName = SchemaUtil.getTableName(schemaName, dataTable); final String indxTable = String.format("%s_%s", dataTable, "INDX"); Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); - props.setProperty(QueryServices.TRANSACTIONS_ENABLED, "true"); + props.setProperty(QueryServices.TRANSACTIONS_ENABLED, Boolean.TRUE.toString()); + props.setProperty(QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, Boolean.FALSE.toString()); Connection conn = DriverManager.getConnection(getUrl(), props); Statement stmt = conn.createStatement(); try { http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java index 0791479..8125007 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/MutableIndexToolIT.java @@ -61,6 +61,7 @@ public class MutableIndexToolIT extends BaseOwnClusterHBaseManagedTimeIT { final String dataTable = "DATA_TABLE5"; final String indxTable = String.format("%s_%s",dataTable,"INDX"); Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + props.setProperty(QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, Boolean.FALSE.toString()); Connection conn = DriverManager.getConnection(getUrl(), props); Statement stmt = conn.createStatement(); try { http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectionDisabledIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectionDisabledIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectionDisabledIT.java index a92a665..54ffa7c 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectionDisabledIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectionDisabledIT.java @@ -17,24 +17,26 @@ */ package org.apache.phoenix.end2end; +import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + import java.sql.Connection; import java.sql.DriverManager; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Map; import java.util.Properties; -import com.google.common.collect.Maps; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.util.PropertiesUtil; +import org.apache.phoenix.util.QueryUtil; import org.apache.phoenix.util.ReadOnlyProps; import org.junit.BeforeClass; import org.junit.Test; -import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; -import static org.junit.Assert.assertFalse; +import com.google.common.collect.Maps; /** * Verifies that statistics are not collected if they are disabled via a setting @@ -43,10 +45,12 @@ public class StatsCollectionDisabledIT extends StatsCollectorAbstractIT { @BeforeClass public static void doSetup() throws Exception { - Map<String,String> props = Maps.newHashMapWithExpectedSize(3); + Map<String,String> props = Maps.newHashMapWithExpectedSize(5); // Must update config before starting server props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Long.toString(20)); props.put(QueryServices.STATS_ENABLED_ATTRIB, Boolean.toString(false)); + props.put(QueryServices.EXPLAIN_CHUNK_COUNT_ATTRIB, Boolean.TRUE.toString()); + props.put(QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, Boolean.TRUE.toString()); setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator())); } @@ -65,6 +69,11 @@ public class StatsCollectionDisabledIT extends StatsCollectorAbstractIT { assertFalse(rs.next()); rs.close(); stmt.close(); - conn.close(); + rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM T1"); + String explainPlan = QueryUtil.getExplainPlan(rs); + assertEquals( + "CLIENT 1-CHUNK PARALLEL 1-WAY FULL SCAN OVER T1", + explainPlan); + conn.close(); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectorIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectorIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectorIT.java index e72f41f..bc575fd 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectorIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StatsCollectorIT.java @@ -44,6 +44,7 @@ import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; import org.apache.phoenix.util.PropertiesUtil; +import org.apache.phoenix.util.QueryUtil; import org.apache.phoenix.util.ReadOnlyProps; import org.apache.phoenix.util.SchemaUtil; import org.apache.phoenix.util.TestUtil; @@ -65,10 +66,11 @@ public class StatsCollectorIT extends StatsCollectorAbstractIT { @BeforeClass public static void doSetup() throws Exception { - Map<String,String> props = Maps.newHashMapWithExpectedSize(3); + Map<String,String> props = Maps.newHashMapWithExpectedSize(10); // Must update config before starting server props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Long.toString(20)); props.put(QueryServices.EXPLAIN_CHUNK_COUNT_ATTRIB, Boolean.TRUE.toString()); + props.put(QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, Boolean.TRUE.toString()); props.put(QueryServices.QUEUE_SIZE_ATTRIB, Integer.toString(1024)); props.put(QueryServices.TRANSACTIONS_ENABLED, Boolean.toString(true)); setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator())); @@ -86,6 +88,55 @@ public class StatsCollectorIT extends StatsCollectorAbstractIT { } @Test + public void testUpdateEmptyStats() throws Exception { + Connection conn; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + conn = DriverManager.getConnection(getUrl(), props); + conn.setAutoCommit(true); + conn.createStatement().execute( + "CREATE TABLE " + fullTableName +" ( k CHAR(1) PRIMARY KEY )" + tableDDLOptions); + conn.createStatement().execute("UPDATE STATISTICS " + tableName); + ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM " + fullTableName); + String explainPlan = QueryUtil.getExplainPlan(rs); + assertEquals( + "CLIENT 1-CHUNK 0 ROWS 0 BYTES PARALLEL 1-WAY FULL SCAN OVER " + fullTableName + "\n" + + " SERVER FILTER BY FIRST KEY ONLY", + explainPlan); + conn.close(); + } + + @Test + public void testSomeUpdateEmptyStats() throws Exception { + Connection conn; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + String fullTableName = this.fullTableName + "_SALTED"; + // props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 10)); + conn = DriverManager.getConnection(getUrl(), props); + conn.setAutoCommit(true); + conn.createStatement().execute( + "CREATE TABLE " + fullTableName +" ( k VARCHAR PRIMARY KEY, a.v1 VARCHAR, b.v2 VARCHAR ) " + tableDDLOptions + (tableDDLOptions.isEmpty() ? "" : ",") + "SALT_BUCKETS = 3"); + conn.createStatement().execute("UPSERT INTO " + fullTableName + "(k,v1) VALUES('a','123456789')"); + conn.createStatement().execute("UPDATE STATISTICS " + fullTableName); + ResultSet rs; + String explainPlan; + rs = conn.createStatement().executeQuery("EXPLAIN SELECT v2 FROM " + fullTableName + " WHERE v2='foo'"); + explainPlan = QueryUtil.getExplainPlan(rs); + assertEquals( + "CLIENT 3-CHUNK 0 ROWS 0 BYTES PARALLEL 3-WAY FULL SCAN OVER " + fullTableName + "\n" + + " SERVER FILTER BY B.V2 = 'foo'\n" + + "CLIENT MERGE SORT", + explainPlan); + rs = conn.createStatement().executeQuery("EXPLAIN SELECT * FROM " + fullTableName); + explainPlan = QueryUtil.getExplainPlan(rs); + assertEquals( + "CLIENT 4-CHUNK 1 ROWS 34 BYTES PARALLEL 3-WAY FULL SCAN OVER " + fullTableName + "\n" + + "CLIENT MERGE SORT", + explainPlan); + + conn.close(); + } + + @Test public void testUpdateStats() throws SQLException, IOException, InterruptedException { Connection conn; @@ -336,7 +387,7 @@ public class StatsCollectorIT extends StatsCollectorAbstractIT { // If we've set MIN_STATS_UPDATE_FREQ_MS_ATTRIB, an UPDATE STATISTICS will invalidate the cache // and forcing the new stats to be pulled over. int rowCount = conn.createStatement().executeUpdate("UPDATE STATISTICS " + tableName); - assertEquals(0, rowCount); + assertEquals(10, rowCount); } List<KeyRange>keyRanges = getAllSplits(conn, tableName); assertEquals(nRows+1, keyRanges.size()); @@ -356,7 +407,7 @@ public class StatsCollectorIT extends StatsCollectorAbstractIT { // If we've set MIN_STATS_UPDATE_FREQ_MS_ATTRIB, an UPDATE STATISTICS will invalidate the cache // and force us to pull over the new stats int rowCount = conn.createStatement().executeUpdate("UPDATE STATISTICS " + tableName); - assertEquals(0, rowCount); + assertEquals(5, rowCount); keyRanges = getAllSplits(conn, tableName); } assertEquals(nRows/2+1, keyRanges.size()); http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java index fc3edbe..a48de13 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/BaseResultIterators.java @@ -95,6 +95,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import com.google.common.io.Closeables; /** @@ -120,8 +121,9 @@ public abstract class BaseResultIterators extends ExplainTable implements Result private final ParallelScanGrouper scanGrouper; // TODO: too much nesting here - breakup into new classes. private final List<List<List<Pair<Scan,Future<PeekingResultIterator>>>>> allFutures; - private long estimatedRows; - private long estimatedSize; + private Long estimatedRows; + private Long estimatedSize; + private boolean hasGuidePosts; static final Function<HRegionLocation, KeyRange> TO_KEY_RANGE = new Function<HRegionLocation, KeyRange>() { @Override @@ -401,7 +403,7 @@ public abstract class BaseResultIterators extends ExplainTable implements Result * be further parallelized. TODO: pref test to verify 2) We're collecting stats, as in this case we need to scan * entire regions worth of data to track where to put the guide posts. */ - if (!useStats()) { return GuidePostsInfo.EMPTY_GUIDEPOST; } + if (!useStats()) { return GuidePostsInfo.NO_GUIDEPOST; } GuidePostsInfo gps = null; PTable table = getTable(); @@ -424,7 +426,7 @@ public abstract class BaseResultIterators extends ExplainTable implements Result } } } - if (gps == null) { return GuidePostsInfo.EMPTY_GUIDEPOST; } + if (gps == null) { return GuidePostsInfo.NO_GUIDEPOST; } return gps; } @@ -490,6 +492,7 @@ public abstract class BaseResultIterators extends ExplainTable implements Result } } GuidePostsInfo gps = getGuidePosts(whereConditions); + hasGuidePosts = gps != GuidePostsInfo.NO_GUIDEPOST; boolean traverseAllRegions = isSalted || isLocalIndex; if (!traverseAllRegions) { byte[] scanStartRow = scan.getStartRow(); @@ -528,63 +531,75 @@ public abstract class BaseResultIterators extends ExplainTable implements Result DataInput input = null; PrefixByteDecoder decoder = null; int guideIndex = 0; - if (gpsSize > 0) { - stream = new ByteArrayInputStream(guidePosts.get(), guidePosts.getOffset(), guidePosts.getLength()); - input = new DataInputStream(stream); - decoder = new PrefixByteDecoder(gps.getMaxLength()); - try { - while (currentKey.compareTo(currentGuidePost = PrefixByteCodec.decode(decoder, input)) >= 0 - && currentKey.getLength() != 0) { - guideIndex++; - } - } catch (EOFException e) {} - } - byte[] currentKeyBytes = currentKey.copyBytes(); - - // Merge bisect with guideposts for all but the last region - while (regionIndex <= stopIndex) { - byte[] currentGuidePostBytes = currentGuidePost.copyBytes(); - byte[] endKey, endRegionKey = EMPTY_BYTE_ARRAY; - if (regionIndex == stopIndex) { - endKey = stopKey; - } else { - endKey = regionBoundaries.get(regionIndex); - } - HRegionLocation regionLocation = regionLocations.get(regionIndex); - if (isLocalIndex) { - HRegionInfo regionInfo = regionLocation.getRegionInfo(); - endRegionKey = regionInfo.getEndKey(); - keyOffset = ScanUtil.getRowKeyOffset(regionInfo.getStartKey(), endRegionKey); + long estimatedRows = 0; + long estimatedSize = 0; + try { + if (gpsSize > 0) { + stream = new ByteArrayInputStream(guidePosts.get(), guidePosts.getOffset(), guidePosts.getLength()); + input = new DataInputStream(stream); + decoder = new PrefixByteDecoder(gps.getMaxLength()); + try { + while (currentKey.compareTo(currentGuidePost = PrefixByteCodec.decode(decoder, input)) >= 0 + && currentKey.getLength() != 0) { + guideIndex++; + } + } catch (EOFException e) {} } - try { - while (guideIndex < gpsSize && (currentGuidePost.compareTo(endKey) <= 0 || endKey.length == 0)) { - Scan newScan = scanRanges.intersectScan(scan, currentKeyBytes, currentGuidePostBytes, keyOffset, - false); - estimatedRows += gps.getRowCounts().get(guideIndex); - estimatedSize += gps.getByteCounts().get(guideIndex); - scans = addNewScan(parallelScans, scans, newScan, currentGuidePostBytes, false, regionLocation); - currentKeyBytes = currentGuidePost.copyBytes(); - currentGuidePost = PrefixByteCodec.decode(decoder, input); - currentGuidePostBytes = currentGuidePost.copyBytes(); - guideIndex++; + byte[] currentKeyBytes = currentKey.copyBytes(); + + // Merge bisect with guideposts for all but the last region + while (regionIndex <= stopIndex) { + byte[] currentGuidePostBytes = currentGuidePost.copyBytes(); + byte[] endKey, endRegionKey = EMPTY_BYTE_ARRAY; + if (regionIndex == stopIndex) { + endKey = stopKey; + } else { + endKey = regionBoundaries.get(regionIndex); } - } catch (EOFException e) {} - Scan newScan = scanRanges.intersectScan(scan, currentKeyBytes, endKey, keyOffset, true); - if (isLocalIndex) { - if (newScan != null) { - newScan.setAttribute(EXPECTED_UPPER_REGION_KEY, endRegionKey); - } else if (!scans.isEmpty()) { - scans.get(scans.size()-1).setAttribute(EXPECTED_UPPER_REGION_KEY, endRegionKey); + HRegionLocation regionLocation = regionLocations.get(regionIndex); + if (isLocalIndex) { + HRegionInfo regionInfo = regionLocation.getRegionInfo(); + endRegionKey = regionInfo.getEndKey(); + keyOffset = ScanUtil.getRowKeyOffset(regionInfo.getStartKey(), endRegionKey); } + try { + while (guideIndex < gpsSize && (currentGuidePost.compareTo(endKey) <= 0 || endKey.length == 0)) { + Scan newScan = scanRanges.intersectScan(scan, currentKeyBytes, currentGuidePostBytes, keyOffset, + false); + estimatedRows += gps.getRowCounts().get(guideIndex); + estimatedSize += gps.getByteCounts().get(guideIndex); + scans = addNewScan(parallelScans, scans, newScan, currentGuidePostBytes, false, regionLocation); + currentKeyBytes = currentGuidePost.copyBytes(); + currentGuidePost = PrefixByteCodec.decode(decoder, input); + currentGuidePostBytes = currentGuidePost.copyBytes(); + guideIndex++; + } + } catch (EOFException e) {} + Scan newScan = scanRanges.intersectScan(scan, currentKeyBytes, endKey, keyOffset, true); + if (isLocalIndex) { + if (newScan != null) { + newScan.setAttribute(EXPECTED_UPPER_REGION_KEY, endRegionKey); + } else if (!scans.isEmpty()) { + scans.get(scans.size()-1).setAttribute(EXPECTED_UPPER_REGION_KEY, endRegionKey); + } + } + scans = addNewScan(parallelScans, scans, newScan, endKey, true, regionLocation); + currentKeyBytes = endKey; + regionIndex++; } - scans = addNewScan(parallelScans, scans, newScan, endKey, true, regionLocation); - currentKeyBytes = endKey; - regionIndex++; - } - if (!scans.isEmpty()) { // Add any remaining scans - parallelScans.add(scans); + if (hasGuidePosts) { + this.estimatedRows = estimatedRows; + this.estimatedSize = estimatedSize; + } else { + this.estimatedRows = null; + this.estimatedSize = null; + } + if (!scans.isEmpty()) { // Add any remaining scans + parallelScans.add(scans); + } + } finally { + if (stream != null) Closeables.closeQuietly(stream); } - PrefixByteCodec.close(stream); return parallelScans; } @@ -857,8 +872,11 @@ public abstract class BaseResultIterators extends ExplainTable implements Result StringBuilder buf = new StringBuilder(); buf.append("CLIENT "); if (displayChunkCount) { + boolean displayRowCount = context.getConnection().getQueryServices().getProps().getBoolean( + QueryServices.EXPLAIN_ROW_COUNT_ATTRIB, + QueryServicesOptions.DEFAULT_EXPLAIN_ROW_COUNT); buf.append(this.splits.size()).append("-CHUNK "); - if (estimatedRows > 0) { + if (displayRowCount && hasGuidePosts) { buf.append(estimatedRows).append(" ROWS "); buf.append(estimatedSize).append(" BYTES "); } @@ -867,6 +885,14 @@ public abstract class BaseResultIterators extends ExplainTable implements Result explain(buf.toString(),planSteps); } + public Long getEstimatedRowCount() { + return this.estimatedRows; + } + + public Long getEstimatedByteCount() { + return this.estimatedSize; + } + @Override public String toString() { return "ResultIterators [name=" + getName() + ",id=" + scanId + ",scans=" + scans + "]"; http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java index 63d4e07..471ac73 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java @@ -271,7 +271,7 @@ public interface QueryConstants { "CREATE TABLE " + SYSTEM_CATALOG_SCHEMA + ".\"" + SYSTEM_STATS_TABLE + "\"(\n" + // PK columns PHYSICAL_NAME + " VARCHAR NOT NULL," + - COLUMN_FAMILY + " VARCHAR," + + COLUMN_FAMILY + " VARCHAR NOT NULL," + GUIDE_POST_KEY + " VARBINARY," + GUIDE_POSTS_WIDTH + " BIGINT," + LAST_STATS_UPDATE_TIME+ " DATE, "+ http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java index 1efcd8c..32b4fc0 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java @@ -162,6 +162,7 @@ public interface QueryServices extends SQLCloseable { public static final String SEQUENCE_SALT_BUCKETS_ATTRIB = "phoenix.sequence.saltBuckets"; public static final String COPROCESSOR_PRIORITY_ATTRIB = "phoenix.coprocessor.priority"; public static final String EXPLAIN_CHUNK_COUNT_ATTRIB = "phoenix.explain.displayChunkCount"; + public static final String EXPLAIN_ROW_COUNT_ATTRIB = "phoenix.explain.displayRowCount"; public static final String ALLOW_ONLINE_TABLE_SCHEMA_UPDATE = "hbase.online.schema.update.enable"; public static final String NUM_RETRIES_FOR_SCHEMA_UPDATE_CHECK = "phoenix.schema.change.retries"; public static final String DELAY_FOR_SCHEMA_UPDATE_CHECK = "phoenix.schema.change.delay"; http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java index 27c5693..3e0ffe1 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java @@ -29,6 +29,7 @@ import static org.apache.phoenix.query.QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB import static org.apache.phoenix.query.QueryServices.DELAY_FOR_SCHEMA_UPDATE_CHECK; import static org.apache.phoenix.query.QueryServices.DROP_METADATA_ATTRIB; import static org.apache.phoenix.query.QueryServices.EXPLAIN_CHUNK_COUNT_ATTRIB; +import static org.apache.phoenix.query.QueryServices.EXPLAIN_ROW_COUNT_ATTRIB; import static org.apache.phoenix.query.QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB; import static org.apache.phoenix.query.QueryServices.FORCE_ROW_KEY_ORDER_ATTRIB; import static org.apache.phoenix.query.QueryServices.GLOBAL_METRICS_ENABLED; @@ -196,6 +197,7 @@ public class QueryServicesOptions { */ public static final int DEFAULT_COPROCESSOR_PRIORITY = Coprocessor.PRIORITY_SYSTEM/2 + Coprocessor.PRIORITY_USER/2; // Divide individually to prevent any overflow public static final boolean DEFAULT_EXPLAIN_CHUNK_COUNT = true; + public static final boolean DEFAULT_EXPLAIN_ROW_COUNT = true; public static final boolean DEFAULT_ALLOW_ONLINE_TABLE_SCHEMA_UPDATE = true; public static final int DEFAULT_RETRIES_FOR_SCHEMA_UPDATE_CHECK = 10; public static final long DEFAULT_DELAY_FOR_SCHEMA_UPDATE_CHECK = 5 * 1000; // 5 seconds. @@ -573,6 +575,11 @@ public class QueryServicesOptions { return this; } + public QueryServicesOptions setExplainRowCount(boolean showRowCount) { + config.setBoolean(EXPLAIN_ROW_COUNT_ATTRIB, showRowCount); + return this; + } + public QueryServicesOptions setAllowOnlineSchemaUpdate(boolean allow) { config.setBoolean(ALLOW_ONLINE_TABLE_SCHEMA_UPDATE, allow); return this; http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/DefaultStatisticsCollector.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/DefaultStatisticsCollector.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/DefaultStatisticsCollector.java index cb6f5d4..b81d206 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/DefaultStatisticsCollector.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/DefaultStatisticsCollector.java @@ -24,13 +24,11 @@ import java.util.Map; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.Cell; -import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValueUtil; import org.apache.hadoop.hbase.client.Mutation; import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; -import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.InternalScanner; import org.apache.hadoop.hbase.regionserver.Region; import org.apache.hadoop.hbase.regionserver.Store; @@ -50,18 +48,15 @@ import com.google.common.collect.Maps; /** * A default implementation of the Statistics tracker that helps to collect stats like min key, max key and guideposts. - * TODO: review timestamps used for stats. We support the user controlling the timestamps, so we should honor that with - * timestamps for stats as well. The issue is for compaction, though. I don't know of a way for the user to specify any - * timestamp for that. Perhaps best to use current time across the board for now. */ class DefaultStatisticsCollector implements StatisticsCollector { private static final Logger logger = LoggerFactory.getLogger(DefaultStatisticsCollector.class); + private final Map<ImmutableBytesPtr, Pair<Long, GuidePostsInfoBuilder>> guidePostsInfoWriterMap = Maps.newHashMap(); + private final StatisticsWriter statsWriter; + private final Pair<Long, GuidePostsInfoBuilder> cachedGps; private long guidepostDepth; private long maxTimeStamp = MetaDataProtocol.MIN_TABLE_TIMESTAMP; - private Map<ImmutableBytesPtr, Pair<Long, GuidePostsInfoBuilder>> guidePostsInfoWriterMap = Maps.newHashMap(); - protected StatisticsWriter statsTable; - private Pair<Long, GuidePostsInfoBuilder> cachedGps = null; DefaultStatisticsCollector(RegionCoprocessorEnvironment env, String tableName, long clientTimeStamp, byte[] family, byte[] gp_width_bytes, byte[] gp_per_region_bytes) throws IOException { @@ -87,12 +82,14 @@ class DefaultStatisticsCollector implements StatisticsCollector { } // Get the stats table associated with the current table on which the CP is // triggered - this.statsTable = StatisticsWriter.newWriter(env, tableName, clientTimeStamp); + this.statsWriter = StatisticsWriter.newWriter(env, tableName, clientTimeStamp); // in a compaction we know the one family ahead of time if (family != null) { ImmutableBytesPtr cfKey = new ImmutableBytesPtr(family); cachedGps = new Pair<Long, GuidePostsInfoBuilder>(0l, new GuidePostsInfoBuilder()); guidePostsInfoWriterMap.put(cfKey, cachedGps); + } else { + cachedGps = null; } } @@ -103,7 +100,7 @@ class DefaultStatisticsCollector implements StatisticsCollector { @Override public void close() throws IOException { - this.statsTable.close(); + this.statsWriter.close(); } @Override @@ -129,9 +126,13 @@ class DefaultStatisticsCollector implements StatisticsCollector { // Delete statistics for a region if no guidepost is collected for that region during UPDATE STATISTICS // This will not impact a stats collection of single column family during compaction as // guidePostsInfoWriterMap cannot be empty in this case. - if (guidePostsInfoWriterMap.keySet().isEmpty()) { + if (cachedGps == null) { for (Store store : region.getStores()) { - statsTable.deleteStats(region, this, new ImmutableBytesPtr(store.getFamily().getName()), mutations); + ImmutableBytesPtr cfKey = new ImmutableBytesPtr(store.getFamily().getName()); + if (!guidePostsInfoWriterMap.containsKey(cfKey)) { + Pair<Long, GuidePostsInfoBuilder> emptyGps = new Pair<Long, GuidePostsInfoBuilder>(0l, new GuidePostsInfoBuilder()); + guidePostsInfoWriterMap.put(cfKey, emptyGps); + } } } for (ImmutableBytesPtr fam : guidePostsInfoWriterMap.keySet()) { @@ -139,12 +140,12 @@ class DefaultStatisticsCollector implements StatisticsCollector { if (logger.isDebugEnabled()) { logger.debug("Deleting the stats for the region " + region.getRegionInfo()); } - statsTable.deleteStats(region, this, fam, mutations); + statsWriter.deleteStats(region, this, fam, mutations); } if (logger.isDebugEnabled()) { logger.debug("Adding new stats for the region " + region.getRegionInfo()); } - statsTable.addStats(this, fam, mutations); + statsWriter.addStats(this, fam, mutations); } } catch (IOException e) { logger.error("Failed to update statistics table!", e); @@ -153,7 +154,7 @@ class DefaultStatisticsCollector implements StatisticsCollector { } private void commitStats(List<Mutation> mutations) throws IOException { - statsTable.commitStats(mutations); + statsWriter.commitStats(mutations); } /** @@ -212,7 +213,7 @@ class DefaultStatisticsCollector implements StatisticsCollector { protected InternalScanner getInternalScanner(RegionCoprocessorEnvironment env, InternalScanner internalScan, ImmutableBytesPtr family) { - return new StatisticsScanner(this, statsTable, env, internalScan, family); + return new StatisticsScanner(this, statsWriter, env, internalScan, family); } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfo.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfo.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfo.java index b8cc3f1..291cb6d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfo.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfo.java @@ -38,7 +38,7 @@ public class GuidePostsInfo { */ private int maxLength; - public final static GuidePostsInfo EMPTY_GUIDEPOST = new GuidePostsInfo(new ArrayList<Long>(), + public final static GuidePostsInfo NO_GUIDEPOST = new GuidePostsInfo(new ArrayList<Long>(), new ImmutableBytesWritable(ByteUtil.EMPTY_BYTE_ARRAY), new ArrayList<Long>(), 0, 0); public int getMaxLength() { http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfoBuilder.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfoBuilder.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfoBuilder.java index 2133349..10d59ee 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfoBuilder.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/GuidePostsInfoBuilder.java @@ -24,7 +24,6 @@ import java.util.List; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.phoenix.util.ByteUtil; -import org.apache.phoenix.util.PrefixByteCodec; import org.apache.phoenix.util.PrefixByteEncoder; import org.apache.phoenix.util.TrustedByteArrayOutputStream; @@ -107,15 +106,10 @@ public class GuidePostsInfoBuilder { return addGuidePosts(new ImmutableBytesWritable(row), byteCount, rowCount); } - private void close() { - PrefixByteCodec.close(stream); - } - public GuidePostsInfo build() { this.guidePosts.set(stream.getBuffer(), 0, stream.size()); GuidePostsInfo guidePostsInfo = new GuidePostsInfo(this.byteCounts, this.guidePosts, this.rowCounts, this.maxLength, this.guidePostsCount); - this.close(); return guidePostsInfo; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStatsImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStatsImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStatsImpl.java index dacc213..42e7bed 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStatsImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStatsImpl.java @@ -32,6 +32,7 @@ import org.apache.phoenix.util.PrefixByteCodec; import org.apache.phoenix.util.PrefixByteDecoder; import org.apache.phoenix.util.SizedUtil; +import com.google.common.io.Closeables; import com.sun.istack.NotNull; /** @@ -89,13 +90,13 @@ public class PTableStatsImpl implements PTableStats { } catch (EOFException e) { // Ignore as this signifies we're done } finally { - PrefixByteCodec.close(stream); + Closeables.closeQuietly(stream); } buf.setLength(buf.length() - 1); } buf.append(")"); } finally { - PrefixByteCodec.close(stream); + Closeables.closeQuietly(stream); } } buf.append("]"); http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsUtil.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsUtil.java index 5b47104..5e03be5 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsUtil.java @@ -62,15 +62,19 @@ public class StatisticsUtil { public static byte[] getRowKey(byte[] table, ImmutableBytesPtr fam, ImmutableBytesWritable guidePostStartKey) { // always starts with the source table - byte[] rowKey = new byte[table.length + fam.getLength() + guidePostStartKey.getLength() + 2]; + int guidePostLength = guidePostStartKey.getLength(); + boolean hasGuidePost = guidePostLength > 0; + byte[] rowKey = new byte[table.length + fam.getLength() + guidePostLength + (hasGuidePost ? 2 : 1)]; int offset = 0; System.arraycopy(table, 0, rowKey, offset, table.length); offset += table.length; rowKey[offset++] = QueryConstants.SEPARATOR_BYTE; // assumes stats table columns not DESC System.arraycopy(fam.get(), fam.getOffset(), rowKey, offset, fam.getLength()); - offset += fam.getLength(); - rowKey[offset++] = QueryConstants.SEPARATOR_BYTE; // assumes stats table columns not DESC - System.arraycopy(guidePostStartKey.get(), 0, rowKey, offset, guidePostStartKey.getLength()); + if (hasGuidePost) { + offset += fam.getLength(); + rowKey[offset++] = QueryConstants.SEPARATOR_BYTE; // assumes stats table columns not DESC + System.arraycopy(guidePostStartKey.get(), 0, rowKey, offset, guidePostLength); + } return rowKey; } @@ -215,9 +219,12 @@ public class StatisticsUtil { } public static byte[] getGuidePostsInfoFromRowKey(byte[] tableNameBytes, byte[] fam, byte[] row) { - ImmutableBytesWritable ptr = new ImmutableBytesWritable(); - int gpOffset = tableNameBytes.length + 1 + fam.length + 1; - ptr.set(row, gpOffset, row.length - gpOffset); - return ByteUtil.copyKeyBytesIfNecessary(ptr); + if (row.length > tableNameBytes.length + 1 + fam.length) { + ImmutableBytesWritable ptr = new ImmutableBytesWritable(); + int gpOffset = tableNameBytes.length + 1 + fam.length + 1; + ptr.set(row, gpOffset, row.length - gpOffset); + return ByteUtil.copyKeyBytesIfNecessary(ptr); + } + return ByteUtil.EMPTY_BYTE_ARRAY; } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsWriter.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsWriter.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsWriter.java index f8c888d..a727c1c 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsWriter.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsWriter.java @@ -49,7 +49,6 @@ import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.schema.types.PDate; import org.apache.phoenix.schema.types.PLong; import org.apache.phoenix.util.ByteUtil; -import org.apache.phoenix.util.PrefixByteCodec; import org.apache.phoenix.util.PrefixByteDecoder; import org.apache.phoenix.util.ServerUtil; import org.apache.phoenix.util.TimeKeeper; @@ -143,33 +142,46 @@ public class StatisticsWriter implements Closeable { List<Long> byteCounts = gps.getByteCounts(); List<Long> rowCounts = gps.getRowCounts(); ImmutableBytesWritable keys = gps.getGuidePosts(); - ByteArrayInputStream stream = new ByteArrayInputStream(keys.get(), keys.getOffset(), keys.getLength()); - DataInput input = new DataInputStream(stream); - PrefixByteDecoder decoder = new PrefixByteDecoder(gps.getMaxLength()); - int guidePostCount = 0; - try { - while (true) { - ImmutableBytesWritable ptr = decoder.decode(input); - byte[] prefix = StatisticsUtil.getRowKey(tableName, cfKey, ptr); - Put put = new Put(prefix); - put.add(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, PhoenixDatabaseMetaData.GUIDE_POSTS_WIDTH_BYTES, - timeStamp, PLong.INSTANCE.toBytes(byteCounts.get(guidePostCount))); - put.add(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, - PhoenixDatabaseMetaData.GUIDE_POSTS_ROW_COUNT_BYTES, timeStamp, - PLong.INSTANCE.toBytes(rowCounts.get(guidePostCount))); - // Add our empty column value so queries behave correctly - put.add(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, QueryConstants.EMPTY_COLUMN_BYTES, timeStamp, - ByteUtil.EMPTY_BYTE_ARRAY); - mutations.add(put); - guidePostCount++; - } - } catch (EOFException e) { // Ignore as this signifies we're done + boolean hasGuidePosts = keys.getLength() > 0; + if (hasGuidePosts) { + int guidePostCount = 0; + try (ByteArrayInputStream stream = new ByteArrayInputStream(keys.get(), keys.getOffset(), keys.getLength())) { + DataInput input = new DataInputStream(stream); + PrefixByteDecoder decoder = new PrefixByteDecoder(gps.getMaxLength()); + do { + ImmutableBytesWritable ptr = decoder.decode(input); + addGuidepost(cfKey, mutations, ptr, byteCounts.get(guidePostCount), rowCounts.get(guidePostCount), timeStamp); + guidePostCount++; + } while (decoder != null); + } catch (EOFException e) { // Ignore as this signifies we're done - } finally { - PrefixByteCodec.close(stream); + } + // If we've written guideposts with a guidepost key, then delete the + // empty guidepost indicator that may have been written by other + // regions. + byte[] rowKey = StatisticsUtil.getRowKey(tableName, cfKey, ByteUtil.EMPTY_IMMUTABLE_BYTE_ARRAY); + Delete delete = new Delete(rowKey, timeStamp); + mutations.add(delete); + } else { + addGuidepost(cfKey, mutations, ByteUtil.EMPTY_IMMUTABLE_BYTE_ARRAY, 0, 0, timeStamp); } } } + + @SuppressWarnings("deprecation") + private void addGuidepost(ImmutableBytesPtr cfKey, List<Mutation> mutations, ImmutableBytesWritable ptr, long byteCount, long rowCount, long timeStamp) { + byte[] prefix = StatisticsUtil.getRowKey(tableName, cfKey, ptr); + Put put = new Put(prefix); + put.add(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, PhoenixDatabaseMetaData.GUIDE_POSTS_WIDTH_BYTES, + timeStamp, PLong.INSTANCE.toBytes(byteCount)); + put.add(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, + PhoenixDatabaseMetaData.GUIDE_POSTS_ROW_COUNT_BYTES, timeStamp, + PLong.INSTANCE.toBytes(rowCount)); + // Add our empty column value so queries behave correctly + put.add(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, QueryConstants.EMPTY_COLUMN_BYTES, timeStamp, + ByteUtil.EMPTY_BYTE_ARRAY); + mutations.add(put); + } private static MutationType getMutationType(Mutation m) throws IOException { if (m instanceof Put) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/main/java/org/apache/phoenix/util/PrefixByteCodec.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/PrefixByteCodec.java b/phoenix-core/src/main/java/org/apache/phoenix/util/PrefixByteCodec.java index 8c3aa80..2641b6a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/PrefixByteCodec.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/PrefixByteCodec.java @@ -18,7 +18,6 @@ package org.apache.phoenix.util; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.DataInput; import java.io.DataInputStream; import java.io.DataOutput; @@ -52,15 +51,15 @@ public class PrefixByteCodec { } public static int encodeBytes(List<byte[]> listOfBytes, ImmutableBytesWritable ptr) throws IOException { - TrustedByteArrayOutputStream stream = new TrustedByteArrayOutputStream(calculateSize(listOfBytes)); - DataOutput output = new DataOutputStream(stream); - PrefixByteEncoder encoder = new PrefixByteEncoder(); - for (byte[] bytes : listOfBytes) { - encoder.encode(output, bytes, 0, bytes.length); + try (TrustedByteArrayOutputStream stream = new TrustedByteArrayOutputStream(calculateSize(listOfBytes))) { + DataOutput output = new DataOutputStream(stream); + PrefixByteEncoder encoder = new PrefixByteEncoder(); + for (byte[] bytes : listOfBytes) { + encoder.encode(output, bytes, 0, bytes.length); + } + ptr.set(stream.getBuffer(), 0, stream.size()); + return encoder.getMaxLength(); } - close(stream); - ptr.set(stream.getBuffer(), 0, stream.size()); - return encoder.getMaxLength(); } public static int calculateSize(List<byte[]> listOfBytes) { @@ -81,24 +80,4 @@ public class PrefixByteCodec { throw new RuntimeException(e); } } - - public static void close(ByteArrayInputStream stream) { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - public static void close(ByteArrayOutputStream stream) { - if (stream != null) { - try { - stream.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/c25f8879/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java index 29a7001..6ae655c 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java @@ -54,6 +54,7 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl { public static final long DEFAULT_MAX_CLIENT_METADATA_CACHE_SIZE = 1024L*1024L*2L; // 2 Mb public static final int DEFAULT_MIN_STATS_UPDATE_FREQ_MS = 0; public static final boolean DEFAULT_EXPLAIN_CHUNK_COUNT = false; // TODO: update explain plans in test and set to true + public static final boolean DEFAULT_EXPLAIN_ROW_COUNT = false; // TODO: update explain plans in test and set to true public static final String DEFAULT_EXTRA_JDBC_ARGUMENTS = PhoenixRuntime.PHOENIX_TEST_DRIVER_URL_PARAM; private static final boolean DEFAULT_RUN_UPDATE_STATS_ASYNC = false; private static final boolean DEFAULT_COMMIT_STATS_ASYNC = false; @@ -80,6 +81,7 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl { private static QueryServicesOptions getDefaultServicesOptions() { return withDefaults() .setExplainChunkCount(DEFAULT_EXPLAIN_CHUNK_COUNT) + .setExplainRowCount(DEFAULT_EXPLAIN_ROW_COUNT) .setSequenceSaltBuckets(DEFAULT_SEQUENCE_TABLE_SALT_BUCKETS) .setMinStatsUpdateFrequencyMs(DEFAULT_MIN_STATS_UPDATE_FREQ_MS) .setThreadPoolSize(DEFAULT_THREAD_POOL_SIZE)