PHOENIX-4074 Race condition in LazyValueGetter (Samarth Jain)
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/1ca62e4a Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/1ca62e4a Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/1ca62e4a Branch: refs/heads/4.x-HBase-1.1 Commit: 1ca62e4a49c890fbec57c529c3cb1fe8a4cb27d1 Parents: ed180c4 Author: James Taylor <[email protected]> Authored: Mon Aug 7 19:18:20 2017 -0700 Committer: James Taylor <[email protected]> Committed: Mon Aug 7 23:05:01 2017 -0700 ---------------------------------------------------------------------- .../index/covered/data/LazyValueGetter.java | 112 ++++++++++--------- 1 file changed, 58 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/1ca62e4a/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/covered/data/LazyValueGetter.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/covered/data/LazyValueGetter.java b/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/covered/data/LazyValueGetter.java index bafefce..1049c89 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/covered/data/LazyValueGetter.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/hbase/index/covered/data/LazyValueGetter.java @@ -38,66 +38,70 @@ import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr; */ public class LazyValueGetter implements ValueGetter { - private CoveredDeleteScanner scan; - private volatile Map<ColumnReference, ImmutableBytesWritable> values; - private byte[] row; - - /** - * Back the getter with a {@link Scanner} to actually access the local data. - * @param scan backing scanner - * @param currentRow row key for the row to seek in the scanner - */ - public LazyValueGetter(CoveredDeleteScanner scan, byte[] currentRow) { - this.scan = scan; - this.row = currentRow; - } + private CoveredDeleteScanner scan; + private volatile Map<ColumnReference, ImmutableBytesWritable> values; + private byte[] row; - @Override - public ImmutableBytesWritable getLatestValue(ColumnReference ref, long ts) throws IOException { - // ensure we have a backing map - if (values == null) { - synchronized (this) { - values = Collections.synchronizedMap(new HashMap<ColumnReference, ImmutableBytesWritable>()); - } + /** + * Back the getter with a {@link Scanner} to actually access the local data. + * @param scan backing scanner + * @param currentRow row key for the row to seek in the scanner + */ + public LazyValueGetter(CoveredDeleteScanner scan, byte[] currentRow) { + this.scan = scan; + this.row = currentRow; } - // check the value in the map - ImmutableBytesWritable value = values.get(ref); - if (value == null) { - value = get(ref); - DeleteTracker deleteTracker = scan.getDeleteTracker(); - if (value == null) { - // Delete family is used for row deletion. Family won't necessarily match as we'll be at - // the delete family marker on the last column family if there is one. - if (deleteTracker.deleteFamily != null && deleteTracker.deleteFamily.getTimestamp() == ts) { - value = HIDDEN_BY_DELETE; - } - } - values.put(ref, value); - } + @Override + public ImmutableBytesWritable getLatestValue(ColumnReference ref, long ts) throws IOException { + Map<ColumnReference, ImmutableBytesWritable> v = values; + // ensure we have a backing map + if (v == null) { + synchronized (this) { + v = values; + if (v == null) { + v = values = Collections.synchronizedMap(new HashMap<ColumnReference, ImmutableBytesWritable>()); + } + } + } - return value; - } + // check the value in the map + ImmutableBytesWritable value = v.get(ref); + if (value == null) { + value = get(ref); + DeleteTracker deleteTracker = scan.getDeleteTracker(); + if (value == null) { + // Delete family is used for row deletion. Family won't necessarily match as we'll be at + // the delete family marker on the last column family if there is one. + if (deleteTracker.deleteFamily != null && deleteTracker.deleteFamily.getTimestamp() == ts) { + value = HIDDEN_BY_DELETE; + } + } + v.put(ref, value); + } - /** - * @param ref - * @return the first value on the scanner for the given column - */ - private ImmutableBytesPtr get(ColumnReference ref) throws IOException { - KeyValue first = ref.getFirstKeyValueForRow(row); - if (!scan.seek(first)) { - return null; + return value; } - // there is a next value - we only care about the current value, so we can just snag that - Cell next = scan.next(); - if (ref.matches(next)) { - return new ImmutableBytesPtr(next.getValueArray(), next.getValueOffset(), next.getValueLength()); + + /** + * @param ref + * @return the first value on the scanner for the given column + */ + private ImmutableBytesPtr get(ColumnReference ref) throws IOException { + KeyValue first = ref.getFirstKeyValueForRow(row); + if (!scan.seek(first)) { + return null; + } + // there is a next value - we only care about the current value, so we can just snag that + Cell next = scan.next(); + if (ref.matches(next)) { + return new ImmutableBytesPtr(next.getValueArray(), next.getValueOffset(), next.getValueLength()); + } + return null; } - return null; - } - @Override - public byte[] getRowKey() { - return this.row; - } + @Override + public byte[] getRowKey() { + return this.row; + } } \ No newline at end of file
