From 0ab57c0467d6cdb43309629e399a8cc4bba87d2f Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Tue, 27 Jun 2017 22:40:17 +0100 Subject: [PATCH 1/9] Remove unused. --- .../jena/sparql/engine/optimizer/StatsMatcher.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/engine/optimizer/StatsMatcher.java b/jena-arq/src/main/java/org/apache/jena/sparql/engine/optimizer/StatsMatcher.java index 7798f71130a..b1baacbe044 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/engine/optimizer/StatsMatcher.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/engine/optimizer/StatsMatcher.java @@ -269,19 +269,6 @@ public void addPattern(Pattern pattern) entry.add(pattern) ; } -// public void addPattern(Triple triple) -// { -// if ( triple.getSubject().isVariable() ) -// { -// // PO, P and O -// } -// else -// { -// //SPO, SP and SO -// } -// throw new NotImplementedException("StatsMatcher.addPattern") ; -// } - private static void check(Pattern pattern) { check(pattern.subjItem) ; From 91a65ad2a7e6e0d11dbd1672837b0addb5d12423 Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Tue, 27 Jun 2017 22:41:03 +0100 Subject: [PATCH 2/9] Rename is dumpnodes --- .../{dumpnodetable.java => dumpnodes.java} | 12 +- .../main/java/tdb/tools/dumpnodetable1.java | 184 ------------------ 2 files changed, 8 insertions(+), 188 deletions(-) rename jena-cmds/src/main/java/tdb/tools/{dumpnodetable.java => dumpnodes.java} (95%) delete mode 100644 jena-cmds/src/main/java/tdb/tools/dumpnodetable1.java diff --git a/jena-cmds/src/main/java/tdb/tools/dumpnodetable.java b/jena-cmds/src/main/java/tdb/tools/dumpnodes.java similarity index 95% rename from jena-cmds/src/main/java/tdb/tools/dumpnodetable.java rename to jena-cmds/src/main/java/tdb/tools/dumpnodes.java index c163e8d4be8..933517f8418 100644 --- a/jena-cmds/src/main/java/tdb/tools/dumpnodetable.java +++ b/jena-cmds/src/main/java/tdb/tools/dumpnodes.java @@ -43,18 +43,17 @@ import org.apache.jena.tdb.sys.Names ; import tdb.cmdline.ModLocation ; -public class dumpnodetable extends CmdARQ { +public class dumpnodes extends CmdARQ { ModLocation modLocation = new ModLocation() ; static public void main(String... argv) { LogCtl.setLog4j() ; - new dumpnodetable(argv).mainRun() ; + new dumpnodes(argv).mainRun() ; } @Override protected void exec() { Location loc = modLocation.getLocation() ; - ObjectFile objFile = determineNodeTable(loc); dump(System.out, objFile) ; } @@ -69,7 +68,7 @@ private ObjectFile determineNodeTable(Location loc) { return objFile; } - protected dumpnodetable(String[] argv) { + protected dumpnodes(String[] argv) { super(argv) ; super.addModule(modLocation) ; } @@ -92,6 +91,11 @@ public static void dump(OutputStream w, ObjectFile objFile) { Iterator> iter = all(objFile) ; long count = 0 ; try (IndentedWriter iw = new IndentedWriter(w)) { + if ( ! iter.hasNext() ) { + iw.println("No nodes in the .dat file"); + return ; + } + for ( ; iter.hasNext() ; ) { Pair pair = iter.next() ; iw.print(pair.car().toString()) ; diff --git a/jena-cmds/src/main/java/tdb/tools/dumpnodetable1.java b/jena-cmds/src/main/java/tdb/tools/dumpnodetable1.java deleted file mode 100644 index 05f6da2054d..00000000000 --- a/jena-cmds/src/main/java/tdb/tools/dumpnodetable1.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package tdb.tools ; - -import java.io.OutputStream ; -import java.util.Iterator ; - -import arq.cmdline.CmdARQ; -import org.apache.jena.atlas.io.IndentedWriter ; -import org.apache.jena.atlas.lib.Lib ; -import org.apache.jena.atlas.lib.Pair ; -import org.apache.jena.atlas.logging.Log ; -import org.apache.jena.atlas.logging.LogCtl ; -import org.apache.jena.graph.Node ; -import org.apache.jena.graph.Node_Literal ; -import org.apache.jena.sparql.util.FmtUtils ; -import org.apache.jena.tdb.StoreConnection ; -import org.apache.jena.tdb.base.file.Location ; -import org.apache.jena.tdb.setup.Build ; -import org.apache.jena.tdb.store.DatasetGraphTDB ; -import org.apache.jena.tdb.store.NodeId ; -import org.apache.jena.tdb.store.nodetable.NodeTable ; -import org.apache.jena.tdb.sys.Names ; -import org.apache.jena.tdb.sys.SystemTDB ; -import tdb.cmdline.ModLocation ; - -public class dumpnodetable1 extends CmdARQ { - ModLocation modLocation = new ModLocation() ; - - static public void main(String... argv) { - LogCtl.setLog4j() ; - new dumpnodetable1(argv).mainRun() ; - } - - @Override - protected void exec() { - Location loc = modLocation.getLocation() ; - NodeTable nodeTable = determineNodeTable(loc); - dump(System.out, nodeTable) ; - } - - - - private NodeTable determineNodeTable(Location loc) { - // Causes recovery. - StoreConnection sConn = StoreConnection.make(loc) ; - DatasetGraphTDB dsg = sConn.getBaseDataset() ; - NodeTable nodeTable = dsg.getQuadTable().getNodeTupleTable().getNodeTable() ; - return nodeTable; - } - - protected dumpnodetable1(String[] argv) { - super(argv) ; - super.addModule(modLocation) ; - } - - public static void dumpNodes(OutputStream w, String location) { - dump(w, location, Names.indexNode2Id, SystemTDB.Node2NodeIdCacheSize, Names.indexId2Node, SystemTDB.NodeId2NodeCacheSize, - SystemTDB.NodeMissCacheSize) ; - } - - public static void dumpPrefixes(OutputStream w, String location) { - dump(w, location, Names.prefixNode2Id, 100, Names.prefixId2Node, 100, 10) ; - } - - public static void dump(OutputStream w, String location, String indexNode2Id, int node2NodeIdCacheSize, String indexId2Node, - int nodeId2NodeCacheSize, // - - int sizeNodeMissCacheSize) { - NodeTable nodeTable = Build.makeNodeTable(Location.create(location), indexNode2Id, node2NodeIdCacheSize, indexId2Node, - nodeId2NodeCacheSize, sizeNodeMissCacheSize) ; - } - - public static void dump(OutputStream w, NodeTable nodeTable) { - // Better to hack the indexes? - Iterator> iter = nodeTable.all() ; - long count = 0 ; - try (IndentedWriter iw = new IndentedWriter(w)) { - for ( ; iter.hasNext() ; ) { - Pair pair = iter.next() ; - iw.print(pair.car().toString()) ; - iw.print(" : ") ; - // iw.print(pair.cdr()) ; - Node n = pair.cdr() ; - String $ = stringForNode(n) ; - iw.print($) ; - iw.println() ; - count++ ; - } - iw.println() ; - iw.printf("Total: " + count) ; - iw.println() ; - iw.flush() ; - } - } - - private static String stringForNode(Node n) { - if ( n == null ) - return "<>" ; - - if ( n.isBlank() ) - return "_:" + n.getBlankNodeLabel() ; - - if ( n.isLiteral() ) - return stringForLiteral((Node_Literal)n) ; - - if ( n.isURI() ) { - String uri = n.getURI() ; - return stringForURI(uri) ; - } - - if ( n.isVariable() ) - return "?" + n.getName() ; - - if ( n.equals(Node.ANY) ) - return "ANY" ; - - Log.warn(FmtUtils.class, "Failed to turn a node into a string: " + n) ; - return n.toString() ; - } - - public static String stringForURI(String uri) { - return "<" + uri + ">" ; - } - - public static String stringForLiteral(Node_Literal literal) { - String datatype = literal.getLiteralDatatypeURI() ; - String lang = literal.getLiteralLanguage() ; - String s = literal.getLiteralLexicalForm() ; - - StringBuilder sbuff = new StringBuilder() ; - sbuff.append("\"") ; - FmtUtils.stringEsc(sbuff, s, true) ; - sbuff.append("\"") ; - - // Format the language tag - if ( lang != null && lang.length() > 0 ) { - sbuff.append("@") ; - sbuff.append(lang) ; - } - - if ( datatype != null ) { - sbuff.append("^^") ; - sbuff.append(stringForURI(datatype)) ; - } - - return sbuff.toString() ; - } - - @Override - protected void processModulesAndArgs() { - if ( modVersion.getVersionFlag() ) - modVersion.printVersionAndExit() ; - if ( modLocation.getLocation() == null ) - cmdError("Location required") ; - } - - @Override - protected String getSummary() { - return getCommandName() + " --loc=DIR IndexName" ; - } - - @Override - protected String getCommandName() { - return Lib.className(this) ; - } - -} From 053c06a937e0c2cdf4b344526a036a9e5c356a2e Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Tue, 27 Jun 2017 22:41:38 +0100 Subject: [PATCH 3/9] Remove out of date comment. --- .../src/main/java/org/apache/jena/tdb/TDBLoader.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java b/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java index a9ef02123d4..85be47049fa 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/TDBLoader.java @@ -149,15 +149,6 @@ public static void loadModel(Model model, List urls, boolean showProgres private Logger loaderLog = TDB.logLoader ; private boolean checking ; - // XXX Context control block - // Checker - // Error handler - // verbose flag? - // logger - // generateStats - // checking flag - - // ---- The class itself. public TDBLoader() {} From 9dc27c4ef2865c840555892f9ffa6ae714e6bfc6 Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Tue, 27 Jun 2017 22:42:13 +0100 Subject: [PATCH 4/9] Make private as only used in this class. --- .../java/org/apache/jena/tdb/base/block/BlockMgrFactory.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/base/block/BlockMgrFactory.java b/jena-tdb/src/main/java/org/apache/jena/tdb/base/block/BlockMgrFactory.java index 2a84d78fc54..16e145486a0 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/base/block/BlockMgrFactory.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/base/block/BlockMgrFactory.java @@ -54,8 +54,7 @@ public static BlockMgr create(FileSet fileSet, String ext, int blockSize, int re return create(fileSet, ext, null, blockSize, readBlockCacheSize, writeBlockCacheSize) ; } - // XXX Deprecate? - public static BlockMgr create(FileSet fileSet, String ext, FileMode fileMode, int blockSize, int readBlockCacheSize, int writeBlockCacheSize) { + private static BlockMgr create(FileSet fileSet, String ext, FileMode fileMode, int blockSize, int readBlockCacheSize, int writeBlockCacheSize) { if ( fileSet.isMem() ) return createMem(fileSet.filename(ext), blockSize) ; else From 9d6c6e3c4436fa2f0f23f3bfa8415296015251ef Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Tue, 27 Jun 2017 22:43:04 +0100 Subject: [PATCH 5/9] Readonly enforcement wrapper. --- .../base/objectfile/ObjectFileReadonly.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileReadonly.java diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileReadonly.java b/jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileReadonly.java new file mode 100644 index 00000000000..9044b825caa --- /dev/null +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/base/objectfile/ObjectFileReadonly.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jena.tdb.base.objectfile; + +import java.nio.ByteBuffer ; + +import org.apache.jena.tdb.TDBException; +import org.apache.jena.tdb.base.block.Block ; + +public class ObjectFileReadonly extends ObjectFileWrapper +{ + public ObjectFileReadonly(ObjectFile other) { super(other) ; } + @Override public Block allocWrite(int maxBytes) { throw new TDBException("Read-only object file") ; } + @Override public void completeWrite(Block buffer) { throw new TDBException("Read-only object file") ; } + @Override public void abortWrite(Block buffer) { throw new TDBException("Read-only object file") ; } + @Override public long write(ByteBuffer buffer) { throw new TDBException("Read-only object file") ; } + @Override public void reposition(long id) { throw new TDBException("Read-only object file") ; } + @Override public void truncate(long size) { throw new TDBException("Read-only object file") ; } + + @Override public String toString() { return "RO:"+super.toString() ; } +} From e1abec9268bccc35fefa24dc135ea66e31bb0887 Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Tue, 27 Jun 2017 22:43:12 +0100 Subject: [PATCH 6/9] Typo --- .../java/org/apache/jena/tdb/transaction/BlockMgrJournal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/BlockMgrJournal.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/BlockMgrJournal.java index 89ab95ddfad..ba0b8e8956e 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/BlockMgrJournal.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/BlockMgrJournal.java @@ -42,7 +42,7 @@ import org.slf4j.LoggerFactory ; /** - * Block manager that keeps temporary copies of updated blocks, then writes then + * Block manager that keeps temporary copies of updated blocks, then writes them * to a journal when commitPrepare happens. No work is done in commitEnact * because the {@link TransactionManager} is responsible to writing * the blocks to the main storage. From b92ba1a56a011479aa6f3cfef556fc512c507fae Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Tue, 27 Jun 2017 22:45:40 +0100 Subject: [PATCH 7/9] Tidy up. --- .../org/apache/jena/tdb/transaction/NodeTableTrans.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/NodeTableTrans.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/NodeTableTrans.java index f8090d20b39..98615e10888 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/NodeTableTrans.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/NodeTableTrans.java @@ -58,12 +58,13 @@ public class NodeTableTrans implements NodeTable, TransactionLifecycle private final String label ; private final Transaction txn ; // Can be null (during recovery). - public NodeTableTrans(Transaction txn, String label, NodeTable sub, Index nodeIndex, ObjectFile objFile) + public NodeTableTrans(Transaction txn, String label, NodeTable sub, Index nodeIndex, ObjectFile journalObjFile) { this.txn = txn ; this.base = sub ; this.nodeIndex = nodeIndex ; - this.journalObjFile = objFile ; + // Workspace for + this.journalObjFile = journalObjFile ; // Clear bytes from an old run // (a crash while writing means the old transaction did not commit // any bytes in the file are junk) @@ -280,6 +281,7 @@ private void dump() @Override public void commitPrepare(Transaction txn) { + // The index "node2id", which is Node hash to NodeId, is done because it has a BlockMgr. debug("commitPrepare") ; // The node table is append-only so it can be written during prepare. @@ -314,7 +316,8 @@ private void writeNodeJournal() warn(log, "Inconsistency: base.allocOffset() = %d : allocOffset = %d", expected, allocOffset) ; long newbase = -1 ; - append() ; // Calls all() which does a buffer flish. + // Copy to the base NodeTable. + append() ; // Reset (in case we use this again) nodeIndex.clear() ; journalObjFile.truncate(journalObjFileStartOffset) ; // Side effect is a buffer flush. From 3764a2aedd86e9ca0edd4faac1f36850074dd51d Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Wed, 28 Jun 2017 09:28:57 +0100 Subject: [PATCH 8/9] JENA-1369: Cleaning up TDB Transaction setup. --- .../org/apache/jena/tdb/index/SetupIndex.java | 50 +-------- .../jena/tdb/setup/DatasetBuilderStd.java | 82 ++++++++++---- .../apache/jena/tdb/store/StorageConfig.java | 14 ++- .../tdb/store/nodetable/NodeTableNative.java | 23 ++-- .../org/apache/jena/tdb/sys/SetupTDB.java | 51 +-------- .../tdb/transaction/DatasetBuilderTxn.java | 101 ++++++++++++------ .../jena/tdb/transaction/JournalControl.java | 21 ++-- .../tdb/transaction/TransactionManager.java | 2 +- 8 files changed, 168 insertions(+), 176 deletions(-) diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/index/SetupIndex.java b/jena-tdb/src/main/java/org/apache/jena/tdb/index/SetupIndex.java index ded91e3bd48..dfcee8b23df 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/index/SetupIndex.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/index/SetupIndex.java @@ -122,52 +122,8 @@ public static RangeIndex makeBPlusTree(FileSet fs, int blkSize, } public static RecordFactory makeRecordFactory(int keyLen, int valueLen) - { - return new RecordFactory(keyLen, valueLen) ; - } - // - // /** Make a NodeTable without cache and inline wrappers */ - // public static NodeTable makeNodeTableBase(Location location, String indexNode2Id, String indexId2Node) - // { - // if (location.isMem()) - // return NodeTableFactory.createMem() ; - // - // // -- make id to node mapping -- Names.indexId2Node - // FileSet fsIdToNode = new FileSet(location, indexId2Node) ; - // - // ObjectFile stringFile = makeObjectFile(fsIdToNode) ; - // - // // -- make node to id mapping -- Names.indexNode2Id - // // Make index of id to node (data table) - // - // // No caching at the index level - we use the internal caches of the node table. - // Index nodeToId = makeIndex(location, indexNode2Id, LenNodeHash, SizeOfNodeId, -1 ,-1) ; - // - // // -- Make the node table using the components established above. - // NodeTable nodeTable = new NodeTableNative(nodeToId, stringFile) ; - // return nodeTable ; - // } - // - // /** Make a NodeTable with cache and inline wrappers */ - // public static NodeTable makeNodeTable(Location location) - // { - // return makeNodeTable(location, - // Names.indexNode2Id, SystemTDB.Node2NodeIdCacheSize, - // Names.indexId2Node, SystemTDB.NodeId2NodeCacheSize, - // SystemTDB.NodeMissCacheSize) ; - // } - // - // /** Make a NodeTable with cache and inline wrappers */ - // public static NodeTable makeNodeTable(Location location, - // String indexNode2Id, int nodeToIdCacheSize, - // String indexId2Node, int idToNodeCacheSize, - // int nodeMissCacheSize) - // { - // NodeTable nodeTable = makeNodeTableBase(location, indexNode2Id, indexId2Node) ; - // nodeTable = NodeTableCache.create(nodeTable, nodeToIdCacheSize, idToNodeCacheSize, nodeMissCacheSize) ; - // nodeTable = NodeTableInline.create(nodeTable) ; - // return nodeTable ; - // } - // + { + return new RecordFactory(keyLen, valueLen) ; + } } diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/setup/DatasetBuilderStd.java b/jena-tdb/src/main/java/org/apache/jena/tdb/setup/DatasetBuilderStd.java index 1319e0e6660..d538c0a4acd 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/setup/DatasetBuilderStd.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/setup/DatasetBuilderStd.java @@ -34,6 +34,7 @@ import org.apache.jena.tdb.base.file.BufferChannel ; import org.apache.jena.tdb.base.file.FileSet ; import org.apache.jena.tdb.base.file.Location ; +import org.apache.jena.tdb.base.objectfile.ObjectFile; import org.apache.jena.tdb.index.BuilderStdIndex ; import org.apache.jena.tdb.index.IndexBuilder ; import org.apache.jena.tdb.index.IndexParams ; @@ -105,15 +106,18 @@ protected DatasetBuilderStd() { } // Used by DatasetBuilderTxn public DatasetBuilderStd(BlockMgrBuilder blockMgrBuilder, NodeTableBuilder nodeTableBuilder) { - set(blockMgrBuilder, nodeTableBuilder) ; + setupRecord(blockMgrBuilder, nodeTableBuilder) ; } - protected void set(NodeTableBuilder nodeTableBuilder, TupleIndexBuilder tupleIndexBuilder) { - this.nodeTableBuilder = nodeTableBuilder ; - this.tupleIndexBuilder = tupleIndexBuilder ; + private void standardSetup() { + ObjectFileBuilder objectFileBuilder = new BuilderStdDB.ObjectFileBuilderStd() ; + BlockMgrBuilder blockMgrBuilder = new BuilderStdIndex.BlockMgrBuilderStd() ; + IndexBuilder indexBuilderNT = new BuilderStdIndex.IndexBuilderStd(blockMgrBuilder, blockMgrBuilder) ; + NodeTableBuilder nodeTableBuilder = new BuilderStdDB.NodeTableBuilderStd(indexBuilderNT, objectFileBuilder) ; + setupRecord(blockMgrBuilder, nodeTableBuilder) ; } - - protected void set(BlockMgrBuilder blockMgrBuilder, NodeTableBuilder nodeTableBuilder) { + + protected void setupRecord(BlockMgrBuilder blockMgrBuilder, NodeTableBuilder nodeTableBuilder) { recorder = new Recorder() ; BlockMgrBuilder blockMgrBuilderRec = new BlockMgrBuilderRecorder(blockMgrBuilder, recorder) ; @@ -127,6 +131,11 @@ protected void set(BlockMgrBuilder blockMgrBuilder, NodeTableBuilder nodeTableBu set(nodeTableBuilder, tupleIndexBuilder) ; } + protected void set(NodeTableBuilder nodeTableBuilder, TupleIndexBuilder tupleIndexBuilder) { + this.nodeTableBuilder = nodeTableBuilder ; + this.tupleIndexBuilder = tupleIndexBuilder ; + } + private static void checkLocation(Location location) { if ( location.isMem() ) @@ -144,14 +153,6 @@ private static void checkLocation(Location location) { error(log, "Directory not writeable: "+dirname) ; } - private void standardSetup() { - ObjectFileBuilder objectFileBuilder = new BuilderStdDB.ObjectFileBuilderStd() ; - BlockMgrBuilder blockMgrBuilder = new BuilderStdIndex.BlockMgrBuilderStd() ; - IndexBuilder indexBuilderNT = new BuilderStdIndex.IndexBuilderStd(blockMgrBuilder, blockMgrBuilder) ; - NodeTableBuilder nodeTableBuilder = new BuilderStdDB.NodeTableBuilderStd(indexBuilderNT, objectFileBuilder) ; - set(blockMgrBuilder, nodeTableBuilder) ; - } - @Override public DatasetGraphTDB build(Location location, StoreParams params) { // Ensure that there is global synchronization @@ -182,8 +183,8 @@ private synchronized DatasetGraphTDB buildWorker(Location location, boolean writ ReorderTransformation transform = (_transform == null) ? chooseReorderTransformation(location) : _transform ; - StorageConfig storageConfig = new StorageConfig(location, params, writeable, - recorder.blockMgrs, recorder.bufferChannels, recorder.nodeTables) ; + StorageConfig storageConfig = new StorageConfig(location, params, writeable, + recorder.blockMgrs, recorder.objectFiles, recorder.bufferChannels, recorder.nodeTables) ; recorder.finish() ; @@ -377,13 +378,17 @@ interface RecordBlockMgr { void record(FileRef fileRef, BlockMgr blockMgr) ; } + interface RecordObjectFile { + void record(FileRef fileRef, ObjectFile objFile); + } + interface RecordNodeTable { void record(FileRef fileRef, NodeTable nodeTable) ; } static class NodeTableBuilderRecorder implements NodeTableBuilder { - private NodeTableBuilder builder ; - private RecordNodeTable recorder ; + private final NodeTableBuilder builder ; + private final RecordNodeTable recorder ; NodeTableBuilderRecorder(NodeTableBuilder ntb, RecordNodeTable recorder) { this.builder = ntb ; @@ -401,9 +406,27 @@ public NodeTable buildNodeTable(FileSet fsIndex, FileSet fsObjectFile, StorePara } + static class ObjectFileBuilderRecorder implements ObjectFileBuilder { + private final ObjectFileBuilder builder ; + private final RecordObjectFile recorder ; + + ObjectFileBuilderRecorder(ObjectFileBuilder objFileBuilder, RecordObjectFile recorder) { + this.builder = objFileBuilder ; + this.recorder = recorder ; + } + + @Override + public ObjectFile buildObjectFile(FileSet fsObjectFile, String ext) { + ObjectFile objectFile = builder.buildObjectFile(fsObjectFile, ext); + FileRef ref = FileRef.create(fsObjectFile, ext) ; + recorder.record(ref, objectFile); + return objectFile; + } + } + static class BlockMgrBuilderRecorder implements BlockMgrBuilder { - private BlockMgrBuilder builder ; - private RecordBlockMgr recorder ; + private final BlockMgrBuilder builder ; + private final RecordBlockMgr recorder ; BlockMgrBuilderRecorder(BlockMgrBuilder blkMgrBuilder, RecordBlockMgr recorder) { this.builder = blkMgrBuilder ; @@ -414,16 +437,19 @@ static class BlockMgrBuilderRecorder implements BlockMgrBuilder { public BlockMgr buildBlockMgr(FileSet fileSet, String ext, IndexParams params) { BlockMgr blkMgr = builder.buildBlockMgr(fileSet, ext, params) ; FileRef ref = FileRef.create(fileSet, ext) ; + //System.err.println("Record (BlockMgr) = "+ref); recorder.record(ref, blkMgr) ; return blkMgr ; } } - static class Recorder implements RecordBlockMgr, RecordNodeTable { + static class Recorder implements RecordBlockMgr, RecordObjectFile, RecordNodeTable { Map blockMgrs = null ; + Map objectFiles = null ; + // Not used currently. Map bufferChannels = null ; - Map nodeTables = null ; + Map nodeTables = null ; boolean recording = false ; Recorder() { } @@ -433,15 +459,18 @@ void start() { throw new TDBException("Recorder already recording") ; recording = true ; blockMgrs = new HashMap<>() ; + + objectFiles = new HashMap<>() ; bufferChannels = new HashMap<>() ; nodeTables = new HashMap<>() ; } void finish() { if ( ! recording ) throw new TDBException("Recorder not recording") ; + // null out, not .clear. blockMgrs = null ; + objectFiles = null ; bufferChannels = null ; - nodeTables = null ; recording = false ; } @@ -452,6 +481,13 @@ public void record(FileRef fileRef, BlockMgr blockMgr) { blockMgrs.put(fileRef, blockMgr) ; } + @Override + public void record(FileRef fileRef, ObjectFile objFile) { + if ( recording ) + // log.info("ObjectTable: "+fileRef) ; + objectFiles.put(fileRef, objFile); + } + @Override public void record(FileRef fileRef, NodeTable nodeTable) { if ( recording ) diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/StorageConfig.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/StorageConfig.java index 9c01f420e6a..1da389bd033 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/store/StorageConfig.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/StorageConfig.java @@ -23,29 +23,33 @@ import org.apache.jena.tdb.base.block.BlockMgr ; import org.apache.jena.tdb.base.file.BufferChannel ; import org.apache.jena.tdb.base.file.Location ; +import org.apache.jena.tdb.base.objectfile.ObjectFile; import org.apache.jena.tdb.setup.StoreParams ; -import org.apache.jena.tdb.store.nodetable.NodeTable ; +import org.apache.jena.tdb.store.nodetable.NodeTable; import org.apache.jena.tdb.sys.FileRef ; public class StorageConfig { public final StoreParams params ; public final Map blockMgrs ; - public final Map bufferChannels ; - public final Map nodeTables ; + public final Map objectFiles; + public final Map bufferChannels; + public final Map nodeTables; public final Location location ; public final boolean writeable ; public StorageConfig(Location location, StoreParams params, boolean writeable, Map blockMgrs, - Map bufferChannels, + Map objectFiles, + Map bufferChannels, Map nodeTables) { this.location = location ; this.params = params ; this.blockMgrs = blockMgrs ; + this.objectFiles = objectFiles ; this.bufferChannels = bufferChannels ; - this.nodeTables = nodeTables ; + this.nodeTables = nodeTables; this.writeable = writeable ; } diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableNative.java b/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableNative.java index 51ceee167b7..9974c5d997a 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableNative.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/store/nodetable/NodeTableNative.java @@ -228,23 +228,24 @@ private Iterator> all2() } @Override - public void sync() - { - if ( syncNeeded ) - { - if ( nodeHashToId != null ) - nodeHashToId.sync() ; + public void sync() { + if ( syncNeeded ) { if ( getObjects() != null ) - getObjects().sync() ; - syncNeeded = false ; + getObjects().sync(); + if ( nodeHashToId != null ) + nodeHashToId.sync(); + syncNeeded = false; } } - public ObjectFile getObjects() - { + public ObjectFile getObjects() { return objects; } - + + public Index getIndex() { + return nodeHashToId; + } + @Override public String toString() { return objects.getLabel() ; } diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/sys/SetupTDB.java b/jena-tdb/src/main/java/org/apache/jena/tdb/sys/SetupTDB.java index 29ff118dc2a..bbed8eb21d5 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/sys/SetupTDB.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/sys/SetupTDB.java @@ -104,55 +104,10 @@ public static RangeIndex makeBPlusTree(FileSet fs, int blkSize, } public static RecordFactory makeRecordFactory(int keyLen, int valueLen) - { - return SetupIndex.makeRecordFactory(keyLen, valueLen) ; - } - // - // /** Make a NodeTable without cache and inline wrappers */ - // public static NodeTable makeNodeTableBase(Location location, String indexNode2Id, String indexId2Node) - // { - // if (location.isMem()) - // return NodeTableFactory.createMem() ; - // - // // -- make id to node mapping -- Names.indexId2Node - // FileSet fsIdToNode = new FileSet(location, indexId2Node) ; - // - // ObjectFile stringFile = makeObjectFile(fsIdToNode) ; - // - // // -- make node to id mapping -- Names.indexNode2Id - // // Make index of id to node (data table) - // - // // No caching at the index level - we use the internal caches of the node table. - // Index nodeToId = makeIndex(location, indexNode2Id, LenNodeHash, SizeOfNodeId, -1 ,-1) ; - // - // // -- Make the node table using the components established above. - // NodeTable nodeTable = new NodeTableNative(nodeToId, stringFile) ; - // return nodeTable ; - // } - // - // /** Make a NodeTable with cache and inline wrappers */ - // public static NodeTable makeNodeTable(Location location) - // { - // return makeNodeTable(location, - // Names.indexNode2Id, SystemTDB.Node2NodeIdCacheSize, - // Names.indexId2Node, SystemTDB.NodeId2NodeCacheSize, - // SystemTDB.NodeMissCacheSize) ; - // } - // - // /** Make a NodeTable with cache and inline wrappers */ - // public static NodeTable makeNodeTable(Location location, - // String indexNode2Id, int nodeToIdCacheSize, - // String indexId2Node, int idToNodeCacheSize, - // int nodeMissCacheSize) - // { - // NodeTable nodeTable = makeNodeTableBase(location, indexNode2Id, indexId2Node) ; - // nodeTable = NodeTableCache.create(nodeTable, nodeToIdCacheSize, idToNodeCacheSize, nodeMissCacheSize) ; - // nodeTable = NodeTableInline.create(nodeTable) ; - // return nodeTable ; - // } - // + { + return SetupIndex.makeRecordFactory(keyLen, valueLen) ; + } - // XXX Move to FileFactory public static ObjectFile makeObjectFile(FileSet fsIdToNode) { String filename = fsIdToNode.filename(Names.extNodeData) ; diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java index 1a052f4805a..7a3adb533c4 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java @@ -25,53 +25,52 @@ import org.apache.jena.tdb.base.block.BlockMgr ; import org.apache.jena.tdb.base.block.BlockMgrLogger ; import org.apache.jena.tdb.base.block.BlockMgrReadonly ; -import org.apache.jena.tdb.base.file.FileFactory ; +import org.apache.jena.tdb.base.file.FileFactory; import org.apache.jena.tdb.base.file.FileSet ; import org.apache.jena.tdb.base.objectfile.ObjectFile ; -import org.apache.jena.tdb.base.record.RecordFactory ; -import org.apache.jena.tdb.index.Index ; -import org.apache.jena.tdb.index.IndexMap ; -import org.apache.jena.tdb.index.IndexParams ; -import org.apache.jena.tdb.setup.BlockMgrBuilder ; -import org.apache.jena.tdb.setup.DatasetBuilderStd ; -import org.apache.jena.tdb.setup.NodeTableBuilder ; -import org.apache.jena.tdb.setup.StoreParams ; +import org.apache.jena.tdb.base.objectfile.ObjectFileReadonly; +import org.apache.jena.tdb.base.record.RecordFactory; +import org.apache.jena.tdb.index.*; +import org.apache.jena.tdb.setup.*; import org.apache.jena.tdb.store.DatasetGraphTDB ; -import org.apache.jena.tdb.store.nodetable.NodeTable ; -import org.apache.jena.tdb.store.nodetable.NodeTableInline ; -import org.apache.jena.tdb.store.nodetable.NodeTableReadonly ; +import org.apache.jena.tdb.store.nodetable.NodeTable; +import org.apache.jena.tdb.store.nodetable.NodeTableInline; +import org.apache.jena.tdb.store.nodetable.NodeTableReadonly; import org.apache.jena.tdb.sys.FileRef ; -import org.apache.jena.tdb.sys.Names ; -import org.apache.jena.tdb.sys.SystemTDB ; +import org.apache.jena.tdb.sys.Names; +import org.apache.jena.tdb.sys.SystemTDB; public class DatasetBuilderTxn { // Ideally, don't make a DatasetGraphTDB to pass to new DatasetGraphTxn as it rips it apart. // Context for the build. - private TransactionManager txnMgr ; - private Map blockMgrs ; - private Map nodeTables ; - private Transaction txn ; - private DatasetGraphTDB dsg ; - - public DatasetBuilderTxn(TransactionManager txnMgr) { this.txnMgr = txnMgr ; } - - public DatasetGraphTxn build(Transaction transaction, ReadWrite mode, DatasetGraphTDB dsg) { + private final TransactionManager txnMgr ; + private final Map blockMgrs ; + private final Map objectFiles; + private final Map nodeTables; + private final DatasetGraphTDB dsg ; + private Transaction txn; + + public DatasetBuilderTxn(TransactionManager txnMgr, DatasetGraphTDB dsg) { + this.txnMgr = txnMgr ; this.blockMgrs = dsg.getConfig().blockMgrs ; + this.objectFiles = dsg.getConfig().objectFiles ; this.nodeTables = dsg.getConfig().nodeTables ; - this.txn = transaction ; this.dsg = dsg ; - + } + + DatasetGraphTxn build(Transaction txn, ReadWrite mode) { + this.txn = txn; DatasetGraphTDB dsgTDB ; - + switch(mode) { - case READ : dsgTDB = buildReadonly() ; break ; - case WRITE : dsgTDB = buildWritable() ; break ; - default: dsgTDB = null ; // Silly Java. + case READ : dsgTDB = buildReadonly() ; break ; + case WRITE : dsgTDB = buildWritable() ; break ; + default: dsgTDB = null ; } - + DatasetGraphTxn dsgTxn = new DatasetGraphTxn(dsgTDB, txn) ; // Copy context. Changes not propagated back to the base dataset. dsgTxn.getContext().putAll(dsg.getContext()) ; @@ -79,17 +78,16 @@ public DatasetGraphTxn build(Transaction transaction, ReadWrite mode, DatasetGra } private DatasetGraphTDB buildReadonly() { - BlockMgrBuilder blockMgrBuilder = new BlockMgrBuilderReadonly() ; - NodeTableBuilder nodeTableBuilder = new NodeTableBuilderReadonly() ; + BlockMgrBuilder blockMgrBuilder = new BlockMgrBuilderReadonly(); + NodeTableBuilder nodeTableBuilder = new NodeTableBuilderReadonly(); DatasetBuilderStd x = new DatasetBuilderStd(blockMgrBuilder, nodeTableBuilder) ; DatasetGraphTDB dsg2 = x._build(dsg.getLocation(), dsg.getConfig().params, false, dsg.getReorderTransform()) ; - return dsg2 ; } private DatasetGraphTDB buildWritable() { BlockMgrBuilder blockMgrBuilder = new BlockMgrBuilderTx() ; - NodeTableBuilder nodeTableBuilder = new NodeTableBuilderTx() ; + NodeTableBuilder nodeTableBuilder = new NodeTableBuilderTx(); DatasetBuilderStd x = new DatasetBuilderStd(blockMgrBuilder, nodeTableBuilder) ; DatasetGraphTDB dsg2 = x._build(dsg.getLocation(), dsg.getConfig().params, true, dsg.getReorderTransform()) ; dsg2.getContext().putAll(dsg.getContext()) ; @@ -135,7 +133,10 @@ public NodeTable buildNodeTable(FileSet fsIndex, FileSet fsObjectFile, StorePara else objectFile = FileFactory.createObjectFileDisk(objFilename) ; - NodeTableTrans ntt = new NodeTableTrans(txn, fsObjectFile.getBasename(), ntBase, idx, objectFile) ; + // Allow for a modified base NodeTable. + NodeTable ntBaseTrans = ntBase; + + NodeTableTrans ntt = new NodeTableTrans(txn, fsObjectFile.getBasename(), ntBaseTrans, idx, objectFile) ; txn.addComponent(ntt) ; // Add inline wrapper. @@ -159,6 +160,22 @@ public BlockMgr buildBlockMgr(FileSet fileSet, String ext, IndexParams params) { } } + // Object files currently, don't need journalling. Because they aer apend only, they + // are "self journalling" - can append to them which used read-only elsewhere if the + // index to access them is transactional. +// class ObjectFileBuilderTx implements ObjectFileBuilder +// { +// @Override +// public ObjectFile buildObjectFile(FileSet fileSet, String ext) { +// FileRef ref = FileRef.create(fileSet, ext) ; +// ObjectFile baseObjFile = objectFiles.get(ref); +// if ( baseObjFile == null ) +// throw new TDBException("No ObjectFile for " + ref) ; +// ObjectFileJournal objFile = new ObjectFileJournal(txn, ref, baseObjectFile); +// return objFile; +// } +// } + // ---- Build passthrough versions for readonly access class BlockMgrBuilderReadonly implements BlockMgrBuilder @@ -184,4 +201,18 @@ public NodeTable buildNodeTable(FileSet fsIndex, FileSet fsObjectFile, StorePara return nt ; } } + + class ObjectFileBuilderReadonly implements ObjectFileBuilder + { + @Override + public ObjectFile buildObjectFile(FileSet fileSet, String ext) { + FileRef ref = FileRef.create(fileSet, ext) ; + ObjectFile objFile = objectFiles.get(ref); + if ( objFile == null ) + throw new TDBException("No ObjectFile for " + ref) ; + objFile = new ObjectFileReadonly(objFile) ; + return objFile; + } + } + } diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/JournalControl.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/JournalControl.java index a2282c67239..f384908e3d2 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/JournalControl.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/JournalControl.java @@ -29,22 +29,23 @@ import org.apache.jena.atlas.iterator.Iter ; import org.apache.jena.atlas.lib.FileOps ; +import org.apache.jena.atlas.logging.FmtLog; import org.apache.jena.tdb.TDBException ; import org.apache.jena.tdb.base.block.Block ; import org.apache.jena.tdb.base.block.BlockMgr ; import org.apache.jena.tdb.base.file.BufferChannel ; import org.apache.jena.tdb.base.file.BufferChannelFile ; -import org.apache.jena.tdb.base.file.FileFactory ; +import org.apache.jena.tdb.base.file.FileFactory; import org.apache.jena.tdb.base.file.Location ; -import org.apache.jena.tdb.base.objectfile.ObjectFile ; -import org.apache.jena.tdb.base.record.RecordFactory ; -import org.apache.jena.tdb.index.IndexMap ; +import org.apache.jena.tdb.base.objectfile.ObjectFile; +import org.apache.jena.tdb.base.record.RecordFactory; +import org.apache.jena.tdb.index.IndexMap; import org.apache.jena.tdb.store.DatasetGraphTDB ; import org.apache.jena.tdb.store.StorageConfig ; -import org.apache.jena.tdb.store.nodetable.NodeTable ; +import org.apache.jena.tdb.store.nodetable.NodeTable; import org.apache.jena.tdb.sys.FileRef ; import org.apache.jena.tdb.sys.Names ; -import org.apache.jena.tdb.sys.SystemTDB ; +import org.apache.jena.tdb.sys.SystemTDB; import org.slf4j.Logger ; import org.slf4j.LoggerFactory ; @@ -91,8 +92,12 @@ public static void recovery(DatasetGraphTDB dsg) if ( journal == null || journal.isEmpty() ) return ; + for ( FileRef fileRef : dsg.getConfig().nodeTables.keySet() ) recoverNodeDat(dsg, fileRef) ; + // Not used currently. +// for ( FileRef fileRef : dsg.getConfig().objectFiles.keySet() ) +// recoverObjectFile(dsg, fileRef) ; recoverFromJournal(dsg.getConfig(), journal) ; journal.close() ; @@ -196,6 +201,10 @@ private static void recoverSegment(Journal jrnl, long startPosn, long endPosn, S } finally { Iter.close(iter) ; } } + private static void recoverObjectFile(DatasetGraphTDB dsg, FileRef fileRef) { + FmtLog.warn(log, "Not recovered: recoverObjectFile[%s]", fileRef); + } + /** Recover a node data file (".dat"). * Node data files are append-only so recovering, then not using the data is safe. * Node data file is a precursor for full recovery that works from the master journal. diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java index 433da45bc8d..c87b977d87a 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/TransactionManager.java @@ -466,7 +466,7 @@ private DatasetGraphTxn createDSGTxn(DatasetGraphTDB dsg, Transaction txn, ReadW } } - DatasetGraphTxn dsgTxn = new DatasetBuilderTxn(this).build(txn, mode, dsg) ; + DatasetGraphTxn dsgTxn = new DatasetBuilderTxn(this, dsg).build(txn, mode); if ( mode == ReadWrite.READ ) { // If a READ transaction, cache the storage view. // This is cleared when a WRITE commits From 70d958aa8897fa467bc81cc145146abb0607c16a Mon Sep 17 00:00:00 2001 From: Andy Seaborne Date: Wed, 28 Jun 2017 12:31:44 +0100 Subject: [PATCH 9/9] Edit comment --- .../jena/tdb/transaction/DatasetBuilderTxn.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java index 7a3adb533c4..e32bc2a66ed 100644 --- a/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java +++ b/jena-tdb/src/main/java/org/apache/jena/tdb/transaction/DatasetBuilderTxn.java @@ -33,9 +33,7 @@ import org.apache.jena.tdb.index.*; import org.apache.jena.tdb.setup.*; import org.apache.jena.tdb.store.DatasetGraphTDB ; -import org.apache.jena.tdb.store.nodetable.NodeTable; -import org.apache.jena.tdb.store.nodetable.NodeTableInline; -import org.apache.jena.tdb.store.nodetable.NodeTableReadonly; +import org.apache.jena.tdb.store.nodetable.*; import org.apache.jena.tdb.sys.FileRef ; import org.apache.jena.tdb.sys.Names; import org.apache.jena.tdb.sys.SystemTDB; @@ -160,9 +158,10 @@ public BlockMgr buildBlockMgr(FileSet fileSet, String ext, IndexParams params) { } } - // Object files currently, don't need journalling. Because they aer apend only, they - // are "self journalling" - can append to them which used read-only elsewhere if the - // index to access them is transactional. + // Object files currently don't need journalling. Because they are append only, they + // are "self journalling" - we can append to them while used read-only elsewhere if + // the index to access them is transactional and does not point into the appended new + // bytes. // class ObjectFileBuilderTx implements ObjectFileBuilder // { // @Override