001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.regionserver;
020
021import org.apache.hadoop.hbase.Cell;
022import org.apache.hadoop.hbase.CellComparator;
023import org.apache.hadoop.hbase.CellUtil;
024import org.apache.yetus.audience.InterfaceAudience;
025import org.apache.hadoop.hbase.util.ClassSize;
026
027import java.io.IOException;
028
029/**
030 * CellArrayImmutableSegment extends the API supported by a {@link Segment},
031 * and {@link ImmutableSegment}. This immutable segment is working with CellSet with
032 * CellArrayMap delegatee.
033 */
034@InterfaceAudience.Private
035public class CellArrayImmutableSegment extends ImmutableSegment {
036
037  public static final long DEEP_OVERHEAD_CAM = DEEP_OVERHEAD + ClassSize.CELL_ARRAY_MAP;
038
039  /////////////////////  CONSTRUCTORS  /////////////////////
040  /**------------------------------------------------------------------------
041   * C-tor to be used when new CellArrayImmutableSegment is a result of compaction of a
042   * list of older ImmutableSegments.
043   * The given iterator returns the Cells that "survived" the compaction.
044   */
045  protected CellArrayImmutableSegment(CellComparator comparator, MemStoreSegmentsIterator iterator,
046      MemStoreLAB memStoreLAB, int numOfCells, MemStoreCompactionStrategy.Action action) {
047    super(null, comparator, memStoreLAB); // initiailize the CellSet with NULL
048    incMemStoreSize(0, DEEP_OVERHEAD_CAM, 0, 0); // CAM is always on-heap
049    // build the new CellSet based on CellArrayMap and update the CellSet of the new Segment
050    initializeCellSet(numOfCells, iterator, action);
051  }
052
053  /**------------------------------------------------------------------------
054   * C-tor to be used when new CellChunkImmutableSegment is built as a result of flattening
055   * of CSLMImmutableSegment
056   * The given iterator returns the Cells that "survived" the compaction.
057   */
058  protected CellArrayImmutableSegment(CSLMImmutableSegment segment, MemStoreSizing memstoreSizing,
059      MemStoreCompactionStrategy.Action action) {
060    super(segment); // initiailize the upper class
061    long indexOverhead = DEEP_OVERHEAD_CAM - CSLMImmutableSegment.DEEP_OVERHEAD_CSLM;
062    incMemStoreSize(0, indexOverhead, 0, 0); // CAM is always on-heap
063    memstoreSizing.incMemStoreSize(0, indexOverhead, 0, 0);
064    int numOfCells = segment.getCellsCount();
065    // build the new CellSet based on CellChunkMap and update the CellSet of this Segment
066    reinitializeCellSet(numOfCells, segment.getScanner(Long.MAX_VALUE), segment.getCellSet(),
067      action);
068    // arrange the meta-data size, decrease all meta-data sizes related to SkipList;
069    // add sizes of CellArrayMap entry (reinitializeCellSet doesn't take the care for the sizes)
070    long newSegmentSizeDelta =
071        numOfCells * (indexEntrySize() - ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY);
072    incMemStoreSize(0, newSegmentSizeDelta, 0, 0);
073    memstoreSizing.incMemStoreSize(0, newSegmentSizeDelta, 0, 0);
074  }
075
076  @Override
077  protected long indexEntrySize() {
078    return ClassSize.CELL_ARRAY_MAP_ENTRY;
079  }
080
081  @Override
082  protected boolean canBeFlattened() {
083    return false;
084  }
085
086  /////////////////////  PRIVATE METHODS  /////////////////////
087  /*------------------------------------------------------------------------*/
088  // Create CellSet based on CellArrayMap from compacting iterator
089  private void initializeCellSet(int numOfCells, MemStoreSegmentsIterator iterator,
090      MemStoreCompactionStrategy.Action action) {
091
092    boolean merge = (action == MemStoreCompactionStrategy.Action.MERGE ||
093        action == MemStoreCompactionStrategy.Action.MERGE_COUNT_UNIQUE_KEYS);
094    Cell[] cells = new Cell[numOfCells];   // build the Cell Array
095    int i = 0;
096    int numUniqueKeys=0;
097    Cell prev = null;
098    while (iterator.hasNext()) {
099      Cell c = iterator.next();
100      // The scanner behind the iterator is doing all the elimination logic
101      if (merge) {
102        // if this is merge we just move the Cell object without copying MSLAB
103        // the sizes still need to be updated in the new segment
104        cells[i] = c;
105      } else {
106        // now we just copy it to the new segment (also MSLAB copy)
107        cells[i] = maybeCloneWithAllocator(c, false);
108      }
109      // second parameter true, because in compaction/merge the addition of the cell to new segment
110      // is always successful
111      updateMetaInfo(cells[i], true, null); // updates the size per cell
112      if(action == MemStoreCompactionStrategy.Action.MERGE_COUNT_UNIQUE_KEYS) {
113        //counting number of unique keys
114        if (prev != null) {
115          if (!CellUtil.matchingRowColumnBytes(prev, c)) {
116            numUniqueKeys++;
117          }
118        } else {
119          numUniqueKeys++;
120        }
121      }
122      prev = c;
123      i++;
124    }
125    if(action == MemStoreCompactionStrategy.Action.COMPACT) {
126      numUniqueKeys = numOfCells;
127    } else if(action != MemStoreCompactionStrategy.Action.MERGE_COUNT_UNIQUE_KEYS) {
128      numUniqueKeys = CellSet.UNKNOWN_NUM_UNIQUES;
129    }
130    // build the immutable CellSet
131    CellArrayMap cam = new CellArrayMap(getComparator(), cells, 0, i, false);
132    this.setCellSet(null, new CellSet(cam, numUniqueKeys));   // update the CellSet of this Segment
133  }
134
135  /*------------------------------------------------------------------------*/
136  // Create CellSet based on CellChunkMap from current ConcurrentSkipListMap based CellSet
137  // (without compacting iterator)
138  // We do not consider cells bigger than chunks!
139  private void reinitializeCellSet(
140      int numOfCells, KeyValueScanner segmentScanner, CellSet oldCellSet,
141      MemStoreCompactionStrategy.Action action) {
142    Cell[] cells = new Cell[numOfCells];   // build the Cell Array
143    Cell curCell;
144    int idx = 0;
145    int numUniqueKeys=0;
146    Cell prev = null;
147    try {
148      while ((curCell = segmentScanner.next()) != null) {
149        cells[idx++] = curCell;
150        if(action == MemStoreCompactionStrategy.Action.FLATTEN_COUNT_UNIQUE_KEYS) {
151          //counting number of unique keys
152          if (prev != null) {
153            if (!CellUtil.matchingRowColumn(prev, curCell)) {
154              numUniqueKeys++;
155            }
156          } else {
157            numUniqueKeys++;
158          }
159        }
160        prev = curCell;
161      }
162    } catch (IOException ie) {
163      throw new IllegalStateException(ie);
164    } finally {
165      segmentScanner.close();
166    }
167    if(action != MemStoreCompactionStrategy.Action.FLATTEN_COUNT_UNIQUE_KEYS) {
168      numUniqueKeys = CellSet.UNKNOWN_NUM_UNIQUES;
169    }
170    // build the immutable CellSet
171    CellArrayMap cam = new CellArrayMap(getComparator(), cells, 0, idx, false);
172    // update the CellSet of this Segment
173    this.setCellSet(oldCellSet, new CellSet(cam, numUniqueKeys));
174  }
175
176}