Skip to content

Commit

Permalink
GH-4973 improve performance og inner merge join (#4975)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmottestad authored May 16, 2024
1 parent ccf6250 commit a7a3171
Show file tree
Hide file tree
Showing 10 changed files with 671 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ public String toString() {

Iterator<Binding> iter = iterator();
while (iter.hasNext()) {
sb.append(iter.next().toString());
Binding next = iter.next();
sb.append(next != null ? next.toString() : "null");
if (iter.hasNext()) {
sb.append(';');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import org.eclipse.rdf4j.common.annotation.InternalUseOnly;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.util.Values;
import org.eclipse.rdf4j.query.AbstractBindingSet;
import org.eclipse.rdf4j.query.Binding;
import org.eclipse.rdf4j.query.BindingSet;
Expand All @@ -42,15 +43,15 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
private static final long serialVersionUID = -1L;

private static final Logger logger = LoggerFactory.getLogger(ArrayBindingSet.class);
private static final Value NULL_VALUE = Values
.iri("urn:null:d57c56f3-41a9-468e-8dce-5706ebdef84c_e88d9e52-27cb-4056-a889-1ea353fa6f0c");

private final String[] bindingNames;

// Creating a LinkedHashSet is expensive, so we should cache the binding names set
private Set<String> bindingNamesSetCache;
private boolean empty;

private final boolean[] whichBindingsHaveBeenSet;

private final Value[] values;

/**
Expand All @@ -63,21 +64,24 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
public ArrayBindingSet(String... names) {
this.bindingNames = names;
this.values = new Value[names.length];
this.whichBindingsHaveBeenSet = new boolean[names.length];
this.empty = true;
}

public ArrayBindingSet(BindingSet toCopy, Set<String> names, String[] namesArray) {
assert !(toCopy instanceof ArrayBindingSet);

this.bindingNames = namesArray;
this.whichBindingsHaveBeenSet = new boolean[this.bindingNames.length];
this.values = new Value[this.bindingNames.length];
for (int i = 0; i < this.bindingNames.length; i++) {
Binding binding = toCopy.getBinding(this.bindingNames[i]);

if (binding != null) {
this.values[i] = binding.getValue();
this.whichBindingsHaveBeenSet[i] = true;
if (this.values[i] == null) {
this.values[i] = NULL_VALUE;
}
} else if (hasBinding(this.bindingNames[i])) {
this.values[i] = NULL_VALUE;
}
}
this.empty = toCopy.isEmpty();
Expand All @@ -89,8 +93,6 @@ public ArrayBindingSet(ArrayBindingSet toCopy, String... names) {
this.bindingNames = names;

this.values = Arrays.copyOf(toCopy.values, toCopy.values.length);
this.whichBindingsHaveBeenSet = Arrays.copyOf(toCopy.whichBindingsHaveBeenSet,
toCopy.whichBindingsHaveBeenSet.length);
this.empty = toCopy.empty;
assert !this.empty || size() == 0;
}
Expand All @@ -111,8 +113,7 @@ public BiConsumer<Value, ArrayBindingSet> getDirectSetBinding(String bindingName
return null;
}
return (v, a) -> {
a.values[index] = v;
a.whichBindingsHaveBeenSet[index] = true;
a.values[index] = v == null ? NULL_VALUE : v;
a.empty = false;
a.clearCache();
};
Expand All @@ -126,9 +127,8 @@ public BiConsumer<Value, ArrayBindingSet> getDirectAddBinding(String bindingName
return null;
}
return (v, a) -> {
assert !a.whichBindingsHaveBeenSet[index] : "variable already bound: " + bindingName;
a.values[index] = v;
a.whichBindingsHaveBeenSet[index] = true;
assert a.values[index] == null;
a.values[index] = v == null ? NULL_VALUE : v;
a.empty = false;
a.clearCache();
};
Expand All @@ -143,6 +143,9 @@ public Function<ArrayBindingSet, Binding> getDirectGetBinding(String bindingName
}
return a -> {
Value value = a.values[index];
if (value == NULL_VALUE) {
value = null;
}
if (value != null) {
return new SimpleBinding(bindingName, value);
} else {
Expand All @@ -157,7 +160,7 @@ public Function<ArrayBindingSet, Value> getDirectGetValue(String bindingName) {
if (index == -1) {
return null;
}
return a -> a.values[index];
return a -> a.values[index] == NULL_VALUE ? null : a.values[index];

}

Expand All @@ -166,7 +169,7 @@ public Function<ArrayBindingSet, Boolean> getDirectHasBinding(String bindingName
if (index == -1) {
return null;
}
return a -> a.whichBindingsHaveBeenSet[index];
return a -> a.values[index] != null;
}

private int getIndex(String bindingName) {
Expand Down Expand Up @@ -195,7 +198,7 @@ public Set<String> getBindingNames() {
this.bindingNamesSetCache = Collections.emptySet();
} else if (size == 1) {
for (int i = 0; i < this.bindingNames.length; i++) {
if (whichBindingsHaveBeenSet[i]) {
if (values[i] != null) {
this.bindingNamesSetCache = Collections.singleton(bindingNames[i]);
break;
}
Expand All @@ -204,7 +207,7 @@ public Set<String> getBindingNames() {
} else {
LinkedHashSet<String> bindingNamesSetCache = new LinkedHashSet<>(size * 2);
for (int i = 0; i < this.bindingNames.length; i++) {
if (whichBindingsHaveBeenSet[i]) {
if (values[i] != null) {
bindingNamesSetCache.add(bindingNames[i]);
}
}
Expand All @@ -222,14 +225,14 @@ public Value getValue(String bindingName) {
}

for (int i = 0; i < bindingNames.length; i++) {
if (bindingNames[i] == bindingName && whichBindingsHaveBeenSet[i]) {
return values[i];
if (bindingNames[i] == bindingName && values[i] != null) {
return values[i] == NULL_VALUE ? null : values[i];
}
}

for (int i = 0; i < bindingNames.length; i++) {
if (bindingNames[i].equals(bindingName) && whichBindingsHaveBeenSet[i]) {
return values[i];
if (bindingNames[i].equals(bindingName) && values[i] != null) {
return values[i] == NULL_VALUE ? null : values[i];
}
}
return null;
Expand All @@ -242,6 +245,9 @@ public Binding getBinding(String bindingName) {
}

Value value = getValue(bindingName);
if (value == NULL_VALUE) {
value = null;
}

if (value != null) {
return new SimpleBinding(bindingName, value);
Expand All @@ -260,7 +266,7 @@ public boolean hasBinding(String bindingName) {
if (index == -1) {
return false;
}
return whichBindingsHaveBeenSet[index];
return values[index] != null;
}

@Override
Expand All @@ -280,8 +286,8 @@ public int size() {

int size = 0;

for (boolean value : whichBindingsHaveBeenSet) {
if (value) {
for (Value value : values) {
if (value != null) {
size++;
}
}
Expand All @@ -298,14 +304,14 @@ public List<String> getSortedBindingNames() {

if (size == 1) {
for (int i = 0; i < bindingNames.length; i++) {
if (whichBindingsHaveBeenSet[i]) {
if (values[i] != null) {
sortedBindingNames = Collections.singletonList(bindingNames[i]);
}
}
} else {
ArrayList<String> names = new ArrayList<>(size);
for (int i = 0; i < bindingNames.length; i++) {
if (whichBindingsHaveBeenSet[i]) {
if (values[i] != null) {
names.add(bindingNames[i]);
}
}
Expand All @@ -320,17 +326,17 @@ public List<String> getSortedBindingNames() {
@Override
public void addBinding(Binding binding) {
int index = getIndex(binding.getName());
Value value = binding.getValue();
if (index == -1) {
logger.error(
"We don't actually support adding a binding. " + binding.getName() + " : " + binding.getValue());
"We don't actually support adding a binding. " + binding.getName() + " : " + value);
assert false
: "We don't actually support adding a binding. " + binding.getName() + " : " + binding.getValue();
: "We don't actually support adding a binding. " + binding.getName() + " : " + value;
return;
}

assert !this.whichBindingsHaveBeenSet[index];
this.values[index] = binding.getValue();
this.whichBindingsHaveBeenSet[index] = true;
assert this.values[index] == null;
this.values[index] = value == null ? NULL_VALUE : value;
empty = false;
clearCache();
}
Expand All @@ -341,8 +347,8 @@ public void setBinding(Binding binding) {
if (index == -1) {
return;
}
this.values[index] = binding.getValue();
this.whichBindingsHaveBeenSet[index] = true;
Value value = binding.getValue();
this.values[index] = value == null ? NULL_VALUE : value;
empty = false;
clearCache();
}
Expand All @@ -355,11 +361,10 @@ public void setBinding(String name, Value value) {
}

this.values[index] = value;
this.whichBindingsHaveBeenSet[index] = value != null;
if (value == null) {
this.empty = true;
for (boolean b : whichBindingsHaveBeenSet) {
if (b) {
for (Value value1 : this.values) {
if (value1 != null) {
this.empty = false;
break;
}
Expand All @@ -382,17 +387,16 @@ private void clearCache() {
public void addAll(ArrayBindingSet other) {
if (other.bindingNames == bindingNames) {
for (int i = 0; i < bindingNames.length; i++) {
if (other.whichBindingsHaveBeenSet[i]) {
if (other.values[i] != null) {
this.values[i] = other.values[i];
this.whichBindingsHaveBeenSet[i] = true;
this.empty = false;
}
}
} else {
for (int i = 0; i < bindingNames.length; i++) {
if (other.hasBinding(bindingNames[i])) {
this.values[i] = other.getValue(bindingNames[i]);
this.whichBindingsHaveBeenSet[i] = true;
Value value = other.getValue(bindingNames[i]);
this.values[i] = value == null ? NULL_VALUE : value;
this.empty = false;
}
}
Expand All @@ -412,7 +416,7 @@ public ArrayBindingSetIterator() {
@Override
public boolean hasNext() {
while (index < values.length) {
if (whichBindingsHaveBeenSet[index]) {
if (values[index] != null) {
return true;
}
index++;
Expand All @@ -423,9 +427,12 @@ public boolean hasNext() {
@Override
public Binding next() {
while (index < values.length) {
if (whichBindingsHaveBeenSet[index]) {
if (values[index] != null) {
String name = bindingNames[index];
Value value = values[index++];
if (value == NULL_VALUE) {
value = null;
}
if (value != null) {
return new SimpleBinding(name, value);
} else {
Expand Down
Loading

0 comments on commit a7a3171

Please sign in to comment.