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
.io
.ByteArrayInputStream
;
22 import java
.io
.ByteArrayOutputStream
;
23 import java
.io
.DataInputStream
;
24 import java
.io
.DataOutputStream
;
25 import java
.io
.IOException
;
26 import java
.util
.concurrent
.atomic
.AtomicLong
;
27 import org
.apache
.hadoop
.hbase
.Cell
;
28 import org
.apache
.hadoop
.hbase
.PrivateCellUtil
;
29 import org
.apache
.hadoop
.hbase
.io
.TimeRange
;
30 import org
.apache
.yetus
.audience
.InterfaceAudience
;
32 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.base
.Preconditions
;
34 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.ProtobufUtil
;
35 import org
.apache
.hadoop
.hbase
.shaded
.protobuf
.generated
.HBaseProtos
;
38 * Stores minimum and maximum timestamp values, it is [minimumTimestamp, maximumTimestamp] in
40 * Use this class at write-time ONLY. Too much synchronization to use at read time
41 * Use {@link TimeRange} at read time instead of this. See toTimeRange() to make TimeRange to use.
42 * MemStores use this class to track minimum and maximum timestamps. The TimeRangeTracker made by
43 * the MemStore is passed to the StoreFile for it to write out as part a flush in the the file
44 * metadata. If no memstore involved -- i.e. a compaction -- then the StoreFile will calculate its
45 * own TimeRangeTracker as it appends. The StoreFile serialized TimeRangeTracker is used
46 * at read time via an instance of {@link TimeRange} to test if Cells fit the StoreFile TimeRange.
48 @InterfaceAudience.Private
49 public abstract class TimeRangeTracker
{
58 static final long INITIAL_MIN_TIMESTAMP
= Long
.MAX_VALUE
;
59 static final long INITIAL_MAX_TIMESTAMP
= -1L;
61 public static TimeRangeTracker
create(Type type
) {
64 return new NonSyncTimeRangeTracker();
66 return new SyncTimeRangeTracker();
68 throw new UnsupportedOperationException("The type:" + type
+ " is unsupported");
72 public static TimeRangeTracker
create(Type type
, TimeRangeTracker trt
) {
75 return new NonSyncTimeRangeTracker(trt
);
77 return new SyncTimeRangeTracker(trt
);
79 throw new UnsupportedOperationException("The type:" + type
+ " is unsupported");
83 public static TimeRangeTracker
create(Type type
, long minimumTimestamp
, long maximumTimestamp
) {
86 return new NonSyncTimeRangeTracker(minimumTimestamp
, maximumTimestamp
);
88 return new SyncTimeRangeTracker(minimumTimestamp
, maximumTimestamp
);
90 throw new UnsupportedOperationException("The type:" + type
+ " is unsupported");
94 protected abstract void setMax(long ts
);
95 protected abstract void setMin(long ts
);
96 protected abstract boolean compareAndSetMin(long expect
, long update
);
97 protected abstract boolean compareAndSetMax(long expect
, long update
);
99 * Update the current TimestampRange to include the timestamp from <code>cell</code>.
100 * If the Key is of type DeleteColumn or DeleteFamily, it includes the
101 * entire time range from 0 to timestamp of the key.
102 * @param cell the Cell to include
104 public void includeTimestamp(final Cell cell
) {
105 includeTimestamp(cell
.getTimestamp());
106 if (PrivateCellUtil
.isDeleteColumnOrFamily(cell
)) {
112 * If required, update the current TimestampRange to include timestamp
113 * @param timestamp the timestamp value to include
115 @edu.umd
.cs
.findbugs
.annotations
.SuppressWarnings(value
="MT_CORRECTNESS",
116 justification
="Intentional")
117 void includeTimestamp(final long timestamp
) {
118 long initialMinTimestamp
= getMin();
119 if (timestamp
< initialMinTimestamp
) {
120 long curMinTimestamp
= initialMinTimestamp
;
121 while (timestamp
< curMinTimestamp
) {
122 if (!compareAndSetMin(curMinTimestamp
, timestamp
)) {
123 curMinTimestamp
= getMin();
125 // successfully set minimumTimestamp, break.
130 // When it reaches here, there are two possibilities:
131 // 1). timestamp >= curMinTimestamp, someone already sets the minimumTimestamp. In this case,
132 // it still needs to check if initialMinTimestamp == INITIAL_MIN_TIMESTAMP to see
133 // if it needs to update minimumTimestamp. Someone may already set both
134 // minimumTimestamp/minimumTimestamp to the same value(curMinTimestamp),
135 // need to check if maximumTimestamp needs to be updated.
136 // 2). timestamp < curMinTimestamp, it sets the minimumTimestamp successfully.
137 // In this case,it still needs to check if initialMinTimestamp == INITIAL_MIN_TIMESTAMP
138 // to see if it needs to set maximumTimestamp.
139 if (initialMinTimestamp
!= INITIAL_MIN_TIMESTAMP
) {
140 // Someone already sets minimumTimestamp and timestamp is less than minimumTimestamp.
141 // In this case, no need to set maximumTimestamp as it will be set to at least
142 // initialMinTimestamp.
147 long curMaxTimestamp
= getMax();
149 if (timestamp
> curMaxTimestamp
) {
150 while (timestamp
> curMaxTimestamp
) {
151 if (!compareAndSetMax(curMaxTimestamp
, timestamp
)) {
152 curMaxTimestamp
= getMax();
154 // successfully set maximumTimestamp, break
162 * Check if the range has ANY overlap with TimeRange
163 * @param tr TimeRange, it expects [minStamp, maxStamp)
164 * @return True if there is overlap, false otherwise
166 public boolean includesTimeRange(final TimeRange tr
) {
167 return (getMin() < tr
.getMax() && getMax() >= tr
.getMin());
171 * @return the minimumTimestamp
173 public abstract long getMin();
176 * @return the maximumTimestamp
178 public abstract long getMax();
181 public String
toString() {
182 return "[" + getMin() + "," + getMax() + "]";
186 * @param data the serialization data. It can't be null!
187 * @return An instance of NonSyncTimeRangeTracker filled w/ the content of serialized
188 * NonSyncTimeRangeTracker in <code>timeRangeTrackerBytes</code>.
189 * @throws IOException
191 public static TimeRangeTracker
parseFrom(final byte[] data
) throws IOException
{
192 return parseFrom(data
, Type
.NON_SYNC
);
195 public static TimeRangeTracker
parseFrom(final byte[] data
, Type type
) throws IOException
{
196 Preconditions
.checkNotNull(data
, "input data is null!");
197 if (ProtobufUtil
.isPBMagicPrefix(data
)) {
198 int pblen
= ProtobufUtil
.lengthOfPBMagic();
199 HBaseProtos
.TimeRangeTracker
.Builder builder
= HBaseProtos
.TimeRangeTracker
.newBuilder();
200 ProtobufUtil
.mergeFrom(builder
, data
, pblen
, data
.length
- pblen
);
201 return TimeRangeTracker
.create(type
, builder
.getFrom(), builder
.getTo());
203 try (DataInputStream in
= new DataInputStream(new ByteArrayInputStream(data
))) {
204 return TimeRangeTracker
.create(type
, in
.readLong(), in
.readLong());
210 * This method used to serialize TimeRangeTracker (TRT) by protobuf while this breaks the
211 * forward compatibility on HFile.(See HBASE-21008) In previous hbase version ( < 2.0.0 ) we use
212 * DataOutput to serialize TRT, these old versions don't have capability to deserialize TRT
213 * which is serialized by protobuf. So we need to revert the change of serializing
214 * TimeRangeTracker back to DataOutput. For more information, please check HBASE-21012.
215 * @param tracker TimeRangeTracker needed to be serialized.
216 * @return byte array filled with serialized TimeRangeTracker.
217 * @throws IOException if something goes wrong in writeLong.
219 public static byte[] toByteArray(TimeRangeTracker tracker
) throws IOException
{
220 try (ByteArrayOutputStream bos
= new ByteArrayOutputStream()) {
221 try (DataOutputStream dos
= new DataOutputStream(bos
)) {
222 dos
.writeLong(tracker
.getMin());
223 dos
.writeLong(tracker
.getMax());
224 return bos
.toByteArray();
230 * @return Make a TimeRange from current state of <code>this</code>.
232 TimeRange
toTimeRange() {
235 // Initial TimeRangeTracker timestamps are the opposite of what you want for a TimeRange. Fix!
236 if (min
== INITIAL_MIN_TIMESTAMP
) {
237 min
= TimeRange
.INITIAL_MIN_TIMESTAMP
;
239 if (max
== INITIAL_MAX_TIMESTAMP
) {
240 max
= TimeRange
.INITIAL_MAX_TIMESTAMP
;
242 return TimeRange
.between(min
, max
);
245 //In order to estimate the heap size, this inner class need to be accessible to TestHeapSize.
246 public static class NonSyncTimeRangeTracker
extends TimeRangeTracker
{
247 private long minimumTimestamp
= INITIAL_MIN_TIMESTAMP
;
248 private long maximumTimestamp
= INITIAL_MAX_TIMESTAMP
;
250 NonSyncTimeRangeTracker() {
253 NonSyncTimeRangeTracker(final TimeRangeTracker trt
) {
254 this.minimumTimestamp
= trt
.getMin();
255 this.maximumTimestamp
= trt
.getMax();
258 NonSyncTimeRangeTracker(long minimumTimestamp
, long maximumTimestamp
) {
259 this.minimumTimestamp
= minimumTimestamp
;
260 this.maximumTimestamp
= maximumTimestamp
;
264 protected void setMax(long ts
) {
265 maximumTimestamp
= ts
;
269 protected void setMin(long ts
) {
270 minimumTimestamp
= ts
;
274 protected boolean compareAndSetMin(long expect
, long update
) {
275 if (minimumTimestamp
!= expect
) {
278 minimumTimestamp
= update
;
283 protected boolean compareAndSetMax(long expect
, long update
) {
284 if (maximumTimestamp
!= expect
) {
287 maximumTimestamp
= update
;
292 public long getMin() {
293 return minimumTimestamp
;
297 public long getMax() {
298 return maximumTimestamp
;
302 //In order to estimate the heap size, this inner class need to be accessible to TestHeapSize.
303 public static class SyncTimeRangeTracker
extends TimeRangeTracker
{
304 private final AtomicLong minimumTimestamp
= new AtomicLong(INITIAL_MIN_TIMESTAMP
);
305 private final AtomicLong maximumTimestamp
= new AtomicLong(INITIAL_MAX_TIMESTAMP
);
307 private SyncTimeRangeTracker() {
310 SyncTimeRangeTracker(final TimeRangeTracker trt
) {
311 this.minimumTimestamp
.set(trt
.getMin());
312 this.maximumTimestamp
.set(trt
.getMax());
315 SyncTimeRangeTracker(long minimumTimestamp
, long maximumTimestamp
) {
316 this.minimumTimestamp
.set(minimumTimestamp
);
317 this.maximumTimestamp
.set(maximumTimestamp
);
321 protected void setMax(long ts
) {
322 maximumTimestamp
.set(ts
);
326 protected void setMin(long ts
) {
327 minimumTimestamp
.set(ts
);
331 protected boolean compareAndSetMin(long expect
, long update
) {
332 return minimumTimestamp
.compareAndSet(expect
, update
);
336 protected boolean compareAndSetMax(long expect
, long update
) {
337 return maximumTimestamp
.compareAndSet(expect
, update
);
341 public long getMin() {
342 return minimumTimestamp
.get();
346 public long getMax() {
347 return maximumTimestamp
.get();