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.hadoop.hbase.util.ReflectionUtils; 023import org.apache.yetus.audience.InterfaceAudience; 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 large 034 * 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_SIZE_PERCENTAGE_KEY = "hbase.hregion.memstore.mslab.indexchunksize.percent"; 056 float INDEX_CHUNK_SIZE_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. Since 076 * the process of flattening to CellChunkMap assumes all cells are allocated on MSLAB, and since 077 * copyCellInto does not copy big cells (for whom size > maxAlloc) into MSLAB, this method is 078 * called while the process of flattening to CellChunkMap is running, for forcing the allocation 079 * of big cells on this MSLAB. 080 */ 081 Cell forceCopyOfBigCellInto(Cell cell); 082 083 /** 084 * Close instance since it won't be used any more, try to put the chunks back to pool 085 */ 086 void close(); 087 088 /** 089 * Called when opening a scanner on the data of this MemStoreLAB 090 */ 091 void incScannerCount(); 092 093 /** 094 * Called when closing a scanner on the data of this MemStoreLAB 095 */ 096 void decScannerCount(); 097 098 /* 099 * Returning a new pool chunk, without replacing current chunk, meaning MSLABImpl does not make 100 * the returned chunk as CurChunk. The space on this chunk will be allocated externally. The 101 * interface is only for external callers. 102 */ 103 Chunk getNewExternalChunk(ChunkCreator.ChunkType chunkType); 104 105 /* 106 * Returning a new chunk, without replacing current chunk, meaning MSLABImpl does not make the 107 * returned chunk as CurChunk. The space on this chunk will be allocated externally. The interface 108 * is only for external callers. 109 */ 110 Chunk getNewExternalChunk(int size); 111 112 static MemStoreLAB newInstance(Configuration conf) { 113 MemStoreLAB memStoreLAB = null; 114 if (isEnabled(conf)) { 115 String className = conf.get(MSLAB_CLASS_NAME, MemStoreLABImpl.class.getName()); 116 memStoreLAB = ReflectionUtils.instantiateWithCustomCtor(className, 117 new Class[] { Configuration.class }, new Object[] { conf }); 118 } 119 return memStoreLAB; 120 } 121 122 static boolean isEnabled(Configuration conf) { 123 return conf.getBoolean(USEMSLAB_KEY, USEMSLAB_DEFAULT); 124 } 125 126 boolean isOnHeap(); 127 128 boolean isOffHeap(); 129}