001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import org.apache.hadoop.conf.Configuration; 021import org.apache.hadoop.hbase.Cell; 022import org.apache.yetus.audience.InterfaceAudience; 023import org.apache.hadoop.hbase.util.ReflectionUtils; 024 025/** 026 * A memstore-local allocation buffer. 027 * <p> 028 * The MemStoreLAB is basically a bump-the-pointer allocator that allocates big (2MB) chunks from 029 * and then doles it out to threads that request slices into the array. These chunks can get pooled 030 * as well. See {@link ChunkCreator}. 031 * <p> 032 * The purpose of this is to combat heap fragmentation in the regionserver. By ensuring that all 033 * Cells in a given memstore refer only to large chunks of contiguous memory, we ensure that 034 * large blocks get freed up when the memstore is flushed. 035 * <p> 036 * Without the MSLAB, the byte array allocated during insertion end up interleaved throughout the 037 * heap, and the old generation gets progressively more fragmented until a stop-the-world compacting 038 * collection occurs. 039 * <p> 040 * This manages the large sized chunks. When Cells are to be added to Memstore, MemStoreLAB's 041 * {@link #copyCellInto(Cell)} gets called. This allocates enough size in the chunk to hold this 042 * cell's data and copies into this area and then recreate a Cell over this copied data. 043 * <p> 044 * @see ChunkCreator 045 */ 046@InterfaceAudience.Private 047public interface MemStoreLAB { 048 049 String USEMSLAB_KEY = "hbase.hregion.memstore.mslab.enabled"; 050 boolean USEMSLAB_DEFAULT = true; 051 String MSLAB_CLASS_NAME = "hbase.regionserver.mslab.class"; 052 053 String CHUNK_SIZE_KEY = "hbase.hregion.memstore.mslab.chunksize"; 054 int CHUNK_SIZE_DEFAULT = 2048 * 1024; 055 String INDEX_CHUNK_PERCENTAGE_KEY = "hbase.hregion.memstore.mslab.indexchunksize"; 056 float INDEX_CHUNK_PERCENTAGE_DEFAULT = 0.1f; 057 String MAX_ALLOC_KEY = "hbase.hregion.memstore.mslab.max.allocation"; 058 int MAX_ALLOC_DEFAULT = 256 * 1024; // allocs bigger than this don't go through 059 // allocator 060 061 // MSLAB pool related configs 062 String CHUNK_POOL_MAXSIZE_KEY = "hbase.hregion.memstore.chunkpool.maxsize"; 063 String CHUNK_POOL_INITIALSIZE_KEY = "hbase.hregion.memstore.chunkpool.initialsize"; 064 float POOL_MAX_SIZE_DEFAULT = 1.0f; 065 float POOL_INITIAL_SIZE_DEFAULT = 0.0f; 066 067 /** 068 * Allocates slice in this LAB and copy the passed Cell into this area. Returns new Cell instance 069 * over the copied the data. When this MemStoreLAB can not copy this Cell, it returns null. 070 */ 071 Cell copyCellInto(Cell cell); 072 073 /** 074 * Allocates slice in this LAB and copy the passed Cell into this area. Returns new Cell instance 075 * over the copied the data. When this MemStoreLAB can not copy this Cell, it returns null. 076 * 077 * Since the process of flattening to CellChunkMap assumes all cells are allocated on MSLAB, 078 * and since copyCellInto does not copy big cells (for whom size > maxAlloc) into MSLAB, 079 * this method is called while the process of flattening to CellChunkMap is running, 080 * for forcing the allocation of big cells on this MSLAB. 081 */ 082 Cell forceCopyOfBigCellInto(Cell cell); 083 084 /** 085 * Close instance since it won't be used any more, try to put the chunks back to pool 086 */ 087 void close(); 088 089 /** 090 * Called when opening a scanner on the data of this MemStoreLAB 091 */ 092 void incScannerCount(); 093 094 /** 095 * Called when closing a scanner on the data of this MemStoreLAB 096 */ 097 void decScannerCount(); 098 099 /* Returning a new pool chunk, without replacing current chunk, 100 ** meaning MSLABImpl does not make the returned chunk as CurChunk. 101 ** The space on this chunk will be allocated externally. 102 ** The interface is only for external callers. 103 */ 104 Chunk getNewExternalChunk(ChunkCreator.ChunkType chunkType); 105 106 /* Returning a new chunk, without replacing current chunk, 107 ** meaning MSLABImpl does not make the returned chunk as CurChunk. 108 ** The space on this chunk will be allocated externally. 109 ** The interface is only for external callers. 110 */ 111 Chunk getNewExternalChunk(int size); 112 113 static MemStoreLAB newInstance(Configuration conf) { 114 MemStoreLAB memStoreLAB = null; 115 if (isEnabled(conf)) { 116 String className = conf.get(MSLAB_CLASS_NAME, MemStoreLABImpl.class.getName()); 117 memStoreLAB = ReflectionUtils.instantiateWithCustomCtor(className, 118 new Class[] { Configuration.class }, new Object[] { conf }); 119 } 120 return memStoreLAB; 121 } 122 123 static boolean isEnabled(Configuration conf) { 124 return conf.getBoolean(USEMSLAB_KEY, USEMSLAB_DEFAULT); 125 } 126 127 boolean isOnHeap(); 128 129 boolean isOffHeap(); 130}