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