HBASE-16012 Major compaction can't work due to obsolete scanner read point in RegionS...
[hbase.git] / hbase-server / src / main / java / org / apache / hadoop / hbase / regionserver / Segment.java
blob64352321a5c213ac5cbff7b2bbdc119600c3423b
1 /**
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 package org.apache.hadoop.hbase.regionserver;
21 import java.util.Iterator;
22 import java.util.SortedSet;
23 import java.util.concurrent.atomic.AtomicLong;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.hbase.Cell;
28 import org.apache.hadoop.hbase.CellComparator;
29 import org.apache.hadoop.hbase.KeyValue;
30 import org.apache.hadoop.hbase.KeyValueUtil;
31 import org.apache.hadoop.hbase.classification.InterfaceAudience;
32 import org.apache.hadoop.hbase.client.Scan;
33 import org.apache.hadoop.hbase.util.ByteRange;
35 /**
36 * This is an abstraction of a segment maintained in a memstore, e.g., the active
37 * cell set or its snapshot.
39 * This abstraction facilitates the management of the compaction pipeline and the shifts of these
40 * segments from active set to snapshot set in the default implementation.
42 @InterfaceAudience.Private
43 public abstract class Segment {
45 private static final Log LOG = LogFactory.getLog(Segment.class);
46 private volatile CellSet cellSet;
47 private final CellComparator comparator;
48 private long minSequenceId;
49 private volatile MemStoreLAB memStoreLAB;
50 protected final AtomicLong size;
51 protected volatile boolean tagsPresent;
52 private final TimeRangeTracker timeRangeTracker;
54 protected Segment(CellSet cellSet, CellComparator comparator, MemStoreLAB memStoreLAB,
55 long size) {
56 this.cellSet = cellSet;
57 this.comparator = comparator;
58 this.minSequenceId = Long.MAX_VALUE;
59 this.memStoreLAB = memStoreLAB;
60 this.size = new AtomicLong(size);
61 this.tagsPresent = false;
62 this.timeRangeTracker = new TimeRangeTracker();
65 protected Segment(Segment segment) {
66 this.cellSet = segment.getCellSet();
67 this.comparator = segment.getComparator();
68 this.minSequenceId = segment.getMinSequenceId();
69 this.memStoreLAB = segment.getMemStoreLAB();
70 this.size = new AtomicLong(segment.getSize());
71 this.tagsPresent = segment.isTagsPresent();
72 this.timeRangeTracker = segment.getTimeRangeTracker();
75 /**
76 * Creates the scanner for the given read point
77 * @return a scanner for the given read point
79 public SegmentScanner getSegmentScanner(long readPoint) {
80 return new SegmentScanner(this, readPoint);
83 /**
84 * Creates the scanner for the given read point, and a specific order in a list
85 * @return a scanner for the given read point
87 public SegmentScanner getSegmentScanner(long readPoint, long order) {
88 return new SegmentScanner(this, readPoint, order);
91 /**
92 * Returns whether the segment has any cells
93 * @return whether the segment has any cells
95 public boolean isEmpty() {
96 return getCellSet().isEmpty();
99 /**
100 * Returns number of cells in segment
101 * @return number of cells in segment
103 public int getCellsCount() {
104 return getCellSet().size();
108 * Returns the first cell in the segment that has equal or greater key than the given cell
109 * @return the first cell in the segment that has equal or greater key than the given cell
111 public Cell getFirstAfter(Cell cell) {
112 SortedSet<Cell> snTailSet = tailSet(cell);
113 if (!snTailSet.isEmpty()) {
114 return snTailSet.first();
116 return null;
120 * Closing a segment before it is being discarded
122 public void close() {
123 MemStoreLAB mslab = getMemStoreLAB();
124 if(mslab != null) {
125 mslab.close();
127 // do not set MSLab to null as scanners may still be reading the data here and need to decrease
128 // the counter when they finish
132 * If the segment has a memory allocator the cell is being cloned to this space, and returned;
133 * otherwise the given cell is returned
134 * @return either the given cell or its clone
136 public Cell maybeCloneWithAllocator(Cell cell) {
137 if (getMemStoreLAB() == null) {
138 return cell;
141 int len = KeyValueUtil.length(cell);
142 ByteRange alloc = getMemStoreLAB().allocateBytes(len);
143 if (alloc == null) {
144 // The allocation was too large, allocator decided
145 // not to do anything with it.
146 return cell;
148 assert alloc.getBytes() != null;
149 KeyValueUtil.appendToByteArray(cell, alloc.getBytes(), alloc.getOffset());
150 KeyValue newKv = new KeyValue(alloc.getBytes(), alloc.getOffset(), len);
151 newKv.setSequenceId(cell.getSequenceId());
152 return newKv;
155 public abstract boolean shouldSeek(Scan scan, long oldestUnexpiredTS);
157 public abstract long getMinTimestamp();
159 public boolean isTagsPresent() {
160 return tagsPresent;
163 public void incScannerCount() {
164 if(getMemStoreLAB() != null) {
165 getMemStoreLAB().incScannerCount();
169 public void decScannerCount() {
170 if(getMemStoreLAB() != null) {
171 getMemStoreLAB().decScannerCount();
176 * Setting the heap size of the segment - used to account for different class overheads
177 * @return this object
180 public Segment setSize(long size) {
181 this.size.set(size);
182 return this;
186 * Returns the heap size of the segment
187 * @return the heap size of the segment
189 public long getSize() {
190 return size.get();
194 * Increases the heap size counter of the segment by the given delta
196 public void incSize(long delta) {
197 size.addAndGet(delta);
200 public long getMinSequenceId() {
201 return minSequenceId;
204 public TimeRangeTracker getTimeRangeTracker() {
205 return this.timeRangeTracker;
208 //*** Methods for SegmentsScanner
209 public Cell last() {
210 return getCellSet().last();
213 public Iterator<Cell> iterator() {
214 return getCellSet().iterator();
217 public SortedSet<Cell> headSet(Cell firstKeyOnRow) {
218 return getCellSet().headSet(firstKeyOnRow);
221 public int compare(Cell left, Cell right) {
222 return getComparator().compare(left, right);
225 public int compareRows(Cell left, Cell right) {
226 return getComparator().compareRows(left, right);
230 * Returns a set of all cells in the segment
231 * @return a set of all cells in the segment
233 protected CellSet getCellSet() {
234 return cellSet;
238 * Returns the Cell comparator used by this segment
239 * @return the Cell comparator used by this segment
241 protected CellComparator getComparator() {
242 return comparator;
245 protected long internalAdd(Cell cell) {
246 boolean succ = getCellSet().add(cell);
247 long s = AbstractMemStore.heapSizeChange(cell, succ);
248 updateMetaInfo(cell, s);
249 return s;
252 protected void updateMetaInfo(Cell toAdd, long s) {
253 getTimeRangeTracker().includeTimestamp(toAdd);
254 size.addAndGet(s);
255 minSequenceId = Math.min(minSequenceId, toAdd.getSequenceId());
256 // In no tags case this NoTagsKeyValue.getTagsLength() is a cheap call.
257 // When we use ACL CP or Visibility CP which deals with Tags during
258 // mutation, the TagRewriteCell.getTagsLength() is a cheaper call. We do not
259 // parse the byte[] to identify the tags length.
260 if(toAdd.getTagsLength() > 0) {
261 tagsPresent = true;
266 * Returns a subset of the segment cell set, which starts with the given cell
267 * @param firstCell a cell in the segment
268 * @return a subset of the segment cell set, which starts with the given cell
270 protected SortedSet<Cell> tailSet(Cell firstCell) {
271 return getCellSet().tailSet(firstCell);
274 private MemStoreLAB getMemStoreLAB() {
275 return memStoreLAB;
278 // Debug methods
280 * Dumps all cells of the segment into the given log
282 void dump(Log log) {
283 for (Cell cell: getCellSet()) {
284 log.debug(cell);
288 @Override
289 public String toString() {
290 String res = "Store segment of type "+this.getClass().getName()+"; ";
291 res += "isEmpty "+(isEmpty()?"yes":"no")+"; ";
292 res += "cellCount "+getCellsCount()+"; ";
293 res += "size "+getSize()+"; ";
294 res += "Min ts "+getMinTimestamp()+"; ";
295 return res;