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 java.util.Iterator;
022import java.util.SortedSet;
023
024import org.apache.hadoop.hbase.Cell;
025import org.apache.hadoop.hbase.CellComparator;
026import org.apache.hadoop.hbase.CellUtil;
027import org.apache.hadoop.hbase.HConstants;
028import org.apache.hadoop.hbase.PrivateCellUtil;
029import org.apache.hadoop.hbase.KeyValue;
030import org.apache.yetus.audience.InterfaceAudience;
031import org.apache.hadoop.hbase.util.ClassSize;
032
033import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
034
035/**
036 * A mutable segment in memstore, specifically the active segment.
037 */
038@InterfaceAudience.Private
039public class MutableSegment extends Segment {
040
041  public final static long DEEP_OVERHEAD = Segment.DEEP_OVERHEAD
042        + ClassSize.CONCURRENT_SKIPLISTMAP
043        + ClassSize.SYNC_TIMERANGE_TRACKER;
044
045  protected MutableSegment(CellSet cellSet, CellComparator comparator,
046      MemStoreLAB memStoreLAB, MemStoreSizing memstoreSizing) {
047    super(cellSet, comparator, memStoreLAB, TimeRangeTracker.create(TimeRangeTracker.Type.SYNC));
048    incMemStoreSize(0, DEEP_OVERHEAD, 0, 0); // update the mutable segment metadata
049    if (memstoreSizing != null) {
050      memstoreSizing.incMemStoreSize(0, DEEP_OVERHEAD, 0, 0);
051    }
052  }
053
054  /**
055   * Adds the given cell into the segment
056   * @param cell the cell to add
057   * @param mslabUsed whether using MSLAB
058   */
059  public void add(Cell cell, boolean mslabUsed, MemStoreSizing memStoreSizing) {
060    internalAdd(cell, mslabUsed, memStoreSizing);
061  }
062
063  public void upsert(Cell cell, long readpoint, MemStoreSizing memStoreSizing) {
064    internalAdd(cell, false, memStoreSizing);
065
066    // Get the Cells for the row/family/qualifier regardless of timestamp.
067    // For this case we want to clean up any other puts
068    Cell firstCell = PrivateCellUtil.createFirstOnRowColTS(cell, HConstants.LATEST_TIMESTAMP);
069    SortedSet<Cell> ss = this.tailSet(firstCell);
070    Iterator<Cell> it = ss.iterator();
071    // versions visible to oldest scanner
072    int versionsVisible = 0;
073    while (it.hasNext()) {
074      Cell cur = it.next();
075
076      if (cell == cur) {
077        // ignore the one just put in
078        continue;
079      }
080      // check that this is the row and column we are interested in, otherwise bail
081      if (CellUtil.matchingRows(cell, cur) && CellUtil.matchingQualifier(cell, cur)) {
082        // only remove Puts that concurrent scanners cannot possibly see
083        if (cur.getTypeByte() == KeyValue.Type.Put.getCode() && cur.getSequenceId() <= readpoint) {
084          if (versionsVisible >= 1) {
085            // if we get here we have seen at least one version visible to the oldest scanner,
086            // which means we can prove that no scanner will see this version
087
088            // false means there was a change, so give us the size.
089            // TODO when the removed cell ie.'cur' having its data in MSLAB, we can not release that
090            // area. Only the Cell object as such going way. We need to consider cellLen to be
091            // decreased there as 0 only. Just keeping it as existing code now. We need to know the
092            // removed cell is from MSLAB or not. Will do once HBASE-16438 is in
093            int cellLen = getCellLength(cur);
094            long heapSize = heapSizeChange(cur, true);
095            long offHeapSize = offHeapSizeChange(cur, true);
096            incMemStoreSize(-cellLen, -heapSize, -offHeapSize, -1);
097            if (memStoreSizing != null) {
098              memStoreSizing.decMemStoreSize(cellLen, heapSize, offHeapSize, 1);
099            }
100            it.remove();
101          } else {
102            versionsVisible++;
103          }
104        }
105      } else {
106        // past the row or column, done
107        break;
108      }
109    }
110  }
111
112  /**
113   * Returns the first cell in the segment
114   * @return the first cell in the segment
115   */
116  @VisibleForTesting
117  Cell first() {
118    return this.getCellSet().first();
119  }
120
121  @Override protected long indexEntrySize() {
122      return ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY;
123  }
124}