Skip to content

Commit

Permalink
PHOENIX-4074 Race condition in LazyValueGetter (Samarth Jain)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesRTaylor committed Aug 8, 2017
1 parent 30224d3 commit 29b7663
Showing 1 changed file with 58 additions and 54 deletions.
Expand Up @@ -38,66 +38,70 @@
*/
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;
}
}

0 comments on commit 29b7663

Please sign in to comment.