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 java.io.IOException;
021import org.apache.hadoop.hbase.Cell;
022import org.apache.hadoop.hbase.CellComparator;
023import org.apache.hadoop.hbase.CellUtil;
024import org.apache.hadoop.hbase.ExtendedCell;
025import org.apache.hadoop.hbase.util.ClassSize;
026import org.apache.yetus.audience.InterfaceAudience;
027
028/**
029 * CellArrayImmutableSegment extends the API supported by a {@link Segment}, and
030 * {@link ImmutableSegment}. This immutable segment is working with CellSet with CellArrayMap
031 * delegatee.
032 */
033@InterfaceAudience.Private
034public class CellArrayImmutableSegment extends ImmutableSegment {
035
036  public static final long DEEP_OVERHEAD_CAM = DEEP_OVERHEAD + ClassSize.CELL_ARRAY_MAP;
037
038  ///////////////////// CONSTRUCTORS /////////////////////
039  /**
040   * ------------------------------------------------------------------------ C-tor to be used when
041   * new CellArrayImmutableSegment is a result of compaction of a list of older ImmutableSegments.
042   * The given iterator returns the Cells that "survived" the compaction.
043   */
044  protected CellArrayImmutableSegment(CellComparator comparator, MemStoreSegmentsIterator iterator,
045    MemStoreLAB memStoreLAB, int numOfCells, MemStoreCompactionStrategy.Action action) {
046    super(null, comparator, memStoreLAB); // initiailize the CellSet with NULL
047    incMemStoreSize(0, DEEP_OVERHEAD_CAM, 0, 0); // CAM is always on-heap
048    // build the new CellSet based on CellArrayMap and update the CellSet of the new Segment
049    initializeCellSet(numOfCells, iterator, action);
050  }
051
052  /**
053   * ------------------------------------------------------------------------ C-tor to be used when
054   * new CellChunkImmutableSegment is built as a result of flattening of CSLMImmutableSegment The
055   * given iterator returns the Cells that "survived" the compaction.
056   */
057  protected CellArrayImmutableSegment(CSLMImmutableSegment segment, MemStoreSizing mss,
058    MemStoreCompactionStrategy.Action action) {
059    super(segment); // initiailize the upper class
060    long indexOverhead = DEEP_OVERHEAD_CAM - CSLMImmutableSegment.DEEP_OVERHEAD_CSLM;
061    incMemStoreSize(0, indexOverhead, 0, 0); // CAM is always on-heap
062    mss.incMemStoreSize(0, indexOverhead, 0, 0);
063    int numOfCells = segment.getCellsCount();
064    // build the new CellSet based on CellChunkMap and update the CellSet of this Segment
065    reinitializeCellSet(numOfCells, segment.getScanner(Long.MAX_VALUE), segment.getCellSet(),
066      action);
067    // arrange the meta-data size, decrease all meta-data sizes related to SkipList;
068    // add sizes of CellArrayMap entry (reinitializeCellSet doesn't take the care for the sizes)
069    long newSegmentSizeDelta =
070      numOfCells * (indexEntrySize() - ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY);
071    incMemStoreSize(0, newSegmentSizeDelta, 0, 0);
072    mss.incMemStoreSize(0, newSegmentSizeDelta, 0, 0);
073  }
074
075  @Override
076  protected long indexEntrySize() {
077    return ClassSize.CELL_ARRAY_MAP_ENTRY;
078  }
079
080  @Override
081  protected boolean canBeFlattened() {
082    return false;
083  }
084
085  ///////////////////// PRIVATE METHODS /////////////////////
086  /*------------------------------------------------------------------------*/
087  // Create CellSet based on CellArrayMap from compacting iterator
088  private void initializeCellSet(int numOfCells, MemStoreSegmentsIterator iterator,
089    MemStoreCompactionStrategy.Action action) {
090    boolean merge = (action == MemStoreCompactionStrategy.Action.MERGE
091      || action == MemStoreCompactionStrategy.Action.MERGE_COUNT_UNIQUE_KEYS);
092    ExtendedCell[] cells = new ExtendedCell[numOfCells]; // build the Cell Array
093    int i = 0;
094    int numUniqueKeys = 0;
095    Cell prev = null;
096    while (iterator.hasNext()) {
097      ExtendedCell c = iterator.next();
098      // The scanner behind the iterator is doing all the elimination logic
099      if (merge) {
100        // if this is merge we just move the Cell object without copying MSLAB
101        // the sizes still need to be updated in the new segment
102        cells[i] = c;
103      } else {
104        // now we just copy it to the new segment (also MSLAB copy)
105        cells[i] = maybeCloneWithAllocator(c, false);
106      }
107      // second parameter true, because in compaction/merge the addition of the cell to new segment
108      // is always successful
109      updateMetaInfo(cells[i], true, null); // updates the size per cell
110      if (action == MemStoreCompactionStrategy.Action.MERGE_COUNT_UNIQUE_KEYS) {
111        // counting number of unique keys
112        if (prev != null) {
113          if (!CellUtil.matchingRowColumnBytes(prev, c)) {
114            numUniqueKeys++;
115          }
116        } else {
117          numUniqueKeys++;
118        }
119      }
120      prev = c;
121      i++;
122    }
123    if (action == MemStoreCompactionStrategy.Action.COMPACT) {
124      numUniqueKeys = numOfCells;
125    } else if (action != MemStoreCompactionStrategy.Action.MERGE_COUNT_UNIQUE_KEYS) {
126      numUniqueKeys = CellSet.UNKNOWN_NUM_UNIQUES;
127    }
128    // build the immutable CellSet
129    CellArrayMap<ExtendedCell> cam = new CellArrayMap<>(getComparator(), cells, 0, i, false);
130    this.setCellSet(null, new CellSet<>(cam, numUniqueKeys)); // update the CellSet of this Segment
131  }
132
133  /*------------------------------------------------------------------------*/
134  // Create CellSet based on CellChunkMap from current ConcurrentSkipListMap based CellSet
135  // (without compacting iterator)
136  // We do not consider cells bigger than chunks!
137  private void reinitializeCellSet(int numOfCells, KeyValueScanner segmentScanner,
138    CellSet<ExtendedCell> oldCellSet, MemStoreCompactionStrategy.Action action) {
139    ExtendedCell[] cells = new ExtendedCell[numOfCells]; // build the Cell Array
140    ExtendedCell curCell;
141    int idx = 0;
142    int numUniqueKeys = 0;
143    ExtendedCell prev = null;
144    try {
145      while ((curCell = segmentScanner.next()) != null) {
146        cells[idx++] = curCell;
147        if (action == MemStoreCompactionStrategy.Action.FLATTEN_COUNT_UNIQUE_KEYS) {
148          // counting number of unique keys
149          if (prev != null) {
150            if (!CellUtil.matchingRowColumn(prev, curCell)) {
151              numUniqueKeys++;
152            }
153          } else {
154            numUniqueKeys++;
155          }
156        }
157        prev = curCell;
158      }
159    } catch (IOException ie) {
160      throw new IllegalStateException(ie);
161    } finally {
162      segmentScanner.close();
163    }
164    if (action != MemStoreCompactionStrategy.Action.FLATTEN_COUNT_UNIQUE_KEYS) {
165      numUniqueKeys = CellSet.UNKNOWN_NUM_UNIQUES;
166    }
167    // build the immutable CellSet
168    CellArrayMap<ExtendedCell> cam = new CellArrayMap<>(getComparator(), cells, 0, idx, false);
169    // update the CellSet of this Segment
170    this.setCellSet(oldCellSet, new CellSet<>(cam, numUniqueKeys));
171  }
172
173}