Skip to content

Commit 872f13a

Browse files
committed
Add row-level cache for the get operation
1 parent 5629108 commit 872f13a

28 files changed

+2418
-34
lines changed

hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,4 +316,11 @@ default boolean matchReplicationScope(boolean enabled) {
316316
}
317317
return !enabled;
318318
}
319+
320+
/**
321+
* Checks whether row caching is enabled for this table. Note that row caching applies only at the
322+
* entire row level, not at the column family level.
323+
* @return {@code true} if row cache is enabled, otherwise {@code false}
324+
*/
325+
boolean isRowCacheEnabled();
319326
}

hbase-client/src/main/java/org/apache/hadoop/hbase/client/TableDescriptorBuilder.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,15 @@ public class TableDescriptorBuilder {
227227
private final static Map<String, String> DEFAULT_VALUES = new HashMap<>();
228228
private final static Set<Bytes> RESERVED_KEYWORDS = new HashSet<>();
229229

230+
/**
231+
* Used by HBase Shell interface to access this metadata attribute which denotes if the row cache
232+
* is enabled.
233+
*/
234+
@InterfaceAudience.Private
235+
public static final String ROW_CACHE_ENABLED = "ROW_CACHE_ENABLED";
236+
private static final Bytes ROW_CACHE_ENABLED_KEY = new Bytes(Bytes.toBytes(ROW_CACHE_ENABLED));
237+
private static final boolean DEFAULT_ROW_CACHE_ENABLED = false;
238+
230239
static {
231240
DEFAULT_VALUES.put(MAX_FILESIZE, String.valueOf(HConstants.DEFAULT_MAX_FILE_SIZE));
232241
DEFAULT_VALUES.put(READONLY, String.valueOf(DEFAULT_READONLY));
@@ -565,6 +574,11 @@ public TableDescriptor build() {
565574
return new ModifyableTableDescriptor(desc);
566575
}
567576

577+
public TableDescriptorBuilder setRowCacheEnabled(boolean rowCacheEnabled) {
578+
desc.setRowCacheEnabled(rowCacheEnabled);
579+
return this;
580+
}
581+
568582
private static final class ModifyableTableDescriptor
569583
implements TableDescriptor, Comparable<ModifyableTableDescriptor> {
570584

@@ -1510,6 +1524,15 @@ public Optional<String> getRegionServerGroup() {
15101524
return Optional.empty();
15111525
}
15121526
}
1527+
1528+
@Override
1529+
public boolean isRowCacheEnabled() {
1530+
return getOrDefault(ROW_CACHE_ENABLED_KEY, Boolean::valueOf, DEFAULT_ROW_CACHE_ENABLED);
1531+
}
1532+
1533+
public ModifyableTableDescriptor setRowCacheEnabled(boolean enabled) {
1534+
return setValue(ROW_CACHE_ENABLED_KEY, Boolean.toString(enabled));
1535+
}
15131536
}
15141537

15151538
/**

hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,14 @@ public enum OperationStatusCode {
10331033
public static final long HBASE_CLIENT_SCANNER_ONHEAP_BLOCK_CACHE_FIXED_SIZE_DEFAULT =
10341034
32 * 1024 * 1024L;
10351035

1036+
/**
1037+
* Configuration key for the minimum number of HFiles required to activate the Row Cache. If the
1038+
* number of HFiles is less than this value, the Row Cache does not operate even if it is enabled
1039+
* at the table level.
1040+
*/
1041+
public static final String ROW_CACHE_ACTIVATE_MIN_HFILES_KEY = "row.cache.activate.min.hfiles";
1042+
public static final int ROW_CACHE_ACTIVATE_MIN_HFILES_DEFAULT = 2;
1043+
10361044
/**
10371045
* Configuration key for setting pread must read both necessaryLen and extraLen, default is
10381046
* disabled. This is an optimized flag for reading HFile from blob storage.

hbase-common/src/main/java/org/apache/hadoop/hbase/io/encoding/BufferedDataBlockEncoder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,8 @@ public void setTimestamp(byte[] ts) throws IOException {
547547

548548
@Override
549549
public ExtendedCell deepClone() {
550-
// This is not used in actual flow. Throwing UnsupportedOperationException
551-
throw new UnsupportedOperationException();
550+
// To garbage collect the objects referenced by this cell, we need to deep clone it
551+
return ExtendedCell.super.deepClone();
552552
}
553553
}
554554

hbase-common/src/main/java/org/apache/hadoop/hbase/io/hfile/BlockType.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,14 @@ public int getId() {
8080
/** Fixed file trailer, both versions (always just a magic string) */
8181
TRAILER("TRABLK\"$", BlockCategory.META),
8282

83+
// Pseudo block
84+
85+
/**
86+
* Cells of a row for row cache. This is a pseudo block type. It only exists to share the
87+
* BlockCache interface.
88+
*/
89+
ROW_CELLS("ROWCELLS", BlockCategory.ROW),
90+
8391
// Legacy blocks
8492

8593
/** Block index magic string in version 1 */
@@ -91,6 +99,7 @@ public enum BlockCategory {
9199
INDEX,
92100
BLOOM,
93101
ALL_CATEGORIES,
102+
ROW,
94103
UNKNOWN;
95104

96105
/**

hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerSource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ public interface MetricsRegionServerSource extends BaseSource, JvmPauseMonitorSo
386386
String BLOCK_CACHE_GENERAL_BLOOM_META_MISS_COUNT = "blockCacheGeneralBloomMetaMissCount";
387387
String BLOCK_CACHE_DELETE_FAMILY_BLOOM_MISS_COUNT = "blockCacheDeleteFamilyBloomMissCount";
388388
String BLOCK_CACHE_TRAILER_MISS_COUNT = "blockCacheTrailerMissCount";
389+
String BLOCK_CACHE_ROW_MISS_COUNT = "blockCacheRowMissCount";
389390
String BLOCK_CACHE_DATA_HIT_COUNT = "blockCacheDataHitCount";
390391
String BLOCK_CACHE_ENCODED_DATA_HIT_COUNT = "blockCacheEncodedDataHitCount";
391392
String BLOCK_CACHE_LEAF_INDEX_HIT_COUNT = "blockCacheLeafIndexHitCount";
@@ -397,6 +398,7 @@ public interface MetricsRegionServerSource extends BaseSource, JvmPauseMonitorSo
397398
String BLOCK_CACHE_GENERAL_BLOOM_META_HIT_COUNT = "blockCacheGeneralBloomMetaHitCount";
398399
String BLOCK_CACHE_DELETE_FAMILY_BLOOM_HIT_COUNT = "blockCacheDeleteFamilyBloomHitCount";
399400
String BLOCK_CACHE_TRAILER_HIT_COUNT = "blockCacheTrailerHitCount";
401+
String BLOCK_CACHE_ROW_HIT_COUNT = "blockCacheRowHitCount";
400402
String L1_CACHE_FREE_SIZE = "l1CacheFreeSize";
401403
String L1_CACHE_FREE_SIZE_DESC = "Amount of free bytes in the L1 cache";
402404
String L1_CACHE_SIZE = "l1CacheSize";

hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerSourceImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ public void getMetrics(MetricsCollector metricsCollector, boolean all) {
436436
.addCounter(Interns.info(BLOCK_CACHE_DELETE_FAMILY_BLOOM_MISS_COUNT, ""),
437437
rsWrap.getDeleteFamilyBloomMissCount())
438438
.addCounter(Interns.info(BLOCK_CACHE_TRAILER_MISS_COUNT, ""), rsWrap.getTrailerMissCount())
439+
.addCounter(Interns.info(BLOCK_CACHE_ROW_MISS_COUNT, ""), rsWrap.getRowMissCount())
439440
.addCounter(Interns.info(BLOCK_CACHE_DATA_HIT_COUNT, ""), rsWrap.getDataHitCount())
440441
.addCounter(Interns.info(BLOCK_CACHE_LEAF_INDEX_HIT_COUNT, ""),
441442
rsWrap.getLeafIndexHitCount())
@@ -452,6 +453,7 @@ public void getMetrics(MetricsCollector metricsCollector, boolean all) {
452453
.addCounter(Interns.info(BLOCK_CACHE_DELETE_FAMILY_BLOOM_HIT_COUNT, ""),
453454
rsWrap.getDeleteFamilyBloomHitCount())
454455
.addCounter(Interns.info(BLOCK_CACHE_TRAILER_HIT_COUNT, ""), rsWrap.getTrailerHitCount())
456+
.addCounter(Interns.info(BLOCK_CACHE_ROW_HIT_COUNT, ""), rsWrap.getRowHitCount())
455457
.addCounter(Interns.info(UPDATES_BLOCKED_TIME, UPDATES_BLOCKED_DESC),
456458
rsWrap.getUpdatesBlockedTime())
457459
.addCounter(Interns.info(FLUSHED_CELLS, FLUSHED_CELLS_DESC), rsWrap.getFlushedCellsCount())

hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerWrapper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,8 @@ public interface MetricsRegionServerWrapper {
615615

616616
long getTrailerMissCount();
617617

618+
long getRowMissCount();
619+
618620
long getDataHitCount();
619621

620622
long getLeafIndexHitCount();
@@ -635,6 +637,8 @@ public interface MetricsRegionServerWrapper {
635637

636638
long getTrailerHitCount();
637639

640+
long getRowHitCount();
641+
638642
long getTotalRowActionRequestCount();
639643

640644
long getByteBuffAllocatorHeapAllocationBytes();

hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CacheStats.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public class CacheStats {
9191
private final LongAdder generalBloomMetaMissCount = new LongAdder();
9292
private final LongAdder deleteFamilyBloomMissCount = new LongAdder();
9393
private final LongAdder trailerMissCount = new LongAdder();
94+
private final LongAdder rowMissCount = new LongAdder();
9495

9596
private final LongAdder dataHitCount = new LongAdder();
9697
private final LongAdder leafIndexHitCount = new LongAdder();
@@ -102,6 +103,7 @@ public class CacheStats {
102103
private final LongAdder generalBloomMetaHitCount = new LongAdder();
103104
private final LongAdder deleteFamilyBloomHitCount = new LongAdder();
104105
private final LongAdder trailerHitCount = new LongAdder();
106+
private final LongAdder rowHitCount = new LongAdder();
105107

106108
// Executor for periodic cache stats rolling
107109
private ScheduledExecutorService metricsRollerScheduler;
@@ -219,6 +221,9 @@ public void miss(boolean caching, boolean primary, BlockType type) {
219221
case TRAILER:
220222
trailerMissCount.increment();
221223
break;
224+
case ROW_CELLS:
225+
rowMissCount.increment();
226+
break;
222227
default:
223228
// If there's a new type that's fine
224229
// Ignore it for now. This is metrics don't exception.
@@ -266,6 +271,9 @@ public void hit(boolean caching, boolean primary, BlockType type) {
266271
case TRAILER:
267272
trailerHitCount.increment();
268273
break;
274+
case ROW_CELLS:
275+
rowHitCount.increment();
276+
break;
269277
default:
270278
// If there's a new type that's fine
271279
// Ignore it for now. This is metrics don't exception.
@@ -376,6 +384,14 @@ public long getTrailerHitCount() {
376384
return trailerHitCount.sum();
377385
}
378386

387+
public long getRowHitCount() {
388+
return rowHitCount.sum();
389+
}
390+
391+
public long getRowMissCount() {
392+
return rowMissCount.sum();
393+
}
394+
379395
public long getRequestCount() {
380396
return getHitCount() + getMissCount();
381397
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.io.hfile;
19+
20+
import java.util.Arrays;
21+
import java.util.Objects;
22+
import org.apache.hadoop.hbase.regionserver.HRegion;
23+
import org.apache.hadoop.hbase.util.Bytes;
24+
import org.apache.hadoop.hbase.util.ClassSize;
25+
import org.apache.yetus.audience.InterfaceAudience;
26+
27+
/**
28+
* Cache Key for use with implementations of {@link BlockCache}
29+
*/
30+
@InterfaceAudience.Private
31+
public class RowCacheKey extends BlockCacheKey {
32+
private static final long serialVersionUID = -686874540957524887L;
33+
public static final long FIXED_OVERHEAD = ClassSize.estimateBase(RowCacheKey.class, false);
34+
35+
private final byte[] rowKey;
36+
// Row cache keys should not be evicted on close, since the cache may contain many entries and
37+
// eviction would be slow. Instead, the region’s rowCacheSeqNum is used to generate new keys that
38+
// ignore the existing cache when the region is reopened or bulk-loaded.
39+
private final long rowCacheSeqNum;
40+
41+
public RowCacheKey(HRegion region, byte[] rowKey) {
42+
super(region.getRegionInfo().getEncodedName(), 0, region.getRegionInfo().getReplicaId() == 0,
43+
BlockType.ROW_CELLS);
44+
45+
this.rowKey = Objects.requireNonNull(rowKey, "rowKey cannot be null");
46+
this.rowCacheSeqNum = region.getRowCacheSeqNum();
47+
}
48+
49+
@Override
50+
public boolean equals(Object o) {
51+
if (this == o) return true;
52+
if (o == null || getClass() != o.getClass()) return false;
53+
if (!super.equals(o)) return false;
54+
RowCacheKey that = (RowCacheKey) o;
55+
return rowCacheSeqNum == that.rowCacheSeqNum && Arrays.equals(rowKey, that.rowKey);
56+
}
57+
58+
@Override
59+
public int hashCode() {
60+
return Objects.hash(super.hashCode(), Arrays.hashCode(rowKey), Long.hashCode(rowCacheSeqNum));
61+
}
62+
63+
@Override
64+
public String toString() {
65+
return super.toString() + '_' + Bytes.toStringBinary(this.rowKey) + '_' + rowCacheSeqNum;
66+
}
67+
68+
@Override
69+
public long heapSize() {
70+
return FIXED_OVERHEAD + ClassSize.align(rowKey.length);
71+
}
72+
}

0 commit comments

Comments
 (0)