diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ClassSize.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ClassSize.java index 1bb34e1..72a064c 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ClassSize.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ClassSize.java @@ -65,7 +65,10 @@ public class ClassSize { /** String overhead */ public static final int STRING; - /** Overhead for TreeMap */ + /** String overhead */ + public static final int RANGE_TIMESTAMP; + + /** Overhead for TreeMap */ public static final int TREEMAP; /** Overhead for ConcurrentHashMap */ @@ -190,7 +193,9 @@ public class ClassSize { TIMERANGE = align(ClassSize.OBJECT + Bytes.SIZEOF_LONG * 2 + Bytes.SIZEOF_BOOLEAN); - TIMERANGE_TRACKER = align(ClassSize.OBJECT + Bytes.SIZEOF_LONG * 2); + RANGE_TIMESTAMP = align(ClassSize.OBJECT + Bytes.SIZEOF_LONG * 2); + + TIMERANGE_TRACKER = align(ClassSize.OBJECT + REFERENCE); CELL_SKIPLIST_SET = align(OBJECT + REFERENCE); } 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 0044634..8ac44ed 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 @@ -21,6 +21,7 @@ package org.apache.hadoop.hbase.regionserver; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; @@ -37,41 +38,26 @@ import org.apache.hadoop.io.Writable; */ @InterfaceAudience.Private public class TimeRangeTracker implements Writable { - static final long INITIAL_MINIMUM_TIMESTAMP = Long.MAX_VALUE; - long minimumTimestamp = INITIAL_MINIMUM_TIMESTAMP; - long maximumTimestamp = -1; - + public static final long INITIAL_MINIMUM_TIMESTAMP = Long.MAX_VALUE; + protected AtomicReference timeRange; /** * Default constructor. * Initializes TimeRange to be null */ - public TimeRangeTracker() {} + public TimeRangeTracker() { + timeRange = new AtomicReference(new RangeTimestamp()); + } /** * Copy Constructor * @param trt source TimeRangeTracker */ public TimeRangeTracker(final TimeRangeTracker trt) { - set(trt.getMinimumTimestamp(), trt.getMaximumTimestamp()); + this(trt.getMinimumTimestamp(), trt.getMaximumTimestamp()); } public TimeRangeTracker(long minimumTimestamp, long maximumTimestamp) { - set(minimumTimestamp, maximumTimestamp); - } - - private void set(final long min, final long max) { - this.minimumTimestamp = min; - this.maximumTimestamp = max; - } - - /** - * @param l - * @return True if we initialized values - */ - private boolean init(final long l) { - if (this.minimumTimestamp != INITIAL_MINIMUM_TIMESTAMP) return false; - set(l, l); - return true; + timeRange = new AtomicReference(new RangeTimestamp(minimumTimestamp,maximumTimestamp)); } /** @@ -92,26 +78,19 @@ public class TimeRangeTracker implements Writable { * @param timestamp the timestamp value to include */ void includeTimestamp(final long timestamp) { - // Do test outside of synchronization block. Synchronization in here can be problematic - // when many threads writing one Store -- they can all pile up trying to add in here. - // Happens when doing big write upload where we are hammering on one region. - if (timestamp < this.minimumTimestamp) { - synchronized (this) { - if (!init(timestamp)) { - if (timestamp < this.minimumTimestamp) { - this.minimumTimestamp = timestamp; - } - } + while (true) { + RangeTimestamp rt = timeRange.get(); + if ( rt.isMaxTs(timestamp) || rt.isMinTs(timestamp)) { + if (timeRange.compareAndSet(rt, + new RangeTimestamp(rt.isMinTs(timestamp) ? timestamp : rt.minimumTimestamp, + rt.isMaxTs(timestamp) ? timestamp : rt.maximumTimestamp))) { + return; // CAS Succeeded + } else { + // CAS Miss, Spin + } + } else + return; // No need to modify } - } else if (timestamp > this.maximumTimestamp) { - synchronized (this) { - if (!init(timestamp)) { - if (this.maximumTimestamp < timestamp) { - this.maximumTimestamp = timestamp; - } - } - } - } } /** @@ -120,35 +99,63 @@ 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()); + RangeTimestamp rt = this.timeRange.get(); + return (rt.minimumTimestamp < tr.getMax() && + rt.maximumTimestamp >= tr.getMin()); } /** * @return the minimumTimestamp */ public synchronized long getMinimumTimestamp() { - return minimumTimestamp; + return this.timeRange.get().minimumTimestamp; } /** * @return the maximumTimestamp */ public synchronized long getMaximumTimestamp() { - return maximumTimestamp; + return timeRange.get().maximumTimestamp; } public synchronized void write(final DataOutput out) throws IOException { - out.writeLong(minimumTimestamp); - out.writeLong(maximumTimestamp); + RangeTimestamp rt = this.timeRange.get(); + out.writeLong(rt.minimumTimestamp); + out.writeLong(rt.maximumTimestamp); } public synchronized void readFields(final DataInput in) throws IOException { - this.minimumTimestamp = in.readLong(); - this.maximumTimestamp = in.readLong(); + this.timeRange = new AtomicReference( + new RangeTimestamp(in.readLong(),in.readLong())); } + public static class RangeTimestamp { + long minimumTimestamp = INITIAL_MINIMUM_TIMESTAMP; + long maximumTimestamp = -1; + + public RangeTimestamp() {}; + + public RangeTimestamp(long minimumTimestamp, long maximumTimestamp) { + this.minimumTimestamp = minimumTimestamp; + this.maximumTimestamp = maximumTimestamp; + } + + public boolean isMaxTs(long timestamp) { + return maximumTimestamp < timestamp; + } + + public boolean isMinTs(long timestamp) { + return minimumTimestamp > timestamp; + } + + @Override + public String toString() { + return "[" + minimumTimestamp + "," + maximumTimestamp + "]"; + } + } + @Override - public synchronized String toString() { - return "[" + minimumTimestamp + "," + maximumTimestamp + "]"; + public String toString() { + return timeRange.get().toString(); } } \ No newline at end of file diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/MockStoreFile.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/MockStoreFile.java index 3a12674..0eab101 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/MockStoreFile.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/MockStoreFile.java @@ -108,7 +108,7 @@ public class MockStoreFile extends StoreFile { @Override public long getMaxTimestamp() { - return timeRange == null ? Long.MAX_VALUE : timeRange.maximumTimestamp; + return timeRange == null ? Long.MAX_VALUE : timeRange.getMaximumTimestamp(); } @Override