Skip to content

Commit a7a3171

Browse files
authored
GH-4973 improve performance og inner merge join (#4975)
1 parent ccf6250 commit a7a3171

10 files changed

Lines changed: 671 additions & 164 deletions

File tree

core/query/src/main/java/org/eclipse/rdf4j/query/AbstractBindingSet.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ public String toString() {
7878

7979
Iterator<Binding> iter = iterator();
8080
while (iter.hasNext()) {
81-
sb.append(iter.next().toString());
81+
Binding next = iter.next();
82+
sb.append(next != null ? next.toString() : "null");
8283
if (iter.hasNext()) {
8384
sb.append(';');
8485
}

core/queryalgebra/evaluation/src/main/java/org/eclipse/rdf4j/query/algebra/evaluation/ArrayBindingSet.java

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import org.eclipse.rdf4j.common.annotation.InternalUseOnly;
2525
import org.eclipse.rdf4j.model.Value;
26+
import org.eclipse.rdf4j.model.util.Values;
2627
import org.eclipse.rdf4j.query.AbstractBindingSet;
2728
import org.eclipse.rdf4j.query.Binding;
2829
import org.eclipse.rdf4j.query.BindingSet;
@@ -42,15 +43,15 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
4243
private static final long serialVersionUID = -1L;
4344

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

4649
private final String[] bindingNames;
4750

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

52-
private final boolean[] whichBindingsHaveBeenSet;
53-
5455
private final Value[] values;
5556

5657
/**
@@ -63,21 +64,24 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
6364
public ArrayBindingSet(String... names) {
6465
this.bindingNames = names;
6566
this.values = new Value[names.length];
66-
this.whichBindingsHaveBeenSet = new boolean[names.length];
6767
this.empty = true;
6868
}
6969

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

7373
this.bindingNames = namesArray;
74-
this.whichBindingsHaveBeenSet = new boolean[this.bindingNames.length];
7574
this.values = new Value[this.bindingNames.length];
7675
for (int i = 0; i < this.bindingNames.length; i++) {
7776
Binding binding = toCopy.getBinding(this.bindingNames[i]);
77+
7878
if (binding != null) {
7979
this.values[i] = binding.getValue();
80-
this.whichBindingsHaveBeenSet[i] = true;
80+
if (this.values[i] == null) {
81+
this.values[i] = NULL_VALUE;
82+
}
83+
} else if (hasBinding(this.bindingNames[i])) {
84+
this.values[i] = NULL_VALUE;
8185
}
8286
}
8387
this.empty = toCopy.isEmpty();
@@ -89,8 +93,6 @@ public ArrayBindingSet(ArrayBindingSet toCopy, String... names) {
8993
this.bindingNames = names;
9094

9195
this.values = Arrays.copyOf(toCopy.values, toCopy.values.length);
92-
this.whichBindingsHaveBeenSet = Arrays.copyOf(toCopy.whichBindingsHaveBeenSet,
93-
toCopy.whichBindingsHaveBeenSet.length);
9496
this.empty = toCopy.empty;
9597
assert !this.empty || size() == 0;
9698
}
@@ -111,8 +113,7 @@ public BiConsumer<Value, ArrayBindingSet> getDirectSetBinding(String bindingName
111113
return null;
112114
}
113115
return (v, a) -> {
114-
a.values[index] = v;
115-
a.whichBindingsHaveBeenSet[index] = true;
116+
a.values[index] = v == null ? NULL_VALUE : v;
116117
a.empty = false;
117118
a.clearCache();
118119
};
@@ -126,9 +127,8 @@ public BiConsumer<Value, ArrayBindingSet> getDirectAddBinding(String bindingName
126127
return null;
127128
}
128129
return (v, a) -> {
129-
assert !a.whichBindingsHaveBeenSet[index] : "variable already bound: " + bindingName;
130-
a.values[index] = v;
131-
a.whichBindingsHaveBeenSet[index] = true;
130+
assert a.values[index] == null;
131+
a.values[index] = v == null ? NULL_VALUE : v;
132132
a.empty = false;
133133
a.clearCache();
134134
};
@@ -143,6 +143,9 @@ public Function<ArrayBindingSet, Binding> getDirectGetBinding(String bindingName
143143
}
144144
return a -> {
145145
Value value = a.values[index];
146+
if (value == NULL_VALUE) {
147+
value = null;
148+
}
146149
if (value != null) {
147150
return new SimpleBinding(bindingName, value);
148151
} else {
@@ -157,7 +160,7 @@ public Function<ArrayBindingSet, Value> getDirectGetValue(String bindingName) {
157160
if (index == -1) {
158161
return null;
159162
}
160-
return a -> a.values[index];
163+
return a -> a.values[index] == NULL_VALUE ? null : a.values[index];
161164

162165
}
163166

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

172175
private int getIndex(String bindingName) {
@@ -195,7 +198,7 @@ public Set<String> getBindingNames() {
195198
this.bindingNamesSetCache = Collections.emptySet();
196199
} else if (size == 1) {
197200
for (int i = 0; i < this.bindingNames.length; i++) {
198-
if (whichBindingsHaveBeenSet[i]) {
201+
if (values[i] != null) {
199202
this.bindingNamesSetCache = Collections.singleton(bindingNames[i]);
200203
break;
201204
}
@@ -204,7 +207,7 @@ public Set<String> getBindingNames() {
204207
} else {
205208
LinkedHashSet<String> bindingNamesSetCache = new LinkedHashSet<>(size * 2);
206209
for (int i = 0; i < this.bindingNames.length; i++) {
207-
if (whichBindingsHaveBeenSet[i]) {
210+
if (values[i] != null) {
208211
bindingNamesSetCache.add(bindingNames[i]);
209212
}
210213
}
@@ -222,14 +225,14 @@ public Value getValue(String bindingName) {
222225
}
223226

224227
for (int i = 0; i < bindingNames.length; i++) {
225-
if (bindingNames[i] == bindingName && whichBindingsHaveBeenSet[i]) {
226-
return values[i];
228+
if (bindingNames[i] == bindingName && values[i] != null) {
229+
return values[i] == NULL_VALUE ? null : values[i];
227230
}
228231
}
229232

230233
for (int i = 0; i < bindingNames.length; i++) {
231-
if (bindingNames[i].equals(bindingName) && whichBindingsHaveBeenSet[i]) {
232-
return values[i];
234+
if (bindingNames[i].equals(bindingName) && values[i] != null) {
235+
return values[i] == NULL_VALUE ? null : values[i];
233236
}
234237
}
235238
return null;
@@ -242,6 +245,9 @@ public Binding getBinding(String bindingName) {
242245
}
243246

244247
Value value = getValue(bindingName);
248+
if (value == NULL_VALUE) {
249+
value = null;
250+
}
245251

246252
if (value != null) {
247253
return new SimpleBinding(bindingName, value);
@@ -260,7 +266,7 @@ public boolean hasBinding(String bindingName) {
260266
if (index == -1) {
261267
return false;
262268
}
263-
return whichBindingsHaveBeenSet[index];
269+
return values[index] != null;
264270
}
265271

266272
@Override
@@ -280,8 +286,8 @@ public int size() {
280286

281287
int size = 0;
282288

283-
for (boolean value : whichBindingsHaveBeenSet) {
284-
if (value) {
289+
for (Value value : values) {
290+
if (value != null) {
285291
size++;
286292
}
287293
}
@@ -298,14 +304,14 @@ public List<String> getSortedBindingNames() {
298304

299305
if (size == 1) {
300306
for (int i = 0; i < bindingNames.length; i++) {
301-
if (whichBindingsHaveBeenSet[i]) {
307+
if (values[i] != null) {
302308
sortedBindingNames = Collections.singletonList(bindingNames[i]);
303309
}
304310
}
305311
} else {
306312
ArrayList<String> names = new ArrayList<>(size);
307313
for (int i = 0; i < bindingNames.length; i++) {
308-
if (whichBindingsHaveBeenSet[i]) {
314+
if (values[i] != null) {
309315
names.add(bindingNames[i]);
310316
}
311317
}
@@ -320,17 +326,17 @@ public List<String> getSortedBindingNames() {
320326
@Override
321327
public void addBinding(Binding binding) {
322328
int index = getIndex(binding.getName());
329+
Value value = binding.getValue();
323330
if (index == -1) {
324331
logger.error(
325-
"We don't actually support adding a binding. " + binding.getName() + " : " + binding.getValue());
332+
"We don't actually support adding a binding. " + binding.getName() + " : " + value);
326333
assert false
327-
: "We don't actually support adding a binding. " + binding.getName() + " : " + binding.getValue();
334+
: "We don't actually support adding a binding. " + binding.getName() + " : " + value;
328335
return;
329336
}
330337

331-
assert !this.whichBindingsHaveBeenSet[index];
332-
this.values[index] = binding.getValue();
333-
this.whichBindingsHaveBeenSet[index] = true;
338+
assert this.values[index] == null;
339+
this.values[index] = value == null ? NULL_VALUE : value;
334340
empty = false;
335341
clearCache();
336342
}
@@ -341,8 +347,8 @@ public void setBinding(Binding binding) {
341347
if (index == -1) {
342348
return;
343349
}
344-
this.values[index] = binding.getValue();
345-
this.whichBindingsHaveBeenSet[index] = true;
350+
Value value = binding.getValue();
351+
this.values[index] = value == null ? NULL_VALUE : value;
346352
empty = false;
347353
clearCache();
348354
}
@@ -355,11 +361,10 @@ public void setBinding(String name, Value value) {
355361
}
356362

357363
this.values[index] = value;
358-
this.whichBindingsHaveBeenSet[index] = value != null;
359364
if (value == null) {
360365
this.empty = true;
361-
for (boolean b : whichBindingsHaveBeenSet) {
362-
if (b) {
366+
for (Value value1 : this.values) {
367+
if (value1 != null) {
363368
this.empty = false;
364369
break;
365370
}
@@ -382,17 +387,16 @@ private void clearCache() {
382387
public void addAll(ArrayBindingSet other) {
383388
if (other.bindingNames == bindingNames) {
384389
for (int i = 0; i < bindingNames.length; i++) {
385-
if (other.whichBindingsHaveBeenSet[i]) {
390+
if (other.values[i] != null) {
386391
this.values[i] = other.values[i];
387-
this.whichBindingsHaveBeenSet[i] = true;
388392
this.empty = false;
389393
}
390394
}
391395
} else {
392396
for (int i = 0; i < bindingNames.length; i++) {
393397
if (other.hasBinding(bindingNames[i])) {
394-
this.values[i] = other.getValue(bindingNames[i]);
395-
this.whichBindingsHaveBeenSet[i] = true;
398+
Value value = other.getValue(bindingNames[i]);
399+
this.values[i] = value == null ? NULL_VALUE : value;
396400
this.empty = false;
397401
}
398402
}
@@ -412,7 +416,7 @@ public ArrayBindingSetIterator() {
412416
@Override
413417
public boolean hasNext() {
414418
while (index < values.length) {
415-
if (whichBindingsHaveBeenSet[index]) {
419+
if (values[index] != null) {
416420
return true;
417421
}
418422
index++;
@@ -423,9 +427,12 @@ public boolean hasNext() {
423427
@Override
424428
public Binding next() {
425429
while (index < values.length) {
426-
if (whichBindingsHaveBeenSet[index]) {
430+
if (values[index] != null) {
427431
String name = bindingNames[index];
428432
Value value = values[index++];
433+
if (value == NULL_VALUE) {
434+
value = null;
435+
}
429436
if (value != null) {
430437
return new SimpleBinding(name, value);
431438
} else {

0 commit comments

Comments
 (0)