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}