Skip to content

Commit cbc265c

Browse files
committed
performance improvements
1 parent 400ef53 commit cbc265c

14 files changed

Lines changed: 1416 additions & 247 deletions

File tree

core/common/io/src/main/java/org/eclipse/rdf4j/common/io/NioFile.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,29 @@ public final class NioFile implements Closeable {
5656

5757
private volatile boolean explictlyClosed;
5858

59+
/**
60+
* Optional factory used to create FileChannel instances, primarily for testing where a delegating channel can
61+
* simulate failures. If not set, {@link FileChannel#open(Path, java.nio.file.OpenOption...)} is used directly.
62+
*/
63+
private static volatile ChannelFactory channelFactory;
64+
65+
/**
66+
* Functional interface for creating FileChannel instances. Intended for test injection.
67+
*/
68+
@FunctionalInterface
69+
public interface ChannelFactory {
70+
FileChannel open(Path path, Set<StandardOpenOption> options) throws IOException;
71+
}
72+
73+
/**
74+
* Install a factory that will be used to create FileChannel instances. Intended for tests only.
75+
*
76+
* Passing {@code null} restores the default behavior.
77+
*/
78+
public static void setChannelFactoryForTesting(ChannelFactory factory) {
79+
channelFactory = factory;
80+
}
81+
5982
/**
6083
* Constructor Opens a file in read/write mode, creating a new one if the file doesn't exist.
6184
*
@@ -110,7 +133,12 @@ private static Set<StandardOpenOption> toOpenOptions(String mode) {
110133
* @throws IOException
111134
*/
112135
private void open() throws IOException {
113-
fc = FileChannel.open(file.toPath(), openOptions);
136+
ChannelFactory factory = channelFactory;
137+
if (factory != null) {
138+
fc = factory.open(file.toPath(), openOptions);
139+
} else {
140+
fc = FileChannel.open(file.toPath(), openOptions);
141+
}
114142
}
115143

116144
/**
@@ -423,4 +451,5 @@ public int readInt(long offset) throws IOException {
423451
}
424452
return buf.getInt(0);
425453
}
454+
426455
}

core/sail/nativerdf/src/main/java/org/eclipse/rdf4j/sail/nativerdf/NativeStatementIterator.java

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
import static org.eclipse.rdf4j.sail.nativerdf.NativeStore.SOFT_FAIL_ON_CORRUPT_DATA_AND_REPAIR_INDEXES;
1414

1515
import java.io.IOException;
16+
import java.util.NoSuchElementException;
1617

1718
import org.eclipse.rdf4j.common.io.ByteArrayUtil;
18-
import org.eclipse.rdf4j.common.iteration.LookAheadIteration;
19+
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
1920
import org.eclipse.rdf4j.model.IRI;
2021
import org.eclipse.rdf4j.model.Resource;
2122
import org.eclipse.rdf4j.model.Statement;
@@ -32,35 +33,21 @@
3233
* A statement iterator that wraps a RecordIterator containing statement records and translates these records to
3334
* {@link Statement} objects.
3435
*/
35-
class NativeStatementIterator extends LookAheadIteration<Statement> {
36+
class NativeStatementIterator implements CloseableIteration<Statement> {
3637

3738
private static final Logger logger = LoggerFactory.getLogger(NativeStatementIterator.class);
3839

39-
/*-----------*
40-
* Variables *
41-
*-----------*/
42-
4340
private final RecordIterator btreeIter;
44-
4541
private final ValueStore valueStore;
4642

47-
/*--------------*
48-
* Constructors *
49-
*--------------*/
43+
private Statement nextElement;
44+
private boolean closed = false;
5045

51-
/**
52-
* Creates a new NativeStatementIterator.
53-
*/
5446
public NativeStatementIterator(RecordIterator btreeIter, ValueStore valueStore) {
5547
this.btreeIter = btreeIter;
5648
this.valueStore = valueStore;
5749
}
5850

59-
/*---------*
60-
* Methods *
61-
*---------*/
62-
63-
@Override
6451
public Statement getNextElement() throws SailException {
6552
try {
6653
byte[] nextValue;
@@ -107,7 +94,6 @@ public Statement getNextElement() throws SailException {
10794
}
10895
}
10996

110-
@Override
11197
protected void handleClose() throws SailException {
11298
try {
11399
btreeIter.close();
@@ -119,4 +105,79 @@ protected void handleClose() throws SailException {
119105
protected SailException causeIOException(IOException e) {
120106
return new SailException(e);
121107
}
108+
109+
@Override
110+
public final boolean hasNext() {
111+
if (isClosed()) {
112+
return false;
113+
}
114+
115+
try {
116+
return lookAhead() != null;
117+
} catch (NoSuchElementException logged) {
118+
// The lookAhead() method shouldn't throw a NoSuchElementException since it should return null when there
119+
// are no more elements.
120+
logger.trace("LookAheadIteration threw NoSuchElementException:", logged);
121+
return false;
122+
}
123+
}
124+
125+
@Override
126+
public final Statement next() {
127+
if (isClosed()) {
128+
throw new NoSuchElementException("The iteration has been closed.");
129+
}
130+
Statement result = lookAhead();
131+
132+
if (result != null) {
133+
nextElement = null;
134+
return result;
135+
} else {
136+
throw new NoSuchElementException();
137+
}
138+
}
139+
140+
/**
141+
* Fetches the next element if it hasn't been fetched yet and stores it in {@link #nextElement}.
142+
*
143+
* @return The next element, or null if there are no more results.
144+
*/
145+
private Statement lookAhead() {
146+
if (nextElement == null) {
147+
nextElement = getNextElement();
148+
149+
if (nextElement == null) {
150+
close();
151+
}
152+
}
153+
return nextElement;
154+
}
155+
156+
/**
157+
* Throws an {@link UnsupportedOperationException}.
158+
*/
159+
@Override
160+
public void remove() {
161+
throw new UnsupportedOperationException();
162+
}
163+
164+
/**
165+
* Checks whether this CloseableIteration has been closed.
166+
*
167+
* @return <var>true</var> if the CloseableIteration has been closed, <var>false</var> otherwise.
168+
*/
169+
public final boolean isClosed() {
170+
return closed;
171+
}
172+
173+
/**
174+
* Calls {@link #handleClose()} upon first call and makes sure the resource closures are only executed once.
175+
*/
176+
@Override
177+
public final void close() {
178+
if (!closed) {
179+
closed = true;
180+
handleClose();
181+
}
182+
}
122183
}

0 commit comments

Comments
 (0)