-
Notifications
You must be signed in to change notification settings - Fork 3.4k
HBASE-29669 Implement basic row cache #7901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: HBASE-29585
Are you sure you want to change the base?
Changes from 1 commit
61c0798
cd93c2f
95de81b
782dd75
267f4ef
1fc9d5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,8 @@ | |
| package org.apache.hadoop.hbase.regionserver; | ||
|
|
||
| import static org.apache.hadoop.hbase.HConstants.REPLICATION_SCOPE_LOCAL; | ||
| import static org.apache.hadoop.hbase.HConstants.ROW_CACHE_EVICT_ON_CLOSE_DEFAULT; | ||
| import static org.apache.hadoop.hbase.HConstants.ROW_CACHE_EVICT_ON_CLOSE_KEY; | ||
| import static org.apache.hadoop.hbase.regionserver.HStoreFile.MAJOR_COMPACTION_KEY; | ||
| import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.REGION_NAMES_KEY; | ||
| import static org.apache.hadoop.hbase.trace.HBaseSemanticAttributes.ROW_LOCK_READ_LOCK_KEY; | ||
|
|
@@ -145,6 +147,7 @@ | |
| import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache; | ||
| import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils; | ||
| import org.apache.hadoop.hbase.ipc.RpcCall; | ||
| import org.apache.hadoop.hbase.ipc.RpcCallContext; | ||
| import org.apache.hadoop.hbase.ipc.RpcServer; | ||
| import org.apache.hadoop.hbase.ipc.ServerCall; | ||
| import org.apache.hadoop.hbase.mob.MobFileCache; | ||
|
|
@@ -946,14 +949,19 @@ public HRegion(final HRegionFileSystem fs, final WAL wal, final Configuration co | |
| this.isRowCacheEnabled = checkRowCacheConfig(); | ||
| } | ||
|
|
||
| private boolean checkRowCacheConfig() { | ||
| boolean checkRowCacheConfig() { | ||
| Boolean fromDescriptor = htableDescriptor.getRowCacheEnabled(); | ||
| // The setting from TableDescriptor has higher priority than the global configuration | ||
| return fromDescriptor != null | ||
| ? fromDescriptor | ||
| : conf.getBoolean(HConstants.ROW_CACHE_ENABLED_KEY, HConstants.ROW_CACHE_ENABLED_DEFAULT); | ||
| } | ||
|
|
||
| // For testing only | ||
| void setRowCache(RowCache rowCache) { | ||
| this.rowCache = rowCache; | ||
| } | ||
|
|
||
| private void setHTableSpecificConf() { | ||
| if (this.htableDescriptor == null) { | ||
| return; | ||
|
|
@@ -1963,6 +1971,8 @@ public Pair<byte[], Collection<HStoreFile>> call() throws IOException { | |
| } | ||
| } | ||
|
|
||
| evictRowCache(); | ||
|
|
||
| status.setStatus("Writing region close event to WAL"); | ||
| // Always write close marker to wal even for read only table. This is not a big problem as we | ||
| // do not write any data into the region; it is just a meta edit in the WAL file. | ||
|
|
@@ -2003,6 +2013,22 @@ public Pair<byte[], Collection<HStoreFile>> call() throws IOException { | |
| } | ||
| } | ||
|
|
||
| private void evictRowCache() { | ||
| boolean evictOnClose = getReadOnlyConfiguration().getBoolean(ROW_CACHE_EVICT_ON_CLOSE_KEY, | ||
| ROW_CACHE_EVICT_ON_CLOSE_DEFAULT); | ||
|
|
||
| if (!evictOnClose) { | ||
| return; | ||
| } | ||
|
|
||
| if (!(rsServices instanceof HRegionServer regionServer)) { | ||
| return; | ||
| } | ||
|
|
||
| RowCache rowCache = regionServer.getRSRpcServices().getServer().getRowCache(); | ||
| rowCache.evictRowsByRegion(this); | ||
| } | ||
|
|
||
| /** Wait for all current flushes and compactions of the region to complete */ | ||
| // TODO HBASE-18906. Check the usage (if any) in Phoenix and expose this or give alternate way for | ||
| // Phoenix needs. | ||
|
|
@@ -3259,21 +3285,32 @@ public RegionScannerImpl getScanner(Scan scan) throws IOException { | |
| return getScanner(scan, null); | ||
| } | ||
|
|
||
| RegionScannerImpl getScannerWithResults(Get get, Scan scan, List<Cell> results) | ||
| throws IOException { | ||
| RegionScannerImpl getScannerWithResults(Get get, Scan scan, List<Cell> results, | ||
| RpcCallContext context) throws IOException { | ||
| if (!rowCache.canCacheRow(get, this)) { | ||
| return getScannerWithResults(scan, results); | ||
| } | ||
|
|
||
| // Try get from row cache | ||
| RowCacheKey key = new RowCacheKey(this, get.getRow()); | ||
| if (rowCache.tryGetFromCache(key, get, results)) { | ||
| addReadRequestsCount(1); | ||
| if (getMetrics() != null) { | ||
| getMetrics().updateReadRequestCount(); | ||
| } | ||
|
|
||
| // Cache is hit, and then no scanner is created | ||
| return null; | ||
| } | ||
|
|
||
| RegionScannerImpl scanner = getScannerWithResults(scan, results); | ||
| rowCache.populateCache(results, key); | ||
|
|
||
| // When results came from memstore only, do not populate the row cache | ||
| boolean readFromMemStoreOnly = context.getBlockBytesScanned() < 1; | ||
| if (!readFromMemStoreOnly) { | ||
| rowCache.populateCache(this, results, key); | ||
| } | ||
|
|
||
| return scanner; | ||
| } | ||
|
|
||
|
|
@@ -3435,6 +3472,15 @@ private void updateDeleteLatestVersionTimestamp(Cell cell, Get get, int count, b | |
| @Override | ||
| public void put(Put put) throws IOException { | ||
| TraceUtil.trace(() -> { | ||
| // Put with TTL is not allowed on tables with row cache enabled, because cached rows cannot | ||
| // track TTL expiration | ||
| if (isRowCacheEnabled) { | ||
| if (put.getTTL() != Long.MAX_VALUE) { | ||
| throw new DoNotRetryIOException( | ||
| "Tables with row cache enabled do not allow setting TTL on Puts"); | ||
| } | ||
| } | ||
|
Comment on lines
+3476
to
+3483
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't we simply implement TTL expiration within the RowCache.getRow logic? |
||
|
|
||
| checkReadOnly(); | ||
|
|
||
| // Do a rough check that we have resources to accept a write. The check is | ||
|
|
@@ -4811,7 +4857,12 @@ public OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic, long | |
| // checkAndMutate. | ||
| // * coprocessor calls (see ex. BulkDeleteEndpoint). | ||
| // So nonces are not really ever used by HBase. They could be by coprocs, and checkAnd... | ||
| return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce)); | ||
| if (rowCache == null) { | ||
| return batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce)); | ||
| } | ||
|
|
||
| return rowCache.mutateWithRowCacheBarrier(this, Arrays.asList(mutations), | ||
| () -> batchMutate(new MutationBatchOperation(this, mutations, atomic, nonceGroup, nonce))); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -4823,10 +4874,9 @@ public OperationStatus[] batchMutate(Mutation[] mutations) throws IOException { | |
| } | ||
|
|
||
| OperationStatus[] batchMutate(Mutation[] mutations, boolean atomic) throws IOException { | ||
| OperationStatus[] operationStatuses = | ||
| rowCache.mutateWithRowCacheBarrier(this, Arrays.asList(mutations), | ||
| () -> this.batchMutate(mutations, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE)); | ||
| return TraceUtil.trace(() -> operationStatuses, () -> createRegionSpan("Region.batchMutate")); | ||
| return TraceUtil.trace( | ||
| () -> batchMutate(mutations, atomic, HConstants.NO_NONCE, HConstants.NO_NONCE), | ||
| () -> createRegionSpan("Region.batchMutate")); | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -5111,8 +5161,17 @@ public CheckAndMutateResult checkAndMutate(CheckAndMutate checkAndMutate) throws | |
|
|
||
| public CheckAndMutateResult checkAndMutate(CheckAndMutate checkAndMutate, long nonceGroup, | ||
| long nonce) throws IOException { | ||
| CheckAndMutateResult checkAndMutateResult = rowCache.mutateWithRowCacheBarrier(this, | ||
| checkAndMutate.getRow(), () -> this.checkAndMutate(checkAndMutate, nonceGroup, nonce)); | ||
| CheckAndMutateResult checkAndMutateResult = | ||
| rowCache.mutateWithRowCacheBarrier(this, checkAndMutate.getRow(), | ||
| () -> this.checkAndMutateInternal(checkAndMutate, nonceGroup, nonce)); | ||
| return TraceUtil.trace(() -> checkAndMutateResult, | ||
| () -> createRegionSpan("Region.checkAndMutate")); | ||
| } | ||
|
|
||
| public CheckAndMutateResult checkAndMutate(List<Mutation> mutations, | ||
| CheckAndMutate checkAndMutate, long nonceGroup, long nonce) throws IOException { | ||
| CheckAndMutateResult checkAndMutateResult = rowCache.mutateWithRowCacheBarrier(this, mutations, | ||
| () -> this.checkAndMutateInternal(checkAndMutate, nonceGroup, nonce)); | ||
| return TraceUtil.trace(() -> checkAndMutateResult, | ||
| () -> createRegionSpan("Region.checkAndMutate")); | ||
| } | ||
|
|
@@ -5312,6 +5371,10 @@ private OperationStatus mutate(Mutation mutation, boolean atomic) throws IOExcep | |
|
|
||
| private OperationStatus mutate(Mutation mutation, boolean atomic, long nonceGroup, long nonce) | ||
| throws IOException { | ||
| if (rowCache == null) { | ||
| return this.mutateInternal(mutation, atomic, nonceGroup, nonce); | ||
| } | ||
|
|
||
| return rowCache.mutateWithRowCacheBarrier(this, mutation.getRow(), | ||
| () -> this.mutateInternal(mutation, atomic, nonceGroup, nonce)); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,6 +69,7 @@ class MetricsRegionServerWrapperImpl implements MetricsRegionServerWrapper { | |
| private BlockCache l2Cache = null; | ||
| private MobFileCache mobFileCache; | ||
| private CacheStats cacheStats; | ||
| private final RowCache rowCache; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better move to L71 under
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, moved rowCache field next to MobFileCache. (782dd75) |
||
| private CacheStats l1Stats = null; | ||
| private CacheStats l2Stats = null; | ||
| private volatile long numWALFiles = 0; | ||
|
|
@@ -99,6 +100,8 @@ public MetricsRegionServerWrapperImpl(final HRegionServer regionServer) { | |
| this.regionServer = regionServer; | ||
| initBlockCache(); | ||
| initMobFileCache(); | ||
| RSRpcServices rsRpcServices = this.regionServer.getRSRpcServices(); | ||
| this.rowCache = rsRpcServices == null ? null : rsRpcServices.getServer().getRowCache(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. better to use a method
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, extracted initRowCache() method. (782dd75) |
||
| this.excludeDatanodeManager = this.regionServer.getWalFactory().getExcludeDatanodeManager(); | ||
|
|
||
| this.period = regionServer.getConfiguration().getLong(HConstants.REGIONSERVER_METRICS_PERIOD, | ||
|
|
@@ -1194,6 +1197,31 @@ public long getTrailerHitCount() { | |
| return this.cacheStats != null ? this.cacheStats.getTrailerHitCount() : 0L; | ||
| } | ||
|
|
||
| @Override | ||
| public long getRowCacheHitCount() { | ||
| return this.rowCache != null ? this.rowCache.getHitCount() : 0L; | ||
| } | ||
|
|
||
| @Override | ||
| public long getRowCacheMissCount() { | ||
| return this.rowCache != null ? this.rowCache.getMissCount() : 0L; | ||
| } | ||
|
|
||
| @Override | ||
| public long getRowCacheSize() { | ||
| return this.rowCache != null ? this.rowCache.getSize() : 0L; | ||
| } | ||
|
|
||
| @Override | ||
| public long getRowCacheCount() { | ||
| return this.rowCache != null ? this.rowCache.getCount() : 0L; | ||
| } | ||
|
|
||
| @Override | ||
| public long getRowCacheEvictedRowCount() { | ||
| return this.rowCache != null ? this.rowCache.getEvictedRowCount() : 0L; | ||
| } | ||
|
|
||
| @Override | ||
| public long getByteBuffAllocatorHeapAllocationBytes() { | ||
| return ByteBuffAllocator.getHeapAllocationBytes(allocator, ByteBuffAllocator.HEAP); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -668,7 +668,7 @@ private CheckAndMutateResult checkAndMutate(HRegion region, List<ClientProtos.Ac | |
| result = region.getCoprocessorHost().preCheckAndMutate(checkAndMutate); | ||
| } | ||
| if (result == null) { | ||
| result = region.checkAndMutate(checkAndMutate, nonceGroup, nonce); | ||
| result = region.checkAndMutate(mutations, checkAndMutate, nonceGroup, nonce); | ||
| if (region.getCoprocessorHost() != null) { | ||
| result = region.getCoprocessorHost().postCheckAndMutate(checkAndMutate, result); | ||
| } | ||
|
|
@@ -2347,8 +2347,21 @@ public BulkLoadHFileResponse bulkLoadHFile(final RpcController controller, | |
| return bulkLoadHFileInternal(request); | ||
| } | ||
|
|
||
| // TODO: implement row cache logic for bulk load | ||
| return bulkLoadHFileInternal(request); | ||
| RowCache rowCache = region.getRegionServerServices().getRowCache(); | ||
|
|
||
| // Since bulkload modifies the store files, the row cache should be disabled until the bulkload | ||
| // is finished. | ||
| rowCache.createRegionLevelBarrier(region); | ||
| try { | ||
| // We do not invalidate the entire row cache directly, as it contains a large number of | ||
| // entries and takes a long time. Instead, we increment rowCacheSeqNum, which is used when | ||
| // constructing a RowCacheKey, thereby making the existing row cache entries stale. | ||
| rowCache.increaseRowCacheSeqNum(region); | ||
| return bulkLoadHFileInternal(request); | ||
| } finally { | ||
| // The row cache for the region has been enabled again | ||
| rowCache.removeTableLevelBarrier(region); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, renamed to removeRegionLevelBarrier. (95de81b) |
||
| } | ||
| } | ||
|
|
||
| BulkLoadHFileResponse bulkLoadHFileInternal(final BulkLoadHFileRequest request) | ||
|
|
@@ -2609,7 +2622,7 @@ private Result get(Get get, HRegion region, RegionScannersCloseCallBack closeCal | |
| RegionScannerImpl scanner = null; | ||
| long blockBytesScannedBefore = context.getBlockBytesScanned(); | ||
| try { | ||
| scanner = region.getScannerWithResults(get, scan, results); | ||
| scanner = region.getScannerWithResults(get, scan, results, context); | ||
| } finally { | ||
| if (scanner != null) { | ||
| if (closeCallBack == null) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For testing only, we could use
@RestrictedApiannotation?Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, added @RestrictedApi annotation. (267f4ef)