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