diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/TimeRangeTracker.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/TimeRangeTracker.java index 6f25129..e55d86f 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/TimeRangeTracker.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/TimeRangeTracker.java @@ -22,13 +22,10 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; -import org.apache.hadoop.hbase.KeyValue; -import org.apache.hadoop.hbase.KeyValue.Type; +import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.io.TimeRange; -import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.io.Writable; /** @@ -40,56 +37,70 @@ import org.apache.hadoop.io.Writable; */ @InterfaceAudience.Private public class TimeRangeTracker implements Writable { - - long minimumTimestamp = -1; + static final long INITIAL_MINIMUM_TIMESTAMP = Long.MAX_VALUE; + long minimumTimestamp = INITIAL_MINIMUM_TIMESTAMP; long maximumTimestamp = -1; /** * Default constructor. * Initializes TimeRange to be null */ - public TimeRangeTracker() { - - } + public TimeRangeTracker() {} /** * Copy Constructor * @param trt source TimeRangeTracker */ public TimeRangeTracker(final TimeRangeTracker trt) { - this.minimumTimestamp = trt.getMinimumTimestamp(); - this.maximumTimestamp = trt.getMaximumTimestamp(); + set(trt.getMinimumTimestamp(), trt.getMaximumTimestamp()); } public TimeRangeTracker(long minimumTimestamp, long maximumTimestamp) { - this.minimumTimestamp = minimumTimestamp; - this.maximumTimestamp = maximumTimestamp; + set(minimumTimestamp, maximumTimestamp); + } + + private void set(final long min, final long max) { + this.minimumTimestamp = min; + this.maximumTimestamp = max; } /** - * Update the current TimestampRange to include the timestamp from Cell - * If the Key is of type DeleteColumn or DeleteFamily, it includes the - * entire time range from 0 to timestamp of the key. - * @param cell the Cell to include + * @param l + * @return True if we initialized values */ - public void includeTimestamp(final Cell cell) { - includeTimestamp(cell.getTimestamp()); - if (CellUtil.isDeleteColumnOrFamily(cell)) { - includeTimestamp(0); + private boolean init(final long l) { + if (this.minimumTimestamp != INITIAL_MINIMUM_TIMESTAMP) return false; + set(l, l); + return true; + } + + private synchronized boolean setMin(final long min) { + if (init(min)) return true; + if (this.minimumTimestamp > min) { + this.minimumTimestamp = min; + return true; } + return false; + } + + private synchronized boolean setMax(final long max) { + if (init(max)) return true; + if (this.maximumTimestamp < max) { + this.maximumTimestamp = max; + return true; + } + return false; } /** - * Update the current TimestampRange to include the timestamp from Key. + * Update the current TimestampRange to include the timestamp from Cell * If the Key is of type DeleteColumn or DeleteFamily, it includes the * entire time range from 0 to timestamp of the key. - * @param key + * @param cell the Cell to include */ - public void includeTimestamp(final byte[] key) { - includeTimestamp(Bytes.toLong(key,key.length-KeyValue.TIMESTAMP_TYPE_SIZE)); - int type = key[key.length - 1]; - if (type == Type.DeleteColumn.getCode() || - type == Type.DeleteFamily.getCode()) { + public void includeTimestamp(final Cell cell) { + includeTimestamp(cell.getTimestamp()); + if (CellUtil.isDeleteColumnOrFamily(cell)) { includeTimestamp(0); } } @@ -98,18 +109,11 @@ public class TimeRangeTracker implements Writable { * If required, update the current TimestampRange to include timestamp * @param timestamp the timestamp value to include */ - private synchronized void includeTimestamp(final long timestamp) { - if (maximumTimestamp == -1) { - minimumTimestamp = timestamp; - maximumTimestamp = timestamp; - } - else if (minimumTimestamp > timestamp) { - minimumTimestamp = timestamp; - } - else if (maximumTimestamp < timestamp) { - maximumTimestamp = timestamp; - } - return; + void includeTimestamp(final long timestamp) { + // Do test outside of synchronization block. Synchronizaton in here can be problematic + // when many threads writing one Store -- they can all pile up trying to add here. + if (timestamp < this.minimumTimestamp) setMin(timestamp); + else if (timestamp > this.maximumTimestamp) setMax(timestamp); } /** @@ -118,8 +122,7 @@ public class TimeRangeTracker implements Writable { * @return True if there is overlap, false otherwise */ public synchronized boolean includesTimeRange(final TimeRange tr) { - return (this.minimumTimestamp < tr.getMax() && - this.maximumTimestamp >= tr.getMin()); + return (this.minimumTimestamp < tr.getMax() && this.maximumTimestamp >= tr.getMin()); } /** @@ -150,4 +153,4 @@ public class TimeRangeTracker implements Writable { public synchronized String toString() { return "[" + minimumTimestamp + "," + maximumTimestamp + "]"; } -} +} \ No newline at end of file diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTimeRangeTracker.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTimeRangeTracker.java new file mode 100644 index 0000000..d064671 --- /dev/null +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTimeRangeTracker.java @@ -0,0 +1,75 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.regionserver; + +import static org.junit.Assert.assertTrue; + +import org.apache.hadoop.hbase.io.TimeRange; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.testclassification.RegionServerTests; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category({RegionServerTests.class, SmallTests.class}) +public class TestTimeRangeTracker { + @Test + public void testAlwaysDecrementingSetsMaximum() { + TimeRangeTracker trr = new TimeRangeTracker(); + trr.includeTimestamp(3); + trr.includeTimestamp(2); + trr.includeTimestamp(1); + assertTrue(trr.getMinimumTimestamp() != TimeRangeTracker.INITIAL_MINIMUM_TIMESTAMP); + assertTrue(trr.getMaximumTimestamp() != -1 /*The initial max value*/); + } + + @Test + public void testSimpleInRange() { + TimeRangeTracker trr = new TimeRangeTracker(); + trr.includeTimestamp(0); + trr.includeTimestamp(2); + assertTrue(trr.includesTimeRange(new TimeRange(1))); + } + + /** + * Bit of code to test concurrent access on this class. + * @param args + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + long start = System.currentTimeMillis(); + final TimeRangeTracker trr = new TimeRangeTracker(); + final int threadCount = 5; + final int calls = 1024 * 1024 * 128; + Thread [] threads = new Thread[threadCount]; + for (int i = 0; i < threads.length; i++) { + Thread t = new Thread("" + i) { + @Override + public void run() { + for (int i = 0; i < calls; i++) trr.includeTimestamp(i); + } + }; + t.start(); + threads[i] = t; + } + for (int i = 0; i < threads.length; i++) { + threads[i].join(); + } + System.out.println(trr.getMinimumTimestamp() + " " + trr.getMaximumTimestamp() + " " + + (System.currentTimeMillis() - start)); + } +} \ No newline at end of file