HBASE-26412 Handle sink failure in RegionReplicationSink (#3815)
[hbase.git] / hbase-server / src / main / java / org / apache / hadoop / hbase / regionserver / TimeRangeTracker.java
blobfdf9db273a69e81d98ed695f5a1743e687d9250d
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.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;
37 /**
38 * Stores minimum and maximum timestamp values, it is [minimumTimestamp, maximumTimestamp] in
39 * interval notation.
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 {
51 public enum Type {
52 // thread-unsafe
53 NON_SYNC,
54 // thread-safe
55 SYNC
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) {
62 switch (type) {
63 case NON_SYNC:
64 return new NonSyncTimeRangeTracker();
65 case SYNC:
66 return new SyncTimeRangeTracker();
67 default:
68 throw new UnsupportedOperationException("The type:" + type + " is unsupported");
72 public static TimeRangeTracker create(Type type, TimeRangeTracker trt) {
73 switch (type) {
74 case NON_SYNC:
75 return new NonSyncTimeRangeTracker(trt);
76 case SYNC:
77 return new SyncTimeRangeTracker(trt);
78 default:
79 throw new UnsupportedOperationException("The type:" + type + " is unsupported");
83 public static TimeRangeTracker create(Type type, long minimumTimestamp, long maximumTimestamp) {
84 switch (type) {
85 case NON_SYNC:
86 return new NonSyncTimeRangeTracker(minimumTimestamp, maximumTimestamp);
87 case SYNC:
88 return new SyncTimeRangeTracker(minimumTimestamp, maximumTimestamp);
89 default:
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);
98 /**
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)) {
107 includeTimestamp(0);
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();
124 } else {
125 // successfully set minimumTimestamp, break.
126 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.
143 return;
147 long curMaxTimestamp = getMax();
149 if (timestamp > curMaxTimestamp) {
150 while (timestamp > curMaxTimestamp) {
151 if (!compareAndSetMax(curMaxTimestamp, timestamp)) {
152 curMaxTimestamp = getMax();
153 } else {
154 // successfully set maximumTimestamp, break
155 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();
180 @Override
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());
202 } else {
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() {
233 long min = getMin();
234 long max = getMax();
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;
263 @Override
264 protected void setMax(long ts) {
265 maximumTimestamp = ts;
268 @Override
269 protected void setMin(long ts) {
270 minimumTimestamp = ts;
273 @Override
274 protected boolean compareAndSetMin(long expect, long update) {
275 if (minimumTimestamp != expect) {
276 return false;
278 minimumTimestamp = update;
279 return true;
282 @Override
283 protected boolean compareAndSetMax(long expect, long update) {
284 if (maximumTimestamp != expect) {
285 return false;
287 maximumTimestamp = update;
288 return true;
291 @Override
292 public long getMin() {
293 return minimumTimestamp;
296 @Override
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);
320 @Override
321 protected void setMax(long ts) {
322 maximumTimestamp.set(ts);
325 @Override
326 protected void setMin(long ts) {
327 minimumTimestamp.set(ts);
330 @Override
331 protected boolean compareAndSetMin(long expect, long update) {
332 return minimumTimestamp.compareAndSet(expect, update);
335 @Override
336 protected boolean compareAndSetMax(long expect, long update) {
337 return maximumTimestamp.compareAndSet(expect, update);
340 @Override
341 public long getMin() {
342 return minimumTimestamp.get();
345 @Override
346 public long getMax() {
347 return maximumTimestamp.get();