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}