Repository: phoenix Updated Branches: refs/heads/3.0 c89f2dd71 -> a5b797225
PHOENIX-1309 Ensure Phoenix table is created for Local index and view index tables to store guideposts against them (James Taylor via Ram) Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/a5b79722 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/a5b79722 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/a5b79722 Branch: refs/heads/3.0 Commit: a5b797225f4ab9df3a470b53ed0e73bd79822b00 Parents: c89f2dd Author: Ramkrishna <ramkrishna.s.vasude...@intel.com> Authored: Mon Oct 13 10:14:03 2014 +0530 Committer: Ramkrishna <ramkrishna.s.vasude...@intel.com> Committed: Mon Oct 13 10:14:03 2014 +0530 ---------------------------------------------------------------------- .../org/apache/phoenix/end2end/BaseViewIT.java | 2 + .../org/apache/phoenix/end2end/QueryIT.java | 20 +-- .../apache/phoenix/end2end/SaltedViewIT.java | 2 +- .../java/org/apache/phoenix/end2end/ViewIT.java | 11 +- .../UngroupedAggregateRegionObserver.java | 1 + .../phoenix/iterate/ParallelIterators.java | 86 +++++++---- .../phoenix/query/ConnectionQueryServices.java | 6 + .../query/ConnectionQueryServicesImpl.java | 41 ++++- .../query/ConnectionlessQueryServicesImpl.java | 14 ++ .../query/DelegateConnectionQueryServices.java | 16 ++ .../org/apache/phoenix/query/QueryServices.java | 1 + .../phoenix/query/QueryServicesOptions.java | 2 +- .../apache/phoenix/schema/MetaDataClient.java | 77 +++++++++- .../phoenix/schema/MetaDataClient.java.orig | 151 +++++++++++++++++-- .../apache/phoenix/schema/PColumnFamily.java | 2 - .../phoenix/schema/PColumnFamilyImpl.java | 19 --- .../java/org/apache/phoenix/schema/PTable.java | 7 - .../org/apache/phoenix/schema/PTableImpl.java | 21 +-- .../phoenix/schema/stats/PTableStats.java | 7 + .../phoenix/schema/stats/PTableStatsImpl.java | 41 +++++ .../schema/stats/StatisticsCollector.java | 14 +- .../phoenix/schema/stats/StatisticsWriter.java | 3 +- .../java/org/apache/phoenix/util/SizedUtil.java | 5 + .../phoenix/query/QueryServicesTestImpl.java | 2 - 24 files changed, 429 insertions(+), 122 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java index e68c82e..b6a9994 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java @@ -27,6 +27,7 @@ import java.sql.DriverManager; import java.sql.ResultSet; import java.util.Map; +import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.util.QueryUtil; import org.apache.phoenix.util.ReadOnlyProps; import org.junit.BeforeClass; @@ -43,6 +44,7 @@ public class BaseViewIT extends BaseHBaseManagedTimeIT { Map<String,String> props = Maps.newHashMapWithExpectedSize(1); // Don't split intra region so we can more easily know that the n-way parallelization is for the explain plan // Must update config before starting server + props.put(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, Integer.toString(20)); setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator())); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryIT.java index bcc2973..ac1c61b 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryIT.java @@ -204,7 +204,7 @@ public class QueryIT extends BaseQueryIT { } private void testNoStringValue(String value) throws Exception { - String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 1); + String url = getUrl() + ";" + PhoenixRuntime.CURRENT_SCN_ATTRIB + "=" + (ts + 10); Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); Connection upsertConn = DriverManager.getConnection(url, props); upsertConn.setAutoCommit(true); // Test auto commit @@ -215,13 +215,15 @@ public class QueryIT extends BaseQueryIT { stmt.setString(2, ROW5); stmt.setString(3, value); stmt.execute(); // should commit too + upsertConn.close(); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 20)); Connection conn1 = DriverManager.getConnection(getUrl(), props); analyzeTable(conn1, "ATABLE"); conn1.close(); upsertConn.close(); String query = "SELECT a_string, b_string FROM aTable WHERE organization_id=? and a_integer = 5"; - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 2)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 30)); Connection conn = DriverManager.getConnection(getUrl(), props); try { PreparedStatement statement = conn.prepareStatement(query); @@ -280,7 +282,7 @@ public class QueryIT extends BaseQueryIT { upsertConn.close(); String query = "SELECT organization_id, a_string AS a FROM atable WHERE organization_id=? and a_integer = 5"; - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 2)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 20)); Connection conn = DriverManager.getConnection(getUrl(), props); PreparedStatement statement = conn.prepareStatement(query); statement.setString(1, tenantId); @@ -813,15 +815,15 @@ public class QueryIT extends BaseQueryIT { public void testSumOverNullIntegerColumn() throws Exception { String query = "SELECT sum(a_integer) FROM aTable a"; Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 2)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 20)); Connection conn = DriverManager.getConnection(getUrl(), props); conn.setAutoCommit(true); conn.createStatement().execute("UPSERT INTO atable(organization_id,entity_id,a_integer) VALUES('" + getOrganizationId() + "','" + ROW3 + "',NULL)"); - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 6)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 30)); Connection conn1 = DriverManager.getConnection(getUrl(), props); analyzeTable(conn1, "ATABLE"); conn1.close(); - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 5)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 50)); conn = DriverManager.getConnection(getUrl(), props); try { PreparedStatement statement = conn.prepareStatement(query); @@ -832,15 +834,15 @@ public class QueryIT extends BaseQueryIT { } finally { conn.close(); } - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 7)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 70)); conn = DriverManager.getConnection(getUrl(), props); conn.setAutoCommit(true); conn.createStatement().execute("UPSERT INTO atable(organization_id,entity_id,a_integer) SELECT organization_id, entity_id, null FROM atable"); - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 6)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 60)); conn1 = DriverManager.getConnection(getUrl(), props); analyzeTable(conn1, "ATABLE"); conn1.close(); - props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 9)); + props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 90)); conn = DriverManager.getConnection(getUrl(), props); try { PreparedStatement statement = conn.prepareStatement(query); http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/it/java/org/apache/phoenix/end2end/SaltedViewIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SaltedViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SaltedViewIT.java index ea59b85..cc08d15 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SaltedViewIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SaltedViewIT.java @@ -20,7 +20,7 @@ package org.apache.phoenix.end2end; import org.junit.Test; import org.junit.experimental.categories.Category; -@Category(HBaseManagedTimeTest.class) +@Category(NeedsOwnMiniClusterTest.class) public class SaltedViewIT extends BaseViewIT { /** http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java index 8ef1024..d997e36 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java @@ -17,6 +17,8 @@ */ package org.apache.phoenix.end2end; +import static org.apache.phoenix.util.TestUtil.analyzeTable; +import static org.apache.phoenix.util.TestUtil.getAllSplits; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -26,14 +28,16 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; import org.apache.phoenix.exception.SQLExceptionCode; +import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.schema.ReadOnlyTableException; import org.apache.phoenix.schema.TableNotFoundException; import org.junit.Test; import org.junit.experimental.categories.Category; -@Category(HBaseManagedTimeTest.class) +@Category(NeedsOwnMiniClusterTest.class) public class ViewIT extends BaseViewIT { @Test @@ -55,6 +59,11 @@ public class ViewIT extends BaseViewIT { } conn.commit(); + analyzeTable(conn, "v"); + + List<KeyRange> splits = getAllSplits(conn, "v"); + assertEquals(4, splits.size()); + int count = 0; ResultSet rs = conn.createStatement().executeQuery("SELECT k FROM v"); while (rs.next()) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java index 7172430..3966953 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/UngroupedAggregateRegionObserver.java @@ -131,6 +131,7 @@ public class UngroupedAggregateRegionObserver extends BaseScannerRegionObserver if(ScanUtil.isAnalyzeTable(scan)) { scan.setStartRow(HConstants.EMPTY_START_ROW); scan.setStopRow(HConstants.EMPTY_END_ROW); + scan.setFilter(null); } return s; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java index bc45389..c8c2dba 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ParallelIterators.java @@ -44,7 +44,6 @@ import org.apache.phoenix.compile.QueryPlan; import org.apache.phoenix.compile.RowProjector; import org.apache.phoenix.compile.ScanRanges; import org.apache.phoenix.compile.StatementContext; -import org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult; import org.apache.phoenix.filter.ColumnProjectionFilter; import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr; import org.apache.phoenix.job.JobManager.JobCallable; @@ -54,15 +53,14 @@ import org.apache.phoenix.query.ConnectionQueryServices; import org.apache.phoenix.query.KeyRange; import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.query.QueryServices; -import org.apache.phoenix.schema.ColumnFamilyNotFoundException; import org.apache.phoenix.schema.MetaDataClient; import org.apache.phoenix.schema.PColumnFamily; import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTable.ViewType; -import org.apache.phoenix.schema.PTableKey; import org.apache.phoenix.schema.SaltingUtil; import org.apache.phoenix.schema.StaleRegionBoundaryCacheException; import org.apache.phoenix.schema.TableRef; +import org.apache.phoenix.schema.stats.PTableStats; import org.apache.phoenix.util.ByteUtil; import org.apache.phoenix.util.ReadOnlyProps; import org.apache.phoenix.util.SQLCloseables; @@ -89,7 +87,8 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { private static final Logger logger = LoggerFactory.getLogger(ParallelIterators.class); private final List<List<Scan>> scans; private final List<KeyRange> splits; - private final PTable physicalTable; + private final PTableStats tableStats; + private final byte[] physicalTableName; private final QueryPlan plan; private final ParallelIteratorFactory iteratorFactory; @@ -113,10 +112,13 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { this.plan = plan; StatementContext context = plan.getContext(); TableRef tableRef = plan.getTableRef(); + PTable table = tableRef.getTable(); FilterableStatement statement = plan.getStatement(); RowProjector projector = plan.getProjector(); MetaDataClient client = new MetaDataClient(context.getConnection()); - PTable physicalTable = tableRef.getTable(); + physicalTableName = table.getPhysicalName().getBytes(); + tableStats = useStats() ? new MetaDataClient(context.getConnection()).getTableStats(table) : PTableStats.EMPTY_STATS; +/* PTable physicalTable = tableRef.getTable(); String physicalName = tableRef.getTable().getPhysicalName().getString(); if ((physicalTable.getViewIndexId() == null) && (!physicalName.equals(physicalTable.getName().getString()))) { // tableRef is not for the physical table String physicalSchemaName = SchemaUtil.getSchemaNameFromFullName(physicalName); @@ -124,7 +126,7 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { // TODO: this will be an extra RPC to ensure we have the latest guideposts, but is almost always // unnecessary. We should instead track when the last time an update cache was done for this // for physical table and not do it again until some interval has passed (it's ok to use stale stats). - MetaDataMutationResult result = client.updateCache(null, /* use global tenant id to get physical table */ + MetaDataMutationResult result = client.updateCache(null, use global tenant id to get physical table physicalSchemaName, physicalTableName); physicalTable = result.getTable(); if(physicalTable == null) { @@ -133,9 +135,8 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { .getTable(new PTableKey(null, physicalTableName)); } } - this.physicalTable = physicalTable; + this.physicalTable = physicalTable;*/ Scan scan = context.getScan(); - PTable table = tableRef.getTable(); if (projector.isProjectEmptyKeyValue()) { Map<byte [], NavigableSet<byte []>> familyMap = scan.getFamilyMap(); // If nothing projected into scan and we only have one column family, just allow everything @@ -272,6 +273,22 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { return scans; } + private PTable getTable() { + return plan.getTableRef().getTable(); + } + + private boolean useStats() { + Scan scan = context.getScan(); + boolean isPointLookup = context.getScanRanges().isPointLookup(); + /* + * Don't use guide posts if: 1) We're doing a point lookup, as HBase is fast enough at those to not need them to 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 (isPointLookup || ScanUtil.isAnalyzeTable(scan)) { return false; } + return true; + } + private static List<byte[]> toBoundaries(List<HRegionLocation> regionLocations) { int nBoundaries = regionLocations.size() - 1; List<byte[]> ranges = Lists.newArrayListWithExpectedSize(nBoundaries); @@ -298,11 +315,7 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { return guideIndex; } - private List<byte[]> getGuidePosts(PTable table) { - Scan scan = context.getScan(); - boolean isPointLookup = context.getScanRanges().isPointLookup(); - byte[] defaultCF = SchemaUtil.getEmptyColumnFamily(table); - List<byte[]> gps = Collections.emptyList(); + private List<byte[]> getGuidePosts() { /* * Don't use guide posts if: * 1) We're doing a point lookup, as HBase is fast enough at those @@ -310,24 +323,31 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { * 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 (!isPointLookup && !ScanUtil.isAnalyzeTable(scan)) { - if (table.getColumnFamilies().isEmpty()) { - // For sure we can get the defaultCF from the table - return table.getGuidePosts(); - } - try { - if (scan.getFamilyMap().size() > 0 && !scan.getFamilyMap().containsKey(defaultCF)) { - // If default CF is not used in scan, use first CF referenced in scan - return table.getColumnFamily(scan.getFamilyMap().keySet().iterator().next()).getGuidePosts(); - } + if (!useStats()) { + return Collections.emptyList(); + } + + List<byte[]> gps = null; + PTable table = getTable(); + Map<byte[],List<byte[]>> guidePostMap = tableStats.getGuidePosts(); + byte[] defaultCF = SchemaUtil.getEmptyColumnFamily(getTable()); + if (table.getColumnFamilies().isEmpty()) { + // For sure we can get the defaultCF from the table + gps = guidePostMap.get(defaultCF); + } else { + Scan scan = context.getScan(); + if (scan.getFamilyMap().size() > 0 && !scan.getFamilyMap().containsKey(defaultCF)) { + // If default CF is not used in scan, use first CF referenced in scan + gps = guidePostMap.get(scan.getFamilyMap().keySet().iterator().next()); + } else { // Otherwise, favor use of default CF. - return table.getColumnFamily(defaultCF).getGuidePosts(); - } catch (ColumnFamilyNotFoundException cfne) { - // Alter table does this + gps = guidePostMap.get(defaultCF); } } + if (gps == null) { + return Collections.emptyList(); + } return gps; - } private static String toString(List<byte[]> gps) { @@ -348,12 +368,13 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { if (scan == null) { return scans; } + PTable table = getTable(); if (!scans.isEmpty()) { boolean startNewScanList = false; if (!plan.isRowKeyOrdered()) { startNewScanList = true; } else if (crossedRegionBoundary) { - if (physicalTable.getBucketNum() != null) { + if (table.getBucketNum() != null) { byte[] previousStartKey = scans.get(scans.size()-1).getStartRow(); byte[] currentStartKey = scan.getStartRow(); byte[] prefix = ScanUtil.getPrefix(previousStartKey, SaltingUtil.NUM_SALTING_BYTES); @@ -377,11 +398,12 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { */ private List<List<Scan>> getParallelScans(final Scan scan) throws SQLException { List<HRegionLocation> regionLocations = context.getConnection().getQueryServices() - .getAllTableRegions(physicalTable.getPhysicalName().getBytes()); + .getAllTableRegions(physicalTableName); List<byte[]> regionBoundaries = toBoundaries(regionLocations); ScanRanges scanRanges = context.getScanRanges(); - boolean isSalted = physicalTable.getBucketNum() != null; - List<byte[]> gps = getGuidePosts(physicalTable); + PTable table = getTable(); + boolean isSalted = table.getBucketNum() != null; + List<byte[]> gps = getGuidePosts(); if (logger.isDebugEnabled()) { logger.debug("Guideposts: " + toString(gps)); } @@ -478,7 +500,7 @@ public class ParallelIterators extends ExplainTable implements ResultIterators { } catch (StaleRegionBoundaryCacheException e2) { // Catch only to try to recover from region boundary cache being out of date List<List<Pair<Scan,Future<PeekingResultIterator>>>> newFutures = Lists.newArrayListWithExpectedSize(2); if (!clearedCache) { // Clear cache once so that we rejigger job based on new boundaries - services.clearTableRegionCache(physicalTable.getName().getBytes()); + services.clearTableRegionCache(physicalTableName); clearedCache = true; } // Resubmit just this portion of work again http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java index 2b4a109..3ae0e81 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java @@ -39,6 +39,7 @@ import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTableType; import org.apache.phoenix.schema.Sequence; import org.apache.phoenix.schema.SequenceKey; +import org.apache.phoenix.schema.stats.PTableStats; public interface ConnectionQueryServices extends QueryServices, MetaDataMutated { @@ -104,4 +105,9 @@ public interface ConnectionQueryServices extends QueryServices, MetaDataMutated public String getUserName(); public void incrementTableTimeStamp(final byte[] tenantId, final byte[] schemaName, final byte[] tableName, long clientTS) throws SQLException; + + public PTableStats getTableStats(String physicalName); + public void addTableStats(String physicalName, PTableStats tableStats); + + public void clearCache() throws SQLException; } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java index 7b8d79c..478ce69 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java @@ -36,6 +36,7 @@ import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import javax.annotation.concurrent.GuardedBy; @@ -103,6 +104,7 @@ import org.apache.phoenix.schema.Sequence; import org.apache.phoenix.schema.SequenceKey; import org.apache.phoenix.schema.TableAlreadyExistsException; import org.apache.phoenix.schema.TableNotFoundException; +import org.apache.phoenix.schema.stats.PTableStats; import org.apache.phoenix.util.ByteUtil; import org.apache.phoenix.util.Closeables; import org.apache.phoenix.util.MetaDataUtil; @@ -116,6 +118,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Throwables; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -124,13 +128,15 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement private static final Logger logger = LoggerFactory.getLogger(ConnectionQueryServicesImpl.class); private static final int INITIAL_CHILD_SERVICES_CAPACITY = 100; private static final int DEFAULT_OUT_OF_ORDER_MUTATIONS_WAIT_TIME_MS = 1000; + // Max number of cached table stats for view or shared index physical tables + private static final int MAX_TABLE_STATS_CACHE_ENTRIES = 512; protected final Configuration config; // Copy of config.getProps(), but read-only to prevent synchronization that we // don't need. private final ReadOnlyProps props; private final String userName; private final ConcurrentHashMap<ImmutableBytesWritable,ConnectionQueryServices> childServices; - + private final Cache<String, PTableStats> tableStatsCache; // Cache the latest meta data here for future connections // writes guarded by "latestMetaDataLock" private volatile PMetaData latestMetaData; @@ -189,6 +195,13 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement // find the HBase version and use that to determine the KeyValueBuilder that should be used String hbaseVersion = VersionInfo.getVersion(); this.kvBuilder = KeyValueBuilder.get(hbaseVersion); + long halfStatsUpdateFreq = config.getLong( + QueryServices.STATS_UPDATE_FREQ_MS_ATTRIB, + QueryServicesOptions.DEFAULT_STATS_UPDATE_FREQ_MS) / 2; + tableStatsCache = CacheBuilder.newBuilder() + .maximumSize(MAX_TABLE_STATS_CACHE_ENTRIES) + .expireAfterWrite(halfStatsUpdateFreq, TimeUnit.MILLISECONDS) + .build(); } private void openConnection() throws SQLException { @@ -281,6 +294,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement } } finally { try { + tableStatsCache.invalidateAll(); super.close(); } catch (SQLException e) { if (sqlE == null) { @@ -1035,6 +1049,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement if (dropMetadata) { dropTables(result.getTableNamesToDelete()); } + invalidateTables(result.getTableNamesToDelete()); if (tableType == PTableType.TABLE) { byte[] physicalTableName = SchemaUtil.getTableNameAsBytes(schemaBytes, tableBytes); long timestamp = MetaDataUtil.getClientTimeStamp(tableMetaData); @@ -1047,6 +1062,14 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement return result; } + private void invalidateTables(final List<byte[]> tableNamesToDelete) { + if (tableNamesToDelete != null) { + for (byte[] tableName : tableNamesToDelete) { + tableStatsCache.invalidate(Bytes.toString(tableName)); + } + } + } + private void dropTables(final List<byte[]> tableNamesToDelete) throws SQLException { HBaseAdmin admin = null; SQLException sqlE = null; @@ -1224,6 +1247,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement if (dropMetadata) { dropTables(result.getTableNamesToDelete()); } + invalidateTables(result.getTableNamesToDelete()); break; default: break; @@ -1388,7 +1412,8 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement * Clears the Phoenix meta data cache on each region server * @throws SQLException */ - protected void clearCache() throws SQLException { + @Override + public void clearCache() throws SQLException { try { SQLException sqlE = null; HTableInterface htable = this.getTable(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES); @@ -1407,6 +1432,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement sqlE = new SQLException(e); } finally { try { + tableStatsCache.invalidateAll(); htable.close(); } catch (IOException e) { if (sqlE == null) { @@ -1829,6 +1855,8 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement sqlE = new SQLException(e); } finally { try { + if (tenantId.length == 0) + tableStatsCache.invalidate(SchemaUtil.getTableName(schemaName, tableName)); htable.close(); } catch (IOException e) { if (sqlE == null) { @@ -1844,4 +1872,13 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement throw new SQLException(ServerUtil.parseServerException(e)); } } + @Override + public PTableStats getTableStats(String physicalName) { + return tableStatsCache.getIfPresent(physicalName); + } + + @Override + public void addTableStats(String physicalName, PTableStats tableStats) { + tableStatsCache.put(physicalName, tableStats); + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java index 3e4643f..dd0cf54 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java @@ -65,6 +65,7 @@ import org.apache.phoenix.schema.SequenceKey; import org.apache.phoenix.schema.SequenceNotFoundException; import org.apache.phoenix.schema.TableAlreadyExistsException; import org.apache.phoenix.schema.TableNotFoundException; +import org.apache.phoenix.schema.stats.PTableStats; import org.apache.phoenix.util.MetaDataUtil; import org.apache.phoenix.util.PhoenixRuntime; import org.apache.phoenix.util.PropertiesUtil; @@ -413,4 +414,17 @@ public class ConnectionlessQueryServicesImpl extends DelegateQueryServices imple public String getUserName() { return userName; } + + @Override + public PTableStats getTableStats(String physicalName) { + return PTableStats.EMPTY_STATS; + } + + @Override + public void addTableStats(String physicalName, PTableStats tableStats) { + } + + @Override + public void clearCache() throws SQLException { + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java index 86523fd..2bcacc6 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java @@ -41,6 +41,7 @@ import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTableType; import org.apache.phoenix.schema.Sequence; import org.apache.phoenix.schema.SequenceKey; +import org.apache.phoenix.schema.stats.PTableStats; public class DelegateConnectionQueryServices extends DelegateQueryServices implements ConnectionQueryServices { @@ -232,4 +233,19 @@ public class DelegateConnectionQueryServices extends DelegateQueryServices imple throws SQLException { getDelegate().incrementTableTimeStamp(tenantId, schemaName, tableName, clientTS); } + + @Override + public PTableStats getTableStats(String physicalName) { + return getDelegate().getTableStats(physicalName); + } + + @Override + public void addTableStats(String physicalName, PTableStats tableStats) { + getDelegate().addTableStats(physicalName, tableStats); + } + + @Override + public void clearCache() throws SQLException { + getDelegate().clearCache(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/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 3a0fa63..ecf4818 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 @@ -123,6 +123,7 @@ public interface QueryServices extends SQLCloseable { public static final String STATS_UPDATE_FREQ_MS_ATTRIB = "phoenix.stats.updateFrequency"; public static final String MIN_STATS_UPDATE_FREQ_MS_ATTRIB = "phoenix.stats.minUpdateFrequency"; public static final String STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB = "phoenix.stats.guidepost.width"; + public static final String STATS_GUIDEPOST_PER_REGION_ATTRIB = "phoenix.stats.guidepost.per.region"; /** * Get executor service used for parallel scans http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/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 467aae1..5fdf165 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 @@ -130,6 +130,7 @@ public class QueryServicesOptions { public static final long DEFAULT_STATS_HISTOGRAM_DEPTH_BYTE = 1024 * 1024 * 30; public static final int DEFAULT_STATS_UPDATE_FREQ_MS = 15 * 60000; // 15min + public static final int DEFAULT_GUIDE_POSTS_PER_REGION = 20; public static final int DEFAULT_MIN_STATS_UPDATE_FREQ_MS = DEFAULT_STATS_UPDATE_FREQ_MS/2; private final Configuration config; @@ -184,7 +185,6 @@ public class QueryServicesOptions { .setIfUnset(GROUPBY_SPILL_FILES_ATTRIB, DEFAULT_GROUPBY_SPILL_FILES) .setIfUnset(SEQUENCE_CACHE_SIZE_ATTRIB, DEFAULT_SEQUENCE_CACHE_SIZE) .setIfUnset(SCAN_RESULT_CHUNK_SIZE, DEFAULT_SCAN_RESULT_CHUNK_SIZE) - .setIfUnset(STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, DEFAULT_STATS_HISTOGRAM_DEPTH_BYTE); ; // HBase sets this to 1, so we reset it to something more appropriate. // Hopefully HBase will change this, because we can't know if a user set http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/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 8bb91b4..b0549d2 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 @@ -86,6 +86,7 @@ import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Delete; +import org.apache.hadoop.hbase.client.HTableInterface; import org.apache.hadoop.hbase.client.Mutation; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Scan; @@ -130,10 +131,13 @@ import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; import org.apache.phoenix.schema.PTable.LinkType; import org.apache.phoenix.schema.PTable.ViewType; +import org.apache.phoenix.schema.stats.PTableStats; +import org.apache.phoenix.schema.stats.StatisticsUtil; 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.ReadOnlyProps; import org.apache.phoenix.util.SchemaUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -292,13 +296,19 @@ public class MetaDataClient { public MetaDataMutationResult updateCache(String schemaName, String tableName) throws SQLException { return updateCache(schemaName, tableName, false); } - + + private long getClientTimeStamp() { + Long scn = connection.getSCN(); + long clientTimeStamp = scn == null ? HConstants.LATEST_TIMESTAMP : scn; + return clientTimeStamp; + } + private MetaDataMutationResult updateCache(PName tenantId, String schemaName, String tableName, boolean alwaysHitServer) throws SQLException { + long clientTimeStamp = getClientTimeStamp(); Long scn = connection.getSCN(); boolean systemTable = SYSTEM_CATALOG_SCHEMA.equals(schemaName); // System tables must always have a null tenantId tenantId = systemTable ? null : tenantId; - long clientTimeStamp = scn == null ? HConstants.LATEST_TIMESTAMP : scn; PTable table = null; String fullTableName = SchemaUtil.getTableName(schemaName, tableName); long tableTimestamp = HConstants.LATEST_TIMESTAMP; @@ -474,11 +484,11 @@ public class MetaDataClient { 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 - final long msMinBetweenUpdates = connection - .getQueryServices() - .getProps() + ReadOnlyProps props = connection.getQueryServices().getProps(); + final long msMinBetweenUpdates = props .getLong(QueryServices.MIN_STATS_UPDATE_FREQ_MS_ATTRIB, - QueryServicesOptions.DEFAULT_MIN_STATS_UPDATE_FREQ_MS); + props.getLong(QueryServices.STATS_UPDATE_FREQ_MS_ATTRIB, + QueryServicesOptions.DEFAULT_STATS_UPDATE_FREQ_MS) / 2); ColumnResolver resolver = FromCompiler.getResolver(updateStatisticsStmt, connection); PTable table = resolver.getTables().get(0).getTable(); List<PTable> indexes = table.getIndexes(); @@ -2194,4 +2204,59 @@ public class MetaDataClient { .build().buildException(); } } + + public PTableStats getTableStats(PTable table) throws SQLException { + boolean isView = table.getType() == PTableType.VIEW; + boolean isSharedIndex = table.getViewIndexId() != null; + if (!isView && !isSharedIndex) { + return table.getTableStats(); + } + String physicalName = table.getPhysicalName().getString(); + // If we have a VIEW or a local or view INDEX, check our cache rather + // than updating the cache for that table to prevent an extra roundtrip. + PTableStats tableStats = connection.getQueryServices().getTableStats(physicalName); + if (tableStats != null) { + return tableStats; + } + if (isView) { + String physicalSchemaName = SchemaUtil.getSchemaNameFromFullName(physicalName); + String physicalTableName = SchemaUtil.getTableNameFromFullName(physicalName); + MetaDataMutationResult result = updateCache(null, /* use global tenant id to get physical table */ + physicalSchemaName, physicalTableName); + PTable physicalTable = result.getTable(); + if(physicalTable == null) { + // We should be able to find the physical table, as we found the logical one + // Might mean the physical table as just deleted. + logger.warn("Unable to retrieve physical table " + physicalName + " for table " + table.getName().getString()); + throw new TableNotFoundException(table.getSchemaName().getString(),table.getTableName().getString()); + } + tableStats = physicalTable.getTableStats(); + } else { + /* + * Otherwise, we have a shared view. This case is tricky, because we don't have + * table metadata for it, only an HBase table. We do have stats, though, so we'll + * query them directly here and cache them so we don't keep querying for them. + */ + HTableInterface statsHTable = connection.getQueryServices().getTable(PhoenixDatabaseMetaData.SYSTEM_STATS_NAME_BYTES); + try { + long clientTimeStamp = getClientTimeStamp(); + tableStats = StatisticsUtil.readStatistics(statsHTable, table.getPhysicalName().getBytes(), clientTimeStamp); + } catch (IOException e) { + logger.warn("Unable to read from stats table", e); + // Just cache empty stats. We'll try again after some time anyway. + tableStats = PTableStats.EMPTY_STATS; + } finally { + try { + statsHTable.close(); + } catch (IOException e) { + // Log, but continue. We have our stats anyway now. + logger.warn("Unable to close stats table", e); + } + } + } + // Cache these stats so that we don't keep making a roundrip just to get the stats (as + // they don't change very often. + connection.getQueryServices().addTableStats(physicalName, tableStats); + return tableStats; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java.orig ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java.orig b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java.orig index 9b744e1..8bb91b4 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java.orig +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java.orig @@ -36,11 +36,14 @@ 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; @@ -59,8 +62,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; @@ -79,9 +84,12 @@ import java.util.Set; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Mutation; import org.apache.hadoop.hbase.client.Put; +import org.apache.hadoop.hbase.client.Scan; +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.io.TimeRange; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; @@ -90,6 +98,8 @@ import org.apache.phoenix.compile.FromCompiler; import org.apache.phoenix.compile.MutationPlan; import org.apache.phoenix.compile.PostDDLCompiler; import org.apache.phoenix.compile.PostIndexDDLCompiler; +import org.apache.phoenix.compile.QueryPlan; +import org.apache.phoenix.coprocessor.BaseScannerRegionObserver; import org.apache.phoenix.coprocessor.MetaDataProtocol; import org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult; import org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode; @@ -98,6 +108,7 @@ import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.execute.MutationState; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; +import org.apache.phoenix.jdbc.PhoenixStatement; import org.apache.phoenix.parse.AddColumnStatement; import org.apache.phoenix.parse.AlterIndexStatement; import org.apache.phoenix.parse.ColumnDef; @@ -113,6 +124,7 @@ 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.QueryConstants; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.query.QueryServicesOptions; @@ -260,7 +272,16 @@ public class MetaDataClient { MetaDataMutationResult result = updateCache(schemaName, tableName, true); return result.getMutationTime(); } - + + private MetaDataMutationResult updateCache(String schemaName, String tableName, boolean alwaysHitServer) + throws SQLException { + return updateCache(connection.getTenantId(), schemaName, tableName, alwaysHitServer); + } + + public MetaDataMutationResult updateCache(PName tenantId, String schemaName, String tableName) throws SQLException { + return updateCache(tenantId, schemaName, tableName, false); + } + /** * Update the cache with the latest as of the connection scn. * @param schemaName @@ -272,11 +293,11 @@ public class MetaDataClient { return updateCache(schemaName, tableName, false); } - private MetaDataMutationResult updateCache(String schemaName, String tableName, boolean alwaysHitServer) throws SQLException { // TODO: pass byte[] here + private MetaDataMutationResult updateCache(PName tenantId, String schemaName, String tableName, boolean alwaysHitServer) throws SQLException { Long scn = connection.getSCN(); boolean systemTable = SYSTEM_CATALOG_SCHEMA.equals(schemaName); // System tables must always have a null tenantId - PName tenantId = systemTable ? null : connection.getTenantId(); + tenantId = systemTable ? null : tenantId; long clientTimeStamp = scn == null ? HConstants.LATEST_TIMESTAMP : scn; PTable table = null; String fullTableName = SchemaUtil.getTableName(schemaName, tableName); @@ -450,6 +471,72 @@ 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 + final long msMinBetweenUpdates = connection + .getQueryServices() + .getProps() + .getLong(QueryServices.MIN_STATS_UPDATE_FREQ_MS_ATTRIB, + QueryServicesOptions.DEFAULT_MIN_STATS_UPDATE_FREQ_MS); + ColumnResolver resolver = FromCompiler.getResolver(updateStatisticsStmt, connection); + PTable table = resolver.getTables().get(0).getTable(); + List<PTable> indexes = table.getIndexes(); + List<PTable> tables = Lists.newArrayListWithExpectedSize(1 + indexes.size()); + if (updateStatisticsStmt.updateColumns()) { + tables.add(table); + } + if (updateStatisticsStmt.updateIndex()) { + tables.addAll(indexes); + } + for(PTable pTable : tables) { + updateStatisticsInternal(msMinBetweenUpdates, pTable); + } + return new MutationState(1, connection); + } + + private MutationState updateStatisticsInternal(long msMinBetweenUpdates, PTable table) throws SQLException { + PName physicalName = table.getPhysicalName(); + byte[] tenantIdBytes = ByteUtil.EMPTY_BYTE_ARRAY; + Long scn = connection.getSCN(); + // Always invalidate the cache + long clientTS = connection.getSCN() == null ? HConstants.LATEST_TIMESTAMP : scn; + String query = "SELECT CURRENT_DATE() - " + LAST_STATS_UPDATE_TIME + " FROM " + PhoenixDatabaseMetaData.SYSTEM_STATS_NAME + + " WHERE " + PHYSICAL_NAME + "='" + physicalName.getString() + "' AND " + COLUMN_FAMILY + + " IS NULL AND " + REGION_NAME + " IS NULL AND " + LAST_STATS_UPDATE_TIME + " IS NOT NULL"; + ResultSet rs = connection.createStatement().executeQuery(query); + long msSinceLastUpdate = Long.MAX_VALUE; + if (rs.next()) { + msSinceLastUpdate = rs.getLong(1); + } + if (msSinceLastUpdate >= msMinBetweenUpdates) { + // Here create the select query. + String countQuery = "SELECT /*+ NO_CACHE NO_INDEX */ count(*) FROM " + table.getName().getString(); + PhoenixStatement statement = (PhoenixStatement) connection.createStatement(); + QueryPlan plan = statement.compileQuery(countQuery); + Scan scan = plan.getContext().getScan(); + // Add all CF in the table + scan.getFamilyMap().clear(); + for (PColumnFamily family : table.getColumnFamilies()) { + scan.addFamily(family.getName().getBytes()); + } + scan.setAttribute(BaseScannerRegionObserver.ANALYZE_TABLE, PDataType.TRUE_BYTES); + KeyValue kv = plan.iterator().next().getValue(0); + ImmutableBytesWritable tempPtr = plan.getContext().getTempPtr(); + tempPtr.set(kv.getValue()); + // A single Cell will be returned with the count(*) - we decode that here + long rowCount = PDataType.LONG.getCodec().decodeLong(tempPtr, SortOrder.getDefault()); + // We need to update the stats table so that client will pull the new one with + // the updated stats. + connection.getQueryServices().incrementTableTimeStamp(tenantIdBytes, + Bytes.toBytes(SchemaUtil.getSchemaNameFromFullName(physicalName.getString())), + Bytes.toBytes(SchemaUtil.getTableNameFromFullName(physicalName.getString())), clientTS); + return new MutationState(0, connection, rowCount); + } 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. @@ -792,7 +879,6 @@ public class MetaDataClient { String parentTableName = null; PName tenantId = connection.getTenantId(); String tenantIdStr = tenantId == null ? null : connection.getTenantId().getString(); - boolean isParentImmutableRows = false; boolean multiTenant = false; Integer saltBucketNum = null; String defaultFamilyName = null; @@ -814,7 +900,6 @@ public class MetaDataClient { } multiTenant = parent.isMultiTenant(); - isParentImmutableRows = parent.isImmutableRows(); parentTableName = parent.getTableName().getString(); // Pass through data table sequence number so we can check it hasn't changed PreparedStatement incrementStatement = connection.prepareStatement(INCREMENT_SEQ_NUM); @@ -905,9 +990,7 @@ public class MetaDataClient { boolean disableWAL = false; Boolean disableWALProp = (Boolean) tableProps.remove(PhoenixDatabaseMetaData.DISABLE_WAL); - if (disableWALProp == null) { - disableWAL = isParentImmutableRows; // By default, disable WAL for immutable indexes - } else { + if (disableWALProp != null) { disableWAL = disableWALProp; } // Delay this check as it is supported to have IMMUTABLE_ROWS and SALT_BUCKETS defined on views @@ -1112,6 +1195,7 @@ public class MetaDataClient { // Bootstrapping for our SYSTEM.TABLE that creates itself before it exists if (SchemaUtil.isMetaTable(schemaName,tableName)) { + // TODO: what about stats for system catalog? PTable table = PTableImpl.makePTable(tenantId,PNameFactory.newName(schemaName), PNameFactory.newName(tableName), tableType, null, MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM, PNameFactory.newName(QueryConstants.SYSTEM_TABLE_PK_NAME), null, columns, null, Collections.<PTable>emptyList(), @@ -1320,7 +1404,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 { @@ -1378,13 +1463,14 @@ public class MetaDataClient { tableRefs.add(new TableRef(null, viewIndexTable, ts, false)); } } + // Delete everything in the column. You'll still be able to do queries at earlier timestamps + tableRefs.add(new TableRef(null, table, ts, false)); + // TODO: Let the standard mutable secondary index maintenance handle this? + for (PTable index: table.getIndexes()) { + tableRefs.add(new TableRef(null, index, ts, false)); + } + deleteFromStatsTable(tableRefs, ts); if (!dropMetaData) { - // Delete everything in the column. You'll still be able to do queries at earlier timestamps - tableRefs.add(new TableRef(null, table, ts, false)); - // TODO: Let the standard mutable secondary index maintenance handle this? - for (PTable index: table.getIndexes()) { - tableRefs.add(new TableRef(null, index, ts, false)); - } MutationPlan plan = new PostDDLCompiler(connection).compile(tableRefs, null, null, Collections.<PColumn>emptyList(), ts); return connection.getQueryServices().updateData(plan); } @@ -1396,6 +1482,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(); http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamily.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamily.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamily.java index 01c236f..c5fe9b1 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamily.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamily.java @@ -18,7 +18,6 @@ package org.apache.phoenix.schema; import java.util.Collection; -import java.util.List; /** * @@ -53,5 +52,4 @@ public interface PColumnFamily { int getEstimatedSize(); - List<byte[]> getGuidePosts(); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamilyImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamilyImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamilyImpl.java index 9841233..2e29656 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamilyImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnFamilyImpl.java @@ -17,7 +17,6 @@ */ package org.apache.phoenix.schema; -import java.util.Collections; import java.util.List; import java.util.Map; @@ -35,7 +34,6 @@ public class PColumnFamilyImpl implements PColumnFamily { private final Map<String, PColumn> columnByString; private final Map<byte[], PColumn> columnByBytes; private final int estimatedSize; - private List<byte[]> guidePosts = Collections.emptyList(); @Override public int getEstimatedSize() { @@ -43,22 +41,10 @@ public class PColumnFamilyImpl implements PColumnFamily { } public PColumnFamilyImpl(PName name, List<PColumn> columns) { - this(name, columns, null); - } - - public PColumnFamilyImpl(PName name, List<PColumn> columns, List<byte[]> guidePosts) { Preconditions.checkNotNull(name); // Include guidePosts also in estimating the size long estimatedSize = SizedUtil.OBJECT_SIZE + SizedUtil.POINTER_SIZE * 5 + SizedUtil.INT_SIZE + name.getEstimatedSize() + SizedUtil.sizeOfMap(columns.size()) * 2 + SizedUtil.sizeOfArrayList(columns.size()); - if(guidePosts != null) { - int guidePostsSize = guidePosts.size(); - estimatedSize += SizedUtil.sizeOfArrayList(guidePostsSize); - for(byte[] gps : guidePosts) { - estimatedSize += gps.length; - } - this.guidePosts = guidePosts; - } this.name = name; this.columns = ImmutableList.copyOf(columns); ImmutableMap.Builder<String, PColumn> columnByStringBuilder = ImmutableMap.builder(); @@ -100,9 +86,4 @@ public class PColumnFamilyImpl implements PColumnFamily { } return column; } - - @Override - public List<byte[]> getGuidePosts() { - return guidePosts; - } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java index 2d11c22..a766d1e 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java @@ -217,13 +217,6 @@ public interface PTable extends Writable { */ int newKey(ImmutableBytesWritable key, byte[][] values); - /** - * Return the statistics table associated with this PTable. A list of - * guide posts are return - * @return the statistics table. - */ - List<byte[]> getGuidePosts(); - RowKeySchema getRowKeySchema(); /** http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java index 0bcd7a8..007abd2 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java @@ -111,7 +111,6 @@ public class PTableImpl implements PTable { private ViewType viewType; private Short viewIndexId; private int estimatedSize; - private List<byte[]> guidePosts = Collections.emptyList(); private PTableStats tableStats = PTableStats.EMPTY_STATS; public PTableImpl() { @@ -353,24 +352,13 @@ public class PTableImpl implements PTable { estimatedSize += rowKeySchema.getEstimatedSize(); Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator(); PColumnFamily[] families = new PColumnFamily[familyMap.size()]; - if (families.length == 0) { - byte[] defaultFamilyNameBytes = (defaultFamilyName == null) ? QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES : defaultFamilyName.getBytes(); - List<byte[]> guidePosts = stats.getGuidePosts().get(defaultFamilyNameBytes); - if (guidePosts != null) { - this.guidePosts = guidePosts; - estimatedSize += SizedUtil.sizeOfArrayList(guidePosts.size()); - for (byte[] gps : guidePosts) { - estimatedSize += gps.length; - } - } - } + estimatedSize += this.tableStats.getEstimatedSize(); ImmutableMap.Builder<String, PColumnFamily> familyByString = ImmutableMap.builder(); ImmutableSortedMap.Builder<byte[], PColumnFamily> familyByBytes = ImmutableSortedMap .orderedBy(Bytes.BYTES_COMPARATOR); for (int i = 0; i < families.length; i++) { Map.Entry<PName,List<PColumn>> entry = iterator.next(); - List<byte[]> famGuidePosts = stats.getGuidePosts().get(entry.getKey().getBytes()); - PColumnFamily family = new PColumnFamilyImpl(entry.getKey(), entry.getValue(), famGuidePosts); + PColumnFamily family = new PColumnFamilyImpl(entry.getKey(), entry.getValue()); families[i] = family; familyByString.put(family.getName().getString(), family); familyByBytes.put(family.getName().getBytes(), family); @@ -719,11 +707,6 @@ public class PTableImpl implements PTable { } @Override - public List<byte[]> getGuidePosts() { - return guidePosts; - } - - @Override public void readFields(DataInput input) throws IOException { byte[] tenantIdBytes = Bytes.readByteArray(input); byte[] schemaNameBytes = Bytes.readByteArray(input); http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStats.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStats.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStats.java index d0f9ecb..d902cb9 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStats.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/PTableStats.java @@ -53,6 +53,11 @@ public interface PTableStats extends Writable { public void readFields(DataInput arg0) throws IOException { throw new UnsupportedOperationException(); } + + @Override + public int getEstimatedSize() { + return 0; + } }; /** @@ -61,4 +66,6 @@ public interface PTableStats extends Writable { * @return */ SortedMap<byte[], List<byte[]>> getGuidePosts(); + + int getEstimatedSize(); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/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 c3e1803..159fb79 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 @@ -21,12 +21,14 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.SortedMap; import java.util.TreeMap; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.io.WritableUtils; +import org.apache.phoenix.util.SizedUtil; import com.google.common.collect.Lists; import com.sun.istack.NotNull; @@ -37,6 +39,7 @@ import com.sun.istack.NotNull; */ public class PTableStatsImpl implements PTableStats { private final SortedMap<byte[], List<byte[]>> guidePosts; + private final int estimatedSize; public PTableStatsImpl() { this(new TreeMap<byte[], List<byte[]>>(Bytes.BYTES_COMPARATOR)); @@ -44,6 +47,17 @@ public class PTableStatsImpl implements PTableStats { public PTableStatsImpl(@NotNull SortedMap<byte[], List<byte[]>> guidePosts) { this.guidePosts = guidePosts; + int estimatedSize = SizedUtil.OBJECT_SIZE + SizedUtil.INT_SIZE + SizedUtil.sizeOfTreeMap(guidePosts.size()); + for (Map.Entry<byte[], List<byte[]>> entry : guidePosts.entrySet()) { + byte[] cf = entry.getKey(); + estimatedSize += SizedUtil.ARRAY_SIZE + cf.length; + List<byte[]> keys = entry.getValue(); + estimatedSize += SizedUtil.sizeOfArrayList(keys.size()); + for (byte[] key : keys) { + estimatedSize += SizedUtil.ARRAY_SIZE + key.length; + } + } + this.estimatedSize = estimatedSize; } @Override @@ -77,4 +91,31 @@ public class PTableStatsImpl implements PTableStats { guidePosts.put(key, value); } } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + buf.append("PTableStats ["); + for (Map.Entry<byte[], List<byte[]>> entry : guidePosts.entrySet()) { + buf.append(Bytes.toStringBinary(entry.getKey())); + buf.append(":("); + List<byte[]> keys = entry.getValue(); + if (!keys.isEmpty()) { + for (byte[] key : keys) { + buf.append(Bytes.toStringBinary(key)); + buf.append(","); + } + buf.setLength(buf.length()-1); + } + buf.append(")"); + } + buf.append("]"); + return buf.toString(); + } + + @Override + public int getEstimatedSize() { + return estimatedSize; + } + } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsCollector.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsCollector.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsCollector.java index a5eb387..29706c7 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsCollector.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/stats/StatisticsCollector.java @@ -59,15 +59,19 @@ public class StatisticsCollector { // Ensures that either analyze or compaction happens at any point of time. private static final Log LOG = LogFactory.getLog(StatisticsCollector.class); - public StatisticsCollector(RegionCoprocessorEnvironment env, String tableName, long clientTimeStamp) throws IOException { + public StatisticsCollector(RegionCoprocessorEnvironment env, String tableName, long clientTimeStamp) + throws IOException { + Configuration config = env.getConfiguration(); + HTableInterface statsHTable = env.getTable((PhoenixDatabaseMetaData.SYSTEM_STATS_NAME_BYTES)); guidepostDepth = - env.getConfiguration().getLong(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, - QueryServicesOptions.DEFAULT_STATS_HISTOGRAM_DEPTH_BYTE); + config.getLong(QueryServices.STATS_GUIDEPOST_WIDTH_BYTES_ATTRIB, + statsHTable.getTableDescriptor().getMaxFileSize() / + config.getInt(QueryServices.STATS_GUIDEPOST_PER_REGION_ATTRIB, + QueryServicesOptions.DEFAULT_GUIDE_POSTS_PER_REGION)); // Get the stats table associated with the current table on which the CP is // triggered - HTableInterface statsHTable = env.getTable(PhoenixDatabaseMetaData.SYSTEM_STATS_NAME_BYTES); - this.statsTable = StatisticsWriter.getStatisticsTable(statsHTable, tableName, clientTimeStamp); + this.statsTable = StatisticsWriter.newWriter(statsHTable, tableName, clientTimeStamp); } public void close() throws IOException { http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/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 60e607c..5bf39c5 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 @@ -38,7 +38,8 @@ import org.apache.phoenix.util.TimeKeeper; * Wrapper to access the statistics table SYSTEM.STATS using the HTable. */ public class StatisticsWriter implements Closeable { - public static StatisticsWriter getStatisticsTable(HTableInterface hTable, String tableName, long clientTimeStamp) throws IOException { + public static StatisticsWriter newWriter(HTableInterface hTable, String tableName, long clientTimeStamp) + throws IOException { if (clientTimeStamp == HConstants.LATEST_TIMESTAMP) { clientTimeStamp = TimeKeeper.SYSTEM.getCurrentTime(); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/phoenix-core/src/main/java/org/apache/phoenix/util/SizedUtil.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/SizedUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/SizedUtil.java index c49b0e7..f82c1b8 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/SizedUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/SizedUtil.java @@ -38,6 +38,7 @@ public class SizedUtil { public static final int INT_SIZE = 4; public static final int LONG_SIZE = 8; + public static final int TREE_MAP_SIZE = OBJECT_SIZE + INT_SIZE * 2 + POINTER_SIZE * 2; public static final int MAP_ENTRY_SIZE = OBJECT_SIZE + 3 * POINTER_SIZE + INT_SIZE; public static final int IMMUTABLE_BYTES_WRITABLE_SIZE = OBJECT_SIZE + INT_SIZE * 2 + ARRAY_SIZE; public static final int IMMUTABLE_BYTES_PTR_SIZE = IMMUTABLE_BYTES_WRITABLE_SIZE + INT_SIZE;// Extra is an int field which caches hashcode. @@ -52,6 +53,10 @@ public class SizedUtil { private SizedUtil() { } + public static int sizeOfTreeMap(int size) { + return TREE_MAP_SIZE + (OBJECT_SIZE + INT_SIZE + POINTER_SIZE * 5) * size; + } + public static int sizeOfArrayList(int capacity) { return SizedUtil.OBJECT_SIZE + SizedUtil.POINTER_SIZE + SizedUtil.INT_SIZE + SizedUtil.ARRAY_SIZE + SizedUtil.POINTER_SIZE * capacity; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/a5b79722/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 e4295ff..16845e8 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 @@ -52,7 +52,6 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl { public static final long DEFAULT_MAX_SERVER_METADATA_CACHE_SIZE = 1024L*1024L*4L; // 4 Mb public static final long DEFAULT_MAX_CLIENT_METADATA_CACHE_SIZE = 1024L*1024L*2L; // 2 Mb - public static final long DEFAULT_STATS_HISTOGRAM_DEPTH_BYTES = 2000; public static final int DEFAULT_MIN_STATS_UPDATE_FREQ_MS = 0; public QueryServicesTestImpl(ReadOnlyProps defaultProps) { @@ -62,7 +61,6 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl { private static QueryServicesOptions getDefaultServicesOptions() { return withDefaults() .setMinStatsUpdateFrequencyMs(DEFAULT_MIN_STATS_UPDATE_FREQ_MS) - .setStatsHistogramDepthBytes(DEFAULT_STATS_HISTOGRAM_DEPTH_BYTES) .setThreadPoolSize(DEFAULT_THREAD_POOL_SIZE) .setQueueSize(DEFAULT_QUEUE_SIZE) .setMaxMemoryPerc(DEFAULT_MAX_MEMORY_PERC)