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}