From 0c73baa3123252915198b6cca56dd68cd74ba366 Mon Sep 17 00:00:00 2001 From: anastas Date: Sun, 20 Aug 2017 16:35:33 +0300 Subject: [PATCH] HBASE-18232: Adding a possibility to create chunks of jumbo size to be used when we need to save very big cell on the MSLAB chunk --- .../apache/hadoop/hbase/regionserver/Chunk.java | 13 ++++- .../hadoop/hbase/regionserver/ChunkCreator.java | 68 +++++++++++++++++----- .../hbase/regionserver/ImmutableMemStoreLAB.java | 12 ++++ .../hadoop/hbase/regionserver/MemStoreLAB.java | 7 +++ .../hadoop/hbase/regionserver/MemStoreLABImpl.java | 17 ++++++ .../hadoop/hbase/regionserver/OffheapChunk.java | 4 +- .../hadoop/hbase/regionserver/OnheapChunk.java | 4 +- 7 files changed, 104 insertions(+), 21 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/Chunk.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/Chunk.java index 8743923..144fd3a 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/Chunk.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/Chunk.java @@ -54,6 +54,9 @@ public abstract class Chunk { // indicates if the chunk is formed by ChunkCreator#MemstorePool private final boolean fromPool; + // indicates whether the chunk is bigger then a normal predefined chunk size + private final boolean jumbo; + /** * Create an uninitialized chunk. Note that memory is not allocated yet, so * this is cheap. @@ -61,7 +64,7 @@ public abstract class Chunk { * @param id the chunk id */ public Chunk(int size, int id) { - this(size, id, false); + this(size, id, false, false); } /** @@ -70,11 +73,13 @@ public abstract class Chunk { * @param size in bytes * @param id the chunk id * @param fromPool if the chunk is formed by pool + * @param jumbo */ - public Chunk(int size, int id, boolean fromPool) { + public Chunk(int size, int id, boolean fromPool, boolean jumbo) { this.size = size; this.id = id; this.fromPool = fromPool; + this.jumbo = jumbo; } int getId() { @@ -85,6 +90,10 @@ public abstract class Chunk { return this.fromPool; } + boolean isJumbo() { + return this.jumbo; + } + /** * Actually claim the memory for this chunk. This should only be called from the thread that * constructed the chunk. It is thread-safe against other threads calling alloc(), who will block diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ChunkCreator.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ChunkCreator.java index e818426..c1c7f77 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ChunkCreator.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ChunkCreator.java @@ -18,7 +18,6 @@ */ package org.apache.hadoop.hbase.regionserver; -import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; @@ -47,6 +46,7 @@ import org.apache.hadoop.hbase.shaded.com.google.common.util.concurrent.ThreadFa @InterfaceAudience.Private public class ChunkCreator { private static final Log LOG = LogFactory.getLog(ChunkCreator.class); + private static final int PREDEFINED_CHUNK_SIZE = -1; // monotonically increasing chunkid private AtomicInteger chunkID = new AtomicInteger(1); // maps the chunk against the monotonically increasing chunk id. We need to preserve the @@ -110,17 +110,27 @@ public class ChunkCreator { * @return the chunk that was initialized */ Chunk getChunk() { - return getChunk(CompactingMemStore.IndexType.ARRAY_MAP); + return getChunk(CompactingMemStore.IndexType.ARRAY_MAP, PREDEFINED_CHUNK_SIZE); + } + + /** + * Creates and inits a chunk. The default implementation for specific index type. + * @return the chunk that was initialized + */ + Chunk getChunk(CompactingMemStore.IndexType chunkIndexType) { + return getChunk(chunkIndexType, PREDEFINED_CHUNK_SIZE); } /** * Creates and inits a chunk. * @return the chunk that was initialized * @param chunkIndexType whether the requested chunk is going to be used with CellChunkMap index + * @param size */ - Chunk getChunk(CompactingMemStore.IndexType chunkIndexType) { + Chunk getChunk(CompactingMemStore.IndexType chunkIndexType, int size) { Chunk chunk = null; - if (pool != null) { + // if we have pool and this is not jumbo chunk + if ((pool != null) && (size == PREDEFINED_CHUNK_SIZE)) { // the pool creates the chunk internally. The chunk#init() call happens here chunk = this.pool.getChunk(); // the pool has run out of maxCount @@ -134,7 +144,7 @@ public class ChunkCreator { if (chunk == null) { // the second boolean parameter means: // if CellChunkMap index is requested, put allocated on demand chunk mapping into chunkIdMap - chunk = createChunk(false, chunkIndexType); + chunk = createChunk(false, chunkIndexType, size); } // now we need to actually do the expensive memory allocation step in case of a new chunk, @@ -144,20 +154,40 @@ public class ChunkCreator { } /** + * Creates and inits a chunk of a special size, bigger than a regular chunk size. + * Such a chunk will never come from pool and will always be on demand allocated. + * @return the chunk that was initialized + * @param chunkIndexType whether the requested chunk is going to be used with CellChunkMap index + * @param jumboSize the special size to be used + */ + Chunk getJumboChunk(CompactingMemStore.IndexType chunkIndexType, int jumboSize) { + if (jumboSize <= chunkSize) { + throw new IllegalArgumentException(" Illegal jumbo chunk size: " + + jumboSize + " must be more than regular chunk size " + chunkSize); + } + return getChunk(chunkIndexType, jumboSize); + } + + /** * Creates the chunk either onheap or offheap * @param pool indicates if the chunks have to be created which will be used by the Pool * @param chunkIndexType + * @param size * @return the chunk */ - private Chunk createChunk(boolean pool, CompactingMemStore.IndexType chunkIndexType) { + private Chunk createChunk(boolean pool, CompactingMemStore.IndexType chunkIndexType, int size) { Chunk chunk = null; int id = chunkID.getAndIncrement(); assert id > 0; // do not create offheap chunk on demand if (pool && this.offheap) { - chunk = new OffheapChunk(chunkSize, id, pool); + chunk = + new OffheapChunk(((size == PREDEFINED_CHUNK_SIZE)?chunkSize:size), + id, pool, (size != PREDEFINED_CHUNK_SIZE)); } else { - chunk = new OnheapChunk(chunkSize, id, pool); + chunk = + new OnheapChunk(((size == PREDEFINED_CHUNK_SIZE)?chunkSize:size), + id, pool, (size != PREDEFINED_CHUNK_SIZE)); } if (pool || (chunkIndexType == CompactingMemStore.IndexType.CHUNK_MAP)) { // put the pool chunk into the chunkIdMap so it is not GC-ed @@ -166,6 +196,12 @@ public class ChunkCreator { return chunk; } + // Chunks from pool are created covered with strong references anyway + // TODO: change to CHUNK_MAP if it is generally defined + private Chunk createChunkForPool() { + return createChunk(true, CompactingMemStore.IndexType.ARRAY_MAP, chunkSize); + } + @VisibleForTesting // Used to translate the ChunkID into a chunk ref Chunk getChunk(int id) { @@ -227,9 +263,7 @@ public class ChunkCreator { this.poolSizePercentage = poolSizePercentage; this.reclaimedChunks = new LinkedBlockingQueue<>(); for (int i = 0; i < initialCount; i++) { - // Chunks from pool are covered with strong references anyway - // TODO: change to CHUNK_MAP if it is generally defined - Chunk chunk = createChunk(true, CompactingMemStore.IndexType.ARRAY_MAP); + Chunk chunk = createChunkForPool(); chunk.init(); reclaimedChunks.add(chunk); } @@ -261,8 +295,7 @@ public class ChunkCreator { long created = this.chunkCount.get(); if (created < this.maxCount) { if (this.chunkCount.compareAndSet(created, created + 1)) { - // TODO: change to CHUNK_MAP if it is generally defined - chunk = createChunk(true, CompactingMemStore.IndexType.ARRAY_MAP); + createChunkForPool(); break; } } else { @@ -365,7 +398,7 @@ public class ChunkCreator { return null; } if (poolSizePercentage > 1.0) { - throw new IllegalArgumentException( + new IllegalArgumentException( MemStoreLAB.CHUNK_POOL_MAXSIZE_KEY + " must be between 0.0 and 1.0"); } int maxCount = (int) (globalMemStoreSize * poolSizePercentage / getChunkSize()); @@ -432,7 +465,12 @@ public class ChunkCreator { // translate chunk ID to chunk, if chunk initially wasn't in pool // this translation will (most likely) return null Chunk chunk = ChunkCreator.this.getChunk(chunkID); - if (chunk != null) { + + // Jumbo chunks are covered with chunkIdMap, but are not from pool, so should be released here + // without going to pool. Removing them from chunkIdMap will cause their removal by the GC. + if (chunk.isJumbo()) { + this.removeChunk(chunkID); + } else if (chunk != null) { pool.putbackChunks(chunk); } // if chunk is null, it was never covered by the chunkIdMap (and so wasn't in pool also), diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ImmutableMemStoreLAB.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ImmutableMemStoreLAB.java index 9bc0fd4..6ef1ca4 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ImmutableMemStoreLAB.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ImmutableMemStoreLAB.java @@ -54,6 +54,18 @@ public class ImmutableMemStoreLAB implements MemStoreLAB { return mslab.getNewExternalChunk(); } + /** + * Return a new empty, special chunk which size is bigger than regular chunks, + * without considering this chunk as current + * The space on this chunk will be allocated externally + * + * @param size + */ + @Override public Chunk getNewExternalJumboChunk(int size) { + MemStoreLAB mslab = this.mslabs.get(0); + return mslab.getNewExternalJumboChunk(size); + } + @Override public void close() { // 'openScannerCount' here tracks the scanners opened on segments which directly refer to this diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLAB.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLAB.java index 7f0e549..65b3e9f 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLAB.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLAB.java @@ -89,6 +89,13 @@ public interface MemStoreLAB { */ Chunk getNewExternalChunk(); + /** + * Return a new empty, special chunk which size is bigger than regular chunks, + * without considering this chunk as current + * The space on this chunk will be allocated externally + */ + Chunk getNewExternalJumboChunk(int size); + public static MemStoreLAB newInstance(Configuration conf) { MemStoreLAB memStoreLAB = null; if (isEnabled(conf)) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLABImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLABImpl.java index 2ae665e..1305fd7 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLABImpl.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreLABImpl.java @@ -271,6 +271,23 @@ public class MemStoreLABImpl implements MemStoreLAB { return c; } + /* Creating chunk to be used as data chunk in CellChunkMap. + ** This chunk is bigger the normal constant chunk size, and thus called JumboChunk it is used for + ** jumbo cells (which size is bigger than normal chunks). + ** Returning a new chunk, without replacing current chunk, + ** meaning MSLABImpl does not make the returned chunk as CurChunk. + ** The space on this chunk will be allocated externally. + ** The interface is only for external callers + */ + @Override + public Chunk getNewExternalJumboChunk(int size) { + // the new chunk is going to hold the jumbo cell data and need to be referenced by a strong map + // thus giving the CCM index type + Chunk c = this.chunkCreator.getChunk(CompactingMemStore.IndexType.CHUNK_MAP, size); + chunks.add(c.getId()); + return c; + } + @VisibleForTesting Chunk getCurrentChunk() { return this.curChunk.get(); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OffheapChunk.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OffheapChunk.java index f5d4905..289ea06 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OffheapChunk.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OffheapChunk.java @@ -32,8 +32,8 @@ public class OffheapChunk extends Chunk { super(size, id); } - OffheapChunk(int size, int id, boolean fromPool) { - super(size, id, fromPool); + OffheapChunk(int size, int id, boolean fromPool, boolean jumbo) { + super(size, id, fromPool, jumbo); assert fromPool == true; } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OnheapChunk.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OnheapChunk.java index 38001ea..a1508ba 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OnheapChunk.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/OnheapChunk.java @@ -31,8 +31,8 @@ public class OnheapChunk extends Chunk { super(size, id); } - OnheapChunk(int size, int id, boolean fromPool) { - super(size, id, fromPool); + OnheapChunk(int size, int id, boolean fromPool, boolean jumbo) { + super(size, id, fromPool, jumbo); } @Override -- 1.8.5.2 (Apple Git-48)