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
;
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
,
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();
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
);
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
);
92 * Returns whether the segment has any cells
93 * @return whether the segment has any cells
95 public boolean isEmpty() {
96 return getCellSet().isEmpty();
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();
120 * Closing a segment before it is being discarded
122 public void close() {
123 MemStoreLAB mslab
= getMemStoreLAB();
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) {
141 int len
= KeyValueUtil
.length(cell
);
142 ByteRange alloc
= getMemStoreLAB().allocateBytes(len
);
144 // The allocation was too large, allocator decided
145 // not to do anything with it.
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());
155 public abstract boolean shouldSeek(Scan scan
, long oldestUnexpiredTS
);
157 public abstract long getMinTimestamp();
159 public boolean isTagsPresent() {
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
) {
186 * Returns the heap size of the segment
187 * @return the heap size of the segment
189 public long getSize() {
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
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() {
238 * Returns the Cell comparator used by this segment
239 * @return the Cell comparator used by this segment
241 protected CellComparator
getComparator() {
245 protected long internalAdd(Cell cell
) {
246 boolean succ
= getCellSet().add(cell
);
247 long s
= AbstractMemStore
.heapSizeChange(cell
, succ
);
248 updateMetaInfo(cell
, s
);
252 protected void updateMetaInfo(Cell toAdd
, long s
) {
253 getTimeRangeTracker().includeTimestamp(toAdd
);
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) {
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() {
280 * Dumps all cells of the segment into the given log
283 for (Cell cell
: getCellSet()) {
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()+"; ";