Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a4d815a
wip (+14 squashed commits)
hmottestad Dec 27, 2025
96b456b
wip
hmottestad Dec 27, 2025
fe9e7ff
faster performance
hmottestad Dec 28, 2025
0aaef46
faster performance
hmottestad Dec 28, 2025
ef3dd92
faster performance
hmottestad Dec 28, 2025
47c3210
faster performance
hmottestad Dec 28, 2025
fe0e011
more potential optimisations
hmottestad Dec 28, 2025
d1b1d53
more potential optimisations
hmottestad Dec 28, 2025
89122c1
more potential optimisations
hmottestad Dec 29, 2025
d576906
more potential optimisations
hmottestad Dec 29, 2025
7a81ef8
more potential optimisations
hmottestad Dec 29, 2025
cc6f415
more potential optimisations
hmottestad Dec 29, 2025
fe7864d
more potential optimisations
hmottestad Dec 29, 2025
c2f72ca
more potential optimisations
hmottestad Dec 29, 2025
19494b0
more potential optimisations
hmottestad Dec 29, 2025
0286771
more potential optimisations
hmottestad Dec 29, 2025
0c31c56
more potential optimisations
hmottestad Dec 29, 2025
faedd30
wip
hmottestad Dec 29, 2025
617909f
wip
hmottestad Dec 29, 2025
05d0fc8
wip
hmottestad Dec 29, 2025
05b6d27
wip
hmottestad Dec 29, 2025
ccac5ff
wip
hmottestad Dec 29, 2025
97042c5
wip
hmottestad Dec 29, 2025
9bc05bc
wip
hmottestad Dec 29, 2025
158fda7
wip
hmottestad Dec 29, 2025
2a930c6
wip
hmottestad Dec 29, 2025
33c5d45
wip
hmottestad Dec 29, 2025
8b92f44
wip
hmottestad Dec 30, 2025
61239cf
wip
hmottestad Dec 30, 2025
27b6fd0
wip
hmottestad Dec 30, 2025
1ac995c
wip
hmottestad Dec 30, 2025
eda66c4
wip
hmottestad Dec 30, 2025
5e4b1f5
wip
hmottestad Dec 31, 2025
b7821d4
wip
hmottestad Dec 31, 2025
f46403c
wip
hmottestad Dec 31, 2025
07b65a4
wip
hmottestad Dec 31, 2025
75b4a79
wip
hmottestad Dec 31, 2025
2bb9466
wip
hmottestad Dec 31, 2025
27cd444
wip
hmottestad Dec 31, 2025
e8b74e2
wip
hmottestad Dec 31, 2025
ee1bcb9
wip
hmottestad Dec 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
// Some portions generated by Codex
package org.eclipse.rdf4j.query.algebra.evaluation;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
Expand Down Expand Up @@ -43,13 +45,22 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin

private static final long serialVersionUID = -1L;

@InternalUseOnly
public interface BindingNamesCache {
Set<String> getBindingNames(long presentMask);

Set<String> getBindingNames(BitSet presentMask);
}

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 BindingNamesCache bindingNamesCache;
private final String[] bindingNames;

// Creating a LinkedHashSet is expensive, so we should cache the binding names set
// Creating a LinkedHashSet is expensive, so we should cache the binding names set (and ideally share it across
// ArrayBindingSet instances created by the same QueryEvaluationContext).
private Set<String> bindingNamesSetCache;
private boolean empty;

Expand All @@ -64,14 +75,27 @@ public class ArrayBindingSet extends AbstractBindingSet implements MutableBindin
* @param names The binding names.
*/
public ArrayBindingSet(String... names) {
this((BindingNamesCache) null, names);
}

@InternalUseOnly
public ArrayBindingSet(BindingNamesCache bindingNamesCache, String... names) {
this.bindingNamesCache = bindingNamesCache;
this.bindingNames = names;
this.values = new Value[names.length];
this.empty = true;
}

public ArrayBindingSet(BindingSet toCopy, Set<String> names, String[] namesArray) {
this(null, toCopy, names, namesArray);
}

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

this.bindingNamesCache = bindingNamesCache;
this.bindingNames = namesArray;
this.values = new Value[this.bindingNames.length];
for (int i = 0; i < this.bindingNames.length; i++) {
Expand All @@ -92,6 +116,12 @@ public ArrayBindingSet(BindingSet toCopy, Set<String> names, String[] namesArray
}

public ArrayBindingSet(ArrayBindingSet toCopy, String... names) {
this(null, toCopy, names);
}

@InternalUseOnly
public ArrayBindingSet(BindingNamesCache bindingNamesCache, ArrayBindingSet toCopy, String... names) {
this.bindingNamesCache = bindingNamesCache;
this.bindingNames = names;

this.values = Arrays.copyOf(toCopy.values, toCopy.values.length);
Expand Down Expand Up @@ -191,32 +221,80 @@ public Set<String> getBindingNames() {
return Collections.emptySet();
}

if (bindingNamesSetCache == null) {
int size = size();
if (size == 0) {
this.bindingNamesSetCache = Collections.emptySet();
} else if (size == 1) {
for (int i = 0; i < this.bindingNames.length; i++) {
if (values[i] != null) {
this.bindingNamesSetCache = Collections.singleton(bindingNames[i]);
break;
}
}
assert this.bindingNamesSetCache != null;
if (bindingNamesSetCache != null) {
return bindingNamesSetCache;
}

Set<String> bindingNamesSetCache;
if (bindingNamesCache != null) {
if (bindingNames.length <= Long.SIZE) {
bindingNamesSetCache = bindingNamesCache.getBindingNames(toLongMask());
} else {
LinkedHashSet<String> bindingNamesSetCache = new LinkedHashSet<>(size * 2);
for (int i = 0; i < this.bindingNames.length; i++) {
if (values[i] != null) {
bindingNamesSetCache.add(bindingNames[i]);
}
}
this.bindingNamesSetCache = Collections.unmodifiableSet(bindingNamesSetCache);
bindingNamesSetCache = bindingNamesCache.getBindingNames(toBitSet());
}
} else if (bindingNames.length <= Long.SIZE) {
bindingNamesSetCache = toSetFromLongMask(toLongMask());
} else {
bindingNamesSetCache = toSetFromBitSet(toBitSet());
}

this.bindingNamesSetCache = bindingNamesSetCache;
return bindingNamesSetCache;
}

private long toLongMask() {
long mask = 0;
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
mask |= (1L << i);
}
}
return mask;
}

private BitSet toBitSet() {
BitSet bitSet = new BitSet(values.length);
for (int i = 0; i < values.length; i++) {
if (values[i] != null) {
bitSet.set(i);
}
}
return bitSet;
}

private Set<String> toSetFromLongMask(long mask) {
int size = Long.bitCount(mask);
if (size == 0) {
return Collections.emptySet();
}
if (size == 1) {
return Collections.singleton(bindingNames[Long.numberOfTrailingZeros(mask)]);
}

LinkedHashSet<String> set = new LinkedHashSet<>(size * 2);
for (long bits = mask; bits != 0; bits &= (bits - 1)) {
int index = Long.numberOfTrailingZeros(bits);
set.add(bindingNames[index]);
}
return Collections.unmodifiableSet(set);
}

private Set<String> toSetFromBitSet(BitSet bitSet) {
int size = bitSet.cardinality();
if (size == 0) {
return Collections.emptySet();
}
if (size == 1) {
return Collections.singleton(bindingNames[bitSet.nextSetBit(0)]);
}

LinkedHashSet<String> set = new LinkedHashSet<>(size * 2);
for (int index = bitSet.nextSetBit(0); index >= 0; index = bitSet.nextSetBit(index + 1)) {
set.add(bindingNames[index]);
}
return Collections.unmodifiableSet(set);
}

@Override
public Value getValue(String bindingName) {
if (isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2025 Eclipse RDF4J contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
// Some portions generated by Codex
package org.eclipse.rdf4j.query.algebra.evaluation;

import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.common.order.StatementOrder;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryEvaluationException;
import org.eclipse.rdf4j.query.algebra.StatementPattern;

/**
* Optional capability for evaluating a StatementPattern against multiple bindings at once.
*/
public interface BulkTripleSource extends TripleSource {

CloseableIteration<BindingSet> getStatementsBatch(StatementPattern statementPattern,
Iterable<BindingSet> bindings,
Resource[] contexts,
StatementOrder order) throws QueryEvaluationException;
}
Loading
Loading