Skip to content

Commit

Permalink
HBASE-15650 Remove TimeRangeTracker as point of contention when many…
Browse files Browse the repository at this point in the history
… threads reading a StoreFile

    Refactor so we use the immutable, unsynchronized TimeRange when doing
    time-based checks at read time rather than use heavily synchronized
    TimeRangeTracker; let TimeRangeTracker be for write-time only.

    While in here, changed the Segment stuff so that when an immutable
    segment, it uses TimeRange rather than TimeRangeTracker too.

    M hbase-common/src/main/java/org/apache/hadoop/hbase/io/TimeRange.java
      Make allTime final.
      Add a includesTimeRange method copied from TimeRangeTracker.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/TimeRangeTracker.java
      Change name of a few methods so they match TimeRange methods that do
      same thing.
      (getTimeRangeTracker, getTimeRange, toTimeRange) add utility methods

    M hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/ImmutableSegment.java
      Change ImmutableSegment so it uses a TimeRange rather than
      TimeRangeTracker.. it is read-only. Redo shouldSeek, getMinTimestamp,
      updateMetaInfo, and getTimeRangeTracker so we use TimeRange-based
      implementations instead of TimeRangeTracker implementations.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MutableSegment.java
      Implement shouldSeek, getMinTimestamp, updateMetaInfo, and
      getTimeRangeTracker using TimeRangeTracker.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/Segment.java
      Make methods that were using TimeRangeTracker abstract and instead
      have the implementations do these methods how they want either using
      TimeRangeTracker when a mutable segment or TimeRange when an immutable
      segment.

    M hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/StoreFile.java
      Change Reader to use TimeRange-based checks instead of
      TimeRangeTracker.

    Signed-off-by: stack <stack@apache.org>
  • Loading branch information
saintstack committed Apr 15, 2016
1 parent 6930da7 commit d815211
Show file tree
Hide file tree
Showing 17 changed files with 213 additions and 136 deletions.
Expand Up @@ -36,11 +36,13 @@
@InterfaceAudience.Public @InterfaceAudience.Public
@InterfaceStability.Stable @InterfaceStability.Stable
public class TimeRange { public class TimeRange {
private static final long MIN_TIME = 0L; static final long INITIAL_MIN_TIMESTAMP = 0l;
private static final long MAX_TIME = Long.MAX_VALUE; private static final long MIN_TIME = INITIAL_MIN_TIMESTAMP;
static final long INITIAL_MAX_TIMESTAMP = Long.MAX_VALUE;
static final long MAX_TIME = INITIAL_MAX_TIMESTAMP;
private long minStamp = MIN_TIME; private long minStamp = MIN_TIME;
private long maxStamp = MAX_TIME; private long maxStamp = MAX_TIME;
private boolean allTime = false; private final boolean allTime;


/** /**
* Default constructor. * Default constructor.
Expand All @@ -56,9 +58,7 @@ public TimeRange() {
*/ */
public TimeRange(long minStamp) { public TimeRange(long minStamp) {
this.minStamp = minStamp; this.minStamp = minStamp;
if (this.minStamp == MIN_TIME){ this.allTime = this.minStamp == MIN_TIME;
this.allTime = true;
}
} }


/** /**
Expand All @@ -67,6 +67,7 @@ public TimeRange(long minStamp) {
*/ */
public TimeRange(byte [] minStamp) { public TimeRange(byte [] minStamp) {
this.minStamp = Bytes.toLong(minStamp); this.minStamp = Bytes.toLong(minStamp);
this.allTime = false;
} }


/** /**
Expand All @@ -80,14 +81,12 @@ public TimeRange(long minStamp, long maxStamp) {
throw new IllegalArgumentException("Timestamp cannot be negative. minStamp:" + minStamp throw new IllegalArgumentException("Timestamp cannot be negative. minStamp:" + minStamp
+ ", maxStamp:" + maxStamp); + ", maxStamp:" + maxStamp);
} }
if(maxStamp < minStamp) { if (maxStamp < minStamp) {
throw new IllegalArgumentException("maxStamp is smaller than minStamp"); throw new IllegalArgumentException("maxStamp is smaller than minStamp");
} }
this.minStamp = minStamp; this.minStamp = minStamp;
this.maxStamp = maxStamp; this.maxStamp = maxStamp;
if (this.minStamp == MIN_TIME && this.maxStamp == MAX_TIME){ this.allTime = this.minStamp == MIN_TIME && this.maxStamp == MAX_TIME;
this.allTime = true;
}
} }


/** /**
Expand Down Expand Up @@ -146,11 +145,27 @@ public boolean withinTimeRange(byte [] bytes, int offset) {
* @return true if within TimeRange, false if not * @return true if within TimeRange, false if not
*/ */
public boolean withinTimeRange(long timestamp) { public boolean withinTimeRange(long timestamp) {
if(allTime) return true; if (this.allTime) {
return true;
}
// check if >= minStamp // check if >= minStamp
return (minStamp <= timestamp && timestamp < maxStamp); return (minStamp <= timestamp && timestamp < maxStamp);
} }


/**
* Check if the range has any overlap with TimeRange
* @param tr TimeRange
* @return True if there is overlap, false otherwise
*/
// This method came from TimeRangeTracker. We used to go there for this function but better
// to come here to the immutable, unsynchronized datastructure at read time.
public boolean includesTimeRange(final TimeRange tr) {
if (this.allTime) {
return true;
}
return getMin() < tr.getMax() && getMax() >= tr.getMin();
}

/** /**
* Check if the specified timestamp is within this TimeRange. * Check if the specified timestamp is within this TimeRange.
* <p> * <p>
Expand Down
Expand Up @@ -19,6 +19,8 @@
*/ */
package org.apache.hadoop.hbase.io.hfile; package org.apache.hadoop.hbase.io.hfile;


import static com.codahale.metrics.MetricRegistry.name;

import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInput; import java.io.DataInput;
import java.io.IOException; import java.io.IOException;
Expand Down Expand Up @@ -47,50 +49,47 @@
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured; import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellComparator; import org.apache.hadoop.hbase.CellComparator;
import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HBaseInterfaceAudience; import org.apache.hadoop.hbase.HBaseInterfaceAudience;
import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.KeyValueUtil;
import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.Tag; import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.TagUtil; import org.apache.hadoop.hbase.TagUtil;
import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.hbase.KeyValueUtil;
import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper; import org.apache.hadoop.hbase.io.FSDataInputStreamWrapper;
import org.apache.hadoop.hbase.io.hfile.HFile.FileInfo; import org.apache.hadoop.hbase.io.hfile.HFile.FileInfo;
import org.apache.hadoop.hbase.mob.MobUtils; import org.apache.hadoop.hbase.mob.MobUtils;
import org.apache.hadoop.hbase.regionserver.TimeRangeTracker; import org.apache.hadoop.hbase.regionserver.TimeRangeTracker;
import org.apache.hadoop.hbase.util.BloomFilter; import org.apache.hadoop.hbase.util.BloomFilter;
import org.apache.hadoop.hbase.util.BloomFilterUtil;
import org.apache.hadoop.hbase.util.BloomFilterFactory; import org.apache.hadoop.hbase.util.BloomFilterFactory;
import org.apache.hadoop.hbase.util.BloomFilterUtil;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.util.FSUtils;
import org.apache.hadoop.hbase.util.HFileArchiveUtil; import org.apache.hadoop.hbase.util.HFileArchiveUtil;
import org.apache.hadoop.hbase.util.Writables;
import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner; import org.apache.hadoop.util.ToolRunner;


import com.codahale.metrics.Histogram; import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Counter; import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge; import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter; import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricFilter; import com.codahale.metrics.MetricFilter;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.ScheduledReporter; import com.codahale.metrics.ScheduledReporter;
import com.codahale.metrics.Snapshot; import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer; import com.codahale.metrics.Timer;


import static com.codahale.metrics.MetricRegistry.name;

/** /**
* Implements pretty-printing functionality for {@link HFile}s. * Implements pretty-printing functionality for {@link HFile}s.
*/ */
Expand Down Expand Up @@ -505,10 +504,8 @@ private void printMeta(HFile.Reader reader, Map<byte[], byte[]> fileInfo)
long seqid = Bytes.toLong(e.getValue()); long seqid = Bytes.toLong(e.getValue());
System.out.println(seqid); System.out.println(seqid);
} else if (Bytes.compareTo(e.getKey(), Bytes.toBytes("TIMERANGE")) == 0) { } else if (Bytes.compareTo(e.getKey(), Bytes.toBytes("TIMERANGE")) == 0) {
TimeRangeTracker timeRangeTracker = new TimeRangeTracker(); TimeRangeTracker timeRangeTracker = TimeRangeTracker.getTimeRangeTracker(e.getValue());
Writables.copyWritable(e.getValue(), timeRangeTracker); System.out.println(timeRangeTracker.getMin() + "...." + timeRangeTracker.getMax());
System.out.println(timeRangeTracker.getMinimumTimestamp() + "...."
+ timeRangeTracker.getMaximumTimestamp());
} else if (Bytes.compareTo(e.getKey(), FileInfo.AVG_KEY_LEN) == 0 } else if (Bytes.compareTo(e.getKey(), FileInfo.AVG_KEY_LEN) == 0
|| Bytes.compareTo(e.getKey(), FileInfo.AVG_VALUE_LEN) == 0) { || Bytes.compareTo(e.getKey(), FileInfo.AVG_VALUE_LEN) == 0) {
System.out.println(Bytes.toInt(e.getValue())); System.out.println(Bytes.toInt(e.getValue()));
Expand Down
Expand Up @@ -161,7 +161,7 @@ protected void performMobFlush(MemStoreSnapshot snapshot, long cacheFlushId,
HConstants.COMPACTION_KV_MAX_DEFAULT); HConstants.COMPACTION_KV_MAX_DEFAULT);
long mobCount = 0; long mobCount = 0;
long mobSize = 0; long mobSize = 0;
long time = snapshot.getTimeRangeTracker().getMaximumTimestamp(); long time = snapshot.getTimeRangeTracker().getMax();
mobFileWriter = mobStore.createWriterInTmp(new Date(time), snapshot.getCellsCount(), mobFileWriter = mobStore.createWriterInTmp(new Date(time), snapshot.getCellsCount(),
store.getFamily().getCompression(), store.getRegionInfo().getStartKey()); store.getFamily().getCompression(), store.getRegionInfo().getStartKey());
// the target path is {tableName}/.mob/{cfName}/mobFiles // the target path is {tableName}/.mob/{cfName}/mobFiles
Expand Down
Expand Up @@ -78,8 +78,7 @@ protected AbstractMemStore(final Configuration conf, final CellComparator c) {


protected void resetCellSet() { protected void resetCellSet() {
// Reset heap to not include any keys // Reset heap to not include any keys
this.active = SegmentFactory.instance().createMutableSegment( this.active = SegmentFactory.instance().createMutableSegment(conf, comparator, DEEP_OVERHEAD);
conf, comparator, DEEP_OVERHEAD);
this.timeOfOldestEdit = Long.MAX_VALUE; this.timeOfOldestEdit = Long.MAX_VALUE;
} }


Expand Down
@@ -1,5 +1,4 @@
/** /**
*
* Licensed to the Apache Software Foundation (ASF) under one * Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file * or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information * distributed with this work for additional information
Expand Down Expand Up @@ -98,7 +97,6 @@ public MemStoreSnapshot snapshot(long flushOpSeqId) {
} }
} }
return new MemStoreSnapshot(this.snapshotId, getSnapshot()); return new MemStoreSnapshot(this.snapshotId, getSnapshot());

} }


@Override @Override
Expand Down Expand Up @@ -190,5 +188,4 @@ public static void main(String [] args) {
LOG.info("Waiting " + seconds + " seconds while heap dump is taken"); LOG.info("Waiting " + seconds + " seconds while heap dump is taken");
LOG.info("Exiting."); LOG.info("Exiting.");
} }

}
}
Expand Up @@ -18,7 +18,10 @@
*/ */
package org.apache.hadoop.hbase.regionserver; package org.apache.hadoop.hbase.regionserver;


import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.TimeRange;
import org.apache.hadoop.hbase.util.CollectionBackedScanner; import org.apache.hadoop.hbase.util.CollectionBackedScanner;


/** /**
Expand All @@ -29,9 +32,16 @@
*/ */
@InterfaceAudience.Private @InterfaceAudience.Private
public class ImmutableSegment extends Segment { public class ImmutableSegment extends Segment {
/**
* This is an immutable segment so use the read-only TimeRange rather than the heavy-weight
* TimeRangeTracker with all its synchronization when doing time range stuff.
*/
private final TimeRange timeRange;


protected ImmutableSegment(Segment segment) { protected ImmutableSegment(Segment segment) {
super(segment); super(segment);
TimeRangeTracker trt = getTimeRangeTracker();
this.timeRange = trt == null? null: trt.toTimeRange();
} }


/** /**
Expand All @@ -43,4 +53,19 @@ public KeyValueScanner getKeyValueScanner() {
return new CollectionBackedScanner(getCellSet(), getComparator()); return new CollectionBackedScanner(getCellSet(), getComparator());
} }


} @Override
public boolean shouldSeek(Scan scan, long oldestUnexpiredTS) {
return this.timeRange.includesTimeRange(scan.getTimeRange()) &&
this.timeRange.getMax() >= oldestUnexpiredTS;
}

@Override
public long getMinTimestamp() {
return this.timeRange.getMin();
}

@Override
protected void updateMetaInfo(Cell toAdd, long s) {
throw new IllegalAccessError("This is an immutable segment");
}
}
Expand Up @@ -26,7 +26,6 @@
*/ */
@InterfaceAudience.Private @InterfaceAudience.Private
public class MemStoreSnapshot { public class MemStoreSnapshot {

private final long id; private final long id;
private final int cellsCount; private final int cellsCount;
private final long size; private final long size;
Expand Down Expand Up @@ -84,4 +83,4 @@ public KeyValueScanner getScanner() {
public boolean isTagsPresent() { public boolean isTagsPresent() {
return this.tagsPresent; return this.tagsPresent;
} }
} }
Expand Up @@ -21,13 +21,13 @@
import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellComparator; import org.apache.hadoop.hbase.CellComparator;
import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.client.Scan;


/** /**
* A mutable segment in memstore, specifically the active segment. * A mutable segment in memstore, specifically the active segment.
*/ */
@InterfaceAudience.Private @InterfaceAudience.Private
public class MutableSegment extends Segment { public class MutableSegment extends Segment {

protected MutableSegment(CellSet cellSet, CellComparator comparator, MemStoreLAB memStoreLAB, protected MutableSegment(CellSet cellSet, CellComparator comparator, MemStoreLAB memStoreLAB,
long size) { long size) {
super(cellSet, comparator, memStoreLAB, size); super(cellSet, comparator, memStoreLAB, size);
Expand Down Expand Up @@ -65,4 +65,28 @@ public long rollback(Cell cell) {
Cell first() { Cell first() {
return this.getCellSet().first(); return this.getCellSet().first();
} }
}
@Override
public boolean shouldSeek(Scan scan, long oldestUnexpiredTS) {
return (getTimeRangeTracker().includesTimeRange(scan.getTimeRange())
&& (getTimeRangeTracker().getMax() >= oldestUnexpiredTS));
}

@Override
public long getMinTimestamp() {
return getTimeRangeTracker().getMin();
}

@Override
protected void updateMetaInfo(Cell toAdd, long s) {
getTimeRangeTracker().includeTimestamp(toAdd);
size.addAndGet(s);
// In no tags case this NoTagsKeyValue.getTagsLength() is a cheap call.
// When we use ACL CP or Visibility CP which deals with Tags during
// mutation, the TagRewriteCell.getTagsLength() is a cheaper call. We do not
// parse the byte[] to identify the tags length.
if(toAdd.getTagsLength() > 0) {
tagsPresent = true;
}
}
}

0 comments on commit d815211

Please sign in to comment.