lance-sp opened a new issue, #3877:
URL: https://github.com/apache/jena/issues/3877
### Version
5.6.0
### What happened?
- Module: `jena-dboe-base`
(`org.apache.jena.dboe.base.file.BinaryDataFileRandomAccess`).
`BinaryDataFileRandomAccess.truncate(length)` in `jena-dboe-base` calls
`RandomAccessFile.setLength(length)` but does not reset the class's own
`writePosition` field. A later `switchToWriteMode()` (triggered by any
read→write transition, e.g. a write after a read inside the same
`BinaryDataFileRandomAccess` lifecycle) seeks the underlying `RandomAccessFile`
to the stale `writePosition` past the just-truncated EOF. The next
`file.write(...)` extends the file at that position; the filesystem zero-fills
the range between the truncated length and the stale seek, leaving a contiguous
zero gap inside the file.
What I expected: after `truncate(length)` followed by `read(...)` then
`write(buf)`, the write should land at offset `length`, and the file should
contain the written bytes only (no zero padding).
What actually happens: the write lands at the stale `writePosition` (the
file length *before* `truncate`), and the filesystem zero-fills the intervening
bytes.
Minimal reproducer, no framework:
var file = new BinaryDataFileRandomAccess("/tmp/bdf-bug.bin");
file.open();
byte[] ab = new byte[1024]; java.util.Arrays.fill(ab, (byte) 0xAB);
for (int i = 0; i < 300; i++) file.write(ab, 0, 1024); // 300 KB of 0xAB
file.truncate(100 * 1024); // file truncated
to 100 KB
file.read(0, new byte[16], 0, 16); // flips internal
readMode
byte[] cd = new byte[100]; java.util.Arrays.fill(cd, (byte) 0xCD);
long pos = file.write(cd, 0, 100);
file.sync();
file.close();
// Expect: pos == 102400, file is 102500 bytes, no zero bytes.
// Actual: pos == 307200, file is 307300 bytes, 204800 bytes of 0x00
between
// the 100 KB of 0xAB and the 100 bytes of 0xCD.
Under TDB2 this surfaces as zero regions inside `nodes-data.obj` after an
aborted write transaction (`TransBinaryDataFile._abort()` calls `truncate()`)
followed by a transaction whose first access to that file is a read (typical
for SPARQL UPDATE — node lookups before allocation). `NodeTable` reads that
later resolve a NodeId into a zero region throw `TDBException:
NodeTableTRDF/Read → TProtocolException: Unrecognized type 0`. The store is
persistently corrupt until the affected range is overwritten; a Fuseki restart
does not recover it.
I have a one-line fix and a JUnit 5 regression test ready as a PR against
`jena-db/jena-dboe-base` — will open it once this issue has a number to
reference.
### Relevant output and stacktrace
```shell
# Output of the minimal reproducer above, on Jena 5.6.0:
after 300 KB writes: writePosition=307200, file on disk=307200 bytes
after truncate(100K): writePosition=307200 (stale), file on disk=102400
bytes
after read of 16 B: readMode=true
after write of 100 B: returned pos=307200 (should be 102400), file on
disk=307300 bytes
byte-content audit: 102400 × 0xAB, 204800 × 0x00, 100 × 0xCD
# The TDB2-level exception this produces when a later NodeTable read
resolves a
# NodeId whose offset falls inside one of the zero regions in nodes-data.obj:
org.apache.jena.tdb2.TDBException: NodeTableTRDF/Read
at
org.apache.jena.tdb2.store.nodetable.NodeTableTRDF.readNodeFromTable(NodeTableTRDF.java:87)
at
org.apache.jena.tdb2.store.nodetable.NodeTableNative._retrieveNodeByNodeId(NodeTableNative.java:102)
at
org.apache.jena.tdb2.store.nodetable.NodeTableNative.getNodeForNodeId(NodeTableNative.java:52)
at
org.apache.jena.tdb2.store.nodetable.NodeTableCache._retrieveNodeByNodeId(NodeTableCache.java:212)
at
org.apache.jena.tdb2.store.nodetable.NodeTableCache.getNodeForNodeId(NodeTableCache.java:137)
at
org.apache.jena.tdb2.store.nodetable.NodeTableWrapper.getNodeForNodeId(NodeTableWrapper.java:52)
...
Caused by: org.apache.thrift.protocol.TProtocolException: Unrecognized type 0
at org.apache.thrift.protocol.TCompactProtocol.getTType(...)
...
```
### Are you interested in making a pull request?
Yes
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]