Skip to content

Commit 9a469ae

Browse files
comnetworkApache9
authored andcommitted
HBASE-26142 NullPointerException when set 'hbase.hregion.memstore.mslab.indexchunksize.percent' to zero (#3531)
Signed-off-by: Duo Zhang <zhangduo@apache.org>
1 parent 27b0c41 commit 9a469ae

File tree

6 files changed

+255
-51
lines changed

6 files changed

+255
-51
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/Chunk.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import java.nio.ByteBuffer;
2121
import java.util.concurrent.atomic.AtomicInteger;
22+
23+
import org.apache.hadoop.hbase.regionserver.ChunkCreator.ChunkType;
2224
import org.apache.hadoop.hbase.util.Bytes;
2325
import org.apache.yetus.audience.InterfaceAudience;
2426

@@ -49,6 +51,8 @@ public abstract class Chunk {
4951
// The unique id associated with the chunk.
5052
private final int id;
5153

54+
private final ChunkType chunkType;
55+
5256
// indicates if the chunk is formed by ChunkCreator#MemstorePool
5357
private final boolean fromPool;
5458

@@ -58,8 +62,8 @@ public abstract class Chunk {
5862
* @param size in bytes
5963
* @param id the chunk id
6064
*/
61-
public Chunk(int size, int id) {
62-
this(size, id, false);
65+
public Chunk(int size, int id, ChunkType chunkType) {
66+
this(size, id, chunkType, false);
6367
}
6468

6569
/**
@@ -69,26 +73,35 @@ public Chunk(int size, int id) {
6973
* @param id the chunk id
7074
* @param fromPool if the chunk is formed by pool
7175
*/
72-
public Chunk(int size, int id, boolean fromPool) {
76+
public Chunk(int size, int id, ChunkType chunkType, boolean fromPool) {
7377
this.size = size;
7478
this.id = id;
79+
this.chunkType = chunkType;
7580
this.fromPool = fromPool;
7681
}
7782

7883
int getId() {
7984
return this.id;
8085
}
8186

87+
ChunkType getChunkType() {
88+
return this.chunkType;
89+
}
90+
8291
boolean isFromPool() {
8392
return this.fromPool;
8493
}
8594

8695
boolean isJumbo() {
87-
return size > ChunkCreator.getInstance().getChunkSize();
96+
return chunkType == ChunkCreator.ChunkType.JUMBO_CHUNK;
8897
}
8998

9099
boolean isIndexChunk() {
91-
return size == ChunkCreator.getInstance().getChunkSize(ChunkCreator.ChunkType.INDEX_CHUNK);
100+
return chunkType == ChunkCreator.ChunkType.INDEX_CHUNK;
101+
}
102+
103+
boolean isDataChunk() {
104+
return chunkType == ChunkCreator.ChunkType.DATA_CHUNK;
92105
}
93106

94107
/**

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ChunkCreator.java

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public enum ChunkType {
7777
static boolean chunkPoolDisabled = false;
7878
private MemStoreChunkPool dataChunksPool;
7979
private final int chunkSize;
80+
private int indexChunkSize;
8081
private MemStoreChunkPool indexChunksPool;
8182

8283
ChunkCreator(int chunkSize, boolean offheap, long globalMemStoreSize, float poolSizePercentage,
@@ -94,13 +95,14 @@ private void initializePools(int chunkSize, long globalMemStoreSize,
9495
HeapMemoryManager heapMemoryManager) {
9596
this.dataChunksPool = initializePool("data", globalMemStoreSize,
9697
(1 - indexChunkSizePercentage) * poolSizePercentage,
97-
initialCountPercentage, chunkSize, heapMemoryManager);
98+
initialCountPercentage, chunkSize, ChunkType.DATA_CHUNK, heapMemoryManager);
9899
// The index chunks pool is needed only when the index type is CCM.
99100
// Since the pools are not created at all when the index type isn't CCM,
100101
// we don't need to check it here.
102+
this.indexChunkSize = (int) (indexChunkSizePercentage * chunkSize);
101103
this.indexChunksPool = initializePool("index", globalMemStoreSize,
102104
indexChunkSizePercentage * poolSizePercentage,
103-
initialCountPercentage, (int) (indexChunkSizePercentage * chunkSize),
105+
initialCountPercentage, this.indexChunkSize, ChunkType.INDEX_CHUNK,
104106
heapMemoryManager);
105107
}
106108

@@ -163,14 +165,20 @@ Chunk getChunk(CompactingMemStore.IndexType chunkIndexType) {
163165
Chunk getChunk(CompactingMemStore.IndexType chunkIndexType, ChunkType chunkType) {
164166
switch (chunkType) {
165167
case INDEX_CHUNK:
166-
if (indexChunksPool != null) {
167-
return getChunk(chunkIndexType, indexChunksPool.getChunkSize());
168+
if (indexChunksPool == null) {
169+
if (indexChunkSize <= 0) {
170+
throw new IllegalArgumentException(
171+
"chunkType is INDEX_CHUNK but indexChunkSize is:[" + this.indexChunkSize + "]");
172+
}
173+
return getChunk(chunkIndexType, chunkType, indexChunkSize);
174+
} else {
175+
return getChunk(chunkIndexType, chunkType, indexChunksPool.getChunkSize());
168176
}
169177
case DATA_CHUNK:
170178
if (dataChunksPool == null) {
171-
return getChunk(chunkIndexType, chunkSize);
179+
return getChunk(chunkIndexType, chunkType, chunkSize);
172180
} else {
173-
return getChunk(chunkIndexType, dataChunksPool.getChunkSize());
181+
return getChunk(chunkIndexType, chunkType, dataChunksPool.getChunkSize());
174182
}
175183
default:
176184
throw new IllegalArgumentException(
@@ -184,14 +192,14 @@ Chunk getChunk(CompactingMemStore.IndexType chunkIndexType, ChunkType chunkType)
184192
* @param chunkIndexType whether the requested chunk is going to be used with CellChunkMap index
185193
* @param size the size of the chunk to be allocated, in bytes
186194
*/
187-
Chunk getChunk(CompactingMemStore.IndexType chunkIndexType, int size) {
195+
Chunk getChunk(CompactingMemStore.IndexType chunkIndexType, ChunkType chunkType, int size) {
188196
Chunk chunk = null;
189197
MemStoreChunkPool pool = null;
190198

191-
// if the size is suitable for one of the pools
192-
if (dataChunksPool != null && size == dataChunksPool.getChunkSize()) {
199+
// if it is one of the pools
200+
if (dataChunksPool != null && chunkType == ChunkType.DATA_CHUNK) {
193201
pool = dataChunksPool;
194-
} else if (indexChunksPool != null && size == indexChunksPool.getChunkSize()) {
202+
} else if (indexChunksPool != null && chunkType == ChunkType.INDEX_CHUNK) {
195203
pool = indexChunksPool;
196204
}
197205

@@ -211,7 +219,7 @@ Chunk getChunk(CompactingMemStore.IndexType chunkIndexType, int size) {
211219
if (chunk == null) {
212220
// the second parameter explains whether CellChunkMap index is requested,
213221
// in that case, put allocated on demand chunk mapping into chunkIdMap
214-
chunk = createChunk(false, chunkIndexType, size);
222+
chunk = createChunk(false, chunkIndexType, chunkType, size);
215223
}
216224

217225
// now we need to actually do the expensive memory allocation step in case of a new chunk,
@@ -228,14 +236,15 @@ Chunk getChunk(CompactingMemStore.IndexType chunkIndexType, int size) {
228236
*/
229237
Chunk getJumboChunk(int jumboSize) {
230238
int allocSize = jumboSize + SIZEOF_CHUNK_HEADER;
231-
if (allocSize <= dataChunksPool.getChunkSize()) {
239+
240+
if (allocSize <= this.getChunkSize(ChunkType.DATA_CHUNK)) {
232241
LOG.warn("Jumbo chunk size " + jumboSize + " must be more than regular chunk size "
233-
+ dataChunksPool.getChunkSize() + ". Converting to regular chunk.");
242+
+ this.getChunkSize(ChunkType.DATA_CHUNK) + ". Converting to regular chunk.");
234243
return getChunk(CompactingMemStore.IndexType.CHUNK_MAP);
235244
}
236245
// the new chunk is going to hold the jumbo cell data and needs to be referenced by
237246
// a strong map. Therefore the CCM index type
238-
return getChunk(CompactingMemStore.IndexType.CHUNK_MAP, allocSize);
247+
return getChunk(CompactingMemStore.IndexType.CHUNK_MAP, ChunkType.JUMBO_CHUNK, allocSize);
239248
}
240249

241250
/**
@@ -245,15 +254,16 @@ Chunk getJumboChunk(int jumboSize) {
245254
* @param size the size of the chunk to be allocated, in bytes
246255
* @return the chunk
247256
*/
248-
private Chunk createChunk(boolean pool, CompactingMemStore.IndexType chunkIndexType, int size) {
257+
private Chunk createChunk(boolean pool, CompactingMemStore.IndexType chunkIndexType,
258+
ChunkType chunkType, int size) {
249259
Chunk chunk = null;
250260
int id = chunkID.getAndIncrement();
251261
assert id > 0;
252262
// do not create offheap chunk on demand
253263
if (pool && this.offheap) {
254-
chunk = new OffheapChunk(size, id, pool);
264+
chunk = new OffheapChunk(size, id, chunkType, pool);
255265
} else {
256-
chunk = new OnheapChunk(size, id, pool);
266+
chunk = new OnheapChunk(size, id, chunkType, pool);
257267
}
258268
if (pool || (chunkIndexType == CompactingMemStore.IndexType.CHUNK_MAP)) {
259269
// put the pool chunk into the chunkIdMap so it is not GC-ed
@@ -264,12 +274,13 @@ private Chunk createChunk(boolean pool, CompactingMemStore.IndexType chunkIndexT
264274

265275
// Chunks from pool are created covered with strong references anyway
266276
// TODO: change to CHUNK_MAP if it is generally defined
267-
private Chunk createChunkForPool(CompactingMemStore.IndexType chunkIndexType, int chunkSize) {
277+
private Chunk createChunkForPool(CompactingMemStore.IndexType chunkIndexType, ChunkType chunkType,
278+
int chunkSize) {
268279
if (chunkSize != dataChunksPool.getChunkSize() &&
269280
chunkSize != indexChunksPool.getChunkSize()) {
270281
return null;
271282
}
272-
return createChunk(true, chunkIndexType, chunkSize);
283+
return createChunk(true, chunkIndexType, chunkType, chunkSize);
273284
}
274285

275286
// Used to translate the ChunkID into a chunk ref
@@ -309,6 +320,7 @@ void clearChunkIds() {
309320
*/
310321
private class MemStoreChunkPool implements HeapMemoryTuneObserver {
311322
private final int chunkSize;
323+
private final ChunkType chunkType;
312324
private int maxCount;
313325

314326
// A queue of reclaimed chunks
@@ -323,15 +335,18 @@ private class MemStoreChunkPool implements HeapMemoryTuneObserver {
323335
private final LongAdder reusedChunkCount = new LongAdder();
324336
private final String label;
325337

326-
MemStoreChunkPool(String label, int chunkSize, int maxCount, int initialCount,
338+
MemStoreChunkPool(String label, int chunkSize, ChunkType chunkType, int maxCount,
339+
int initialCount,
327340
float poolSizePercentage) {
328341
this.label = label;
329342
this.chunkSize = chunkSize;
343+
this.chunkType = chunkType;
330344
this.maxCount = maxCount;
331345
this.poolSizePercentage = poolSizePercentage;
332346
this.reclaimedChunks = new LinkedBlockingQueue<>();
333347
for (int i = 0; i < initialCount; i++) {
334-
Chunk chunk = createChunk(true, CompactingMemStore.IndexType.ARRAY_MAP, chunkSize);
348+
Chunk chunk =
349+
createChunk(true, CompactingMemStore.IndexType.ARRAY_MAP, chunkType, chunkSize);
335350
chunk.init();
336351
reclaimedChunks.add(chunk);
337352
}
@@ -367,7 +382,7 @@ Chunk getChunk(CompactingMemStore.IndexType chunkIndexType) {
367382
long created = this.chunkCount.get();
368383
if (created < this.maxCount) {
369384
if (this.chunkCount.compareAndSet(created, created + 1)) {
370-
chunk = createChunkForPool(chunkIndexType, chunkSize);
385+
chunk = createChunkForPool(chunkIndexType, chunkType, chunkSize);
371386
break;
372387
}
373388
} else {
@@ -465,7 +480,7 @@ static void clearDisableFlag() {
465480
}
466481

467482
private MemStoreChunkPool initializePool(String label, long globalMemStoreSize,
468-
float poolSizePercentage, float initialCountPercentage, int chunkSize,
483+
float poolSizePercentage, float initialCountPercentage, int chunkSize, ChunkType chunkType,
469484
HeapMemoryManager heapMemoryManager) {
470485
if (poolSizePercentage <= 0) {
471486
LOG.info("{} poolSizePercentage is less than 0. So not using pool", label);
@@ -486,8 +501,8 @@ private MemStoreChunkPool initializePool(String label, long globalMemStoreSize,
486501
int initialCount = (int) (initialCountPercentage * maxCount);
487502
LOG.info("Allocating {} MemStoreChunkPool with chunk size {}, max count {}, initial count {}",
488503
label, StringUtils.byteDesc(chunkSize), maxCount, initialCount);
489-
MemStoreChunkPool memStoreChunkPool = new MemStoreChunkPool(label, chunkSize, maxCount,
490-
initialCount, poolSizePercentage);
504+
MemStoreChunkPool memStoreChunkPool = new MemStoreChunkPool(label, chunkSize, chunkType,
505+
maxCount, initialCount, poolSizePercentage);
491506
if (heapMemoryManager != null && memStoreChunkPool != null) {
492507
// Register with Heap Memory manager
493508
heapMemoryManager.registerTuneObserver(memStoreChunkPool);
@@ -578,6 +593,8 @@ int getChunkSize(ChunkType chunkType) {
578593
case INDEX_CHUNK:
579594
if (indexChunksPool != null) {
580595
return indexChunksPool.getChunkSize();
596+
} else {
597+
return indexChunkSize;
581598
}
582599
case DATA_CHUNK:
583600
if (dataChunksPool != null) {
@@ -606,7 +623,7 @@ synchronized void putbackChunks(Set<Integer> chunks) {
606623
if (chunk != null) {
607624
if (chunk.isFromPool() && chunk.isIndexChunk()) {
608625
indexChunksPool.putbackChunks(chunk);
609-
} else if (chunk.isFromPool() && chunk.size == dataChunksPool.getChunkSize()) {
626+
} else if (chunk.isFromPool() && chunk.isDataChunk()) {
610627
dataChunksPool.putbackChunks(chunk);
611628
} else {
612629
// chunks which are not from one of the pools
@@ -621,5 +638,13 @@ synchronized void putbackChunks(Set<Integer> chunks) {
621638
return;
622639
}
623640

641+
MemStoreChunkPool getIndexChunksPool() {
642+
return this.indexChunksPool;
643+
}
644+
645+
MemStoreChunkPool getDataChunksPool() {
646+
return this.dataChunksPool;
647+
}
648+
624649
}
625650

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OffheapChunk.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.nio.ByteBuffer;
2121

22+
import org.apache.hadoop.hbase.regionserver.ChunkCreator.ChunkType;
2223
import org.apache.yetus.audience.InterfaceAudience;
2324

2425
/**
@@ -27,13 +28,13 @@
2728
@InterfaceAudience.Private
2829
public class OffheapChunk extends Chunk {
2930

30-
OffheapChunk(int size, int id) {
31+
OffheapChunk(int size, int id, ChunkType chunkType) {
3132
// better if this is always created fromPool. This should not be called
32-
super(size, id);
33+
super(size, id, chunkType);
3334
}
3435

35-
OffheapChunk(int size, int id, boolean fromPool) {
36-
super(size, id, fromPool);
36+
OffheapChunk(int size, int id, ChunkType chunkType, boolean fromPool) {
37+
super(size, id, chunkType, fromPool);
3738
assert fromPool == true;
3839
}
3940

hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OnheapChunk.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.nio.ByteBuffer;
2121

22+
import org.apache.hadoop.hbase.regionserver.ChunkCreator.ChunkType;
2223
import org.apache.yetus.audience.InterfaceAudience;
2324

2425
/**
@@ -27,12 +28,12 @@
2728
@InterfaceAudience.Private
2829
public class OnheapChunk extends Chunk {
2930

30-
OnheapChunk(int size, int id) {
31-
super(size, id);
31+
OnheapChunk(int size, int id, ChunkType chunkType) {
32+
super(size, id, chunkType);
3233
}
3334

34-
OnheapChunk(int size, int id, boolean fromPool) {
35-
super(size, id, fromPool);
35+
OnheapChunk(int size, int id, ChunkType chunkType, boolean fromPool) {
36+
super(size, id, chunkType, fromPool);
3637
}
3738

3839
@Override

hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestCellFlatSet.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.apache.hadoop.hbase.KeyValue;
3737
import org.apache.hadoop.hbase.KeyValueUtil;
3838
import org.apache.hadoop.hbase.io.util.MemorySizeUtil;
39+
import org.apache.hadoop.hbase.regionserver.ChunkCreator.ChunkType;
3940
import org.apache.hadoop.hbase.testclassification.RegionServerTests;
4041
import org.apache.hadoop.hbase.testclassification.SmallTests;
4142
import org.apache.hadoop.hbase.util.ByteBufferUtils;
@@ -330,7 +331,9 @@ private CellChunkMap setUpJumboCellChunkMap(boolean asc) {
330331
// allocate new chunks and use the data JUMBO chunk to hold the full data of the cells
331332
// and the normal index chunk to hold the cell-representations
332333
Chunk dataJumboChunk =
333-
chunkCreator.getChunk(CompactingMemStore.IndexType.CHUNK_MAP, smallChunkSize);
334+
chunkCreator.getChunk(CompactingMemStore.IndexType.CHUNK_MAP, ChunkType.JUMBO_CHUNK,
335+
smallChunkSize);
336+
assertTrue(dataJumboChunk.isJumbo());
334337
Chunk idxChunk = chunkCreator.getChunk(CompactingMemStore.IndexType.CHUNK_MAP);
335338
// the array of index chunks to be used as a basis for CellChunkMap
336339
Chunk[] chunkArray = new Chunk[8]; // according to test currently written 8 is way enough
@@ -364,7 +367,10 @@ private CellChunkMap setUpJumboCellChunkMap(boolean asc) {
364367

365368
// Jumbo chunks are working only with one cell per chunk, thus always allocate a new jumbo
366369
// data chunk for next cell
367-
dataJumboChunk = chunkCreator.getChunk(CompactingMemStore.IndexType.CHUNK_MAP,smallChunkSize);
370+
dataJumboChunk =
371+
chunkCreator.getChunk(CompactingMemStore.IndexType.CHUNK_MAP, ChunkType.JUMBO_CHUNK,
372+
smallChunkSize);
373+
assertTrue(dataJumboChunk.isJumbo());
368374
dataBuffer = dataJumboChunk.getData();
369375
dataOffset = ChunkCreator.SIZEOF_CHUNK_HEADER;
370376
}

0 commit comments

Comments
 (0)