/** * Reader factory method. Build a Node object (of the right type) by reading a block in the file. * * @param config Configuration of the History Tree * @param fc FileChannel to the history file, ALREADY SEEKED at the start of the node. * @return The node object * @throws IOException If there was an error reading from the file channel */ public static final HTNode readNode(HTConfig config, FileChannel fc) throws IOException { HTNode newNode = null; int res, i; ByteBuffer buffer = ByteBuffer.allocate(config.getBlockSize()); buffer.order(ByteOrder.LITTLE_ENDIAN); buffer.clear(); res = fc.read(buffer); assert (res == config.getBlockSize()); buffer.flip(); /* Read the common header part */ byte typeByte = buffer.get(); NodeType type = NodeType.fromByte(typeByte); long start = buffer.getLong(); long end = buffer.getLong(); int seqNb = buffer.getInt(); int parentSeqNb = buffer.getInt(); int intervalCount = buffer.getInt(); int stringSectionOffset = buffer.getInt(); buffer.get(); // TODO Used to be "isDone", to be removed from the header /* Now the rest of the header depends on the node type */ switch (type) { case CORE: /* Core nodes */ newNode = new CoreNode(config, seqNb, parentSeqNb, start); newNode.readSpecificHeader(buffer); break; case LEAF: /* Leaf nodes */ newNode = new LeafNode(config, seqNb, parentSeqNb, start); newNode.readSpecificHeader(buffer); break; default: /* Unrecognized node type */ throw new IOException(); } /* * At this point, we should be done reading the header and 'buffer' * should only have the intervals left */ for (i = 0; i < intervalCount; i++) { HTInterval interval = HTInterval.readFrom(buffer); newNode.fIntervals.add(interval); newNode.fSizeOfIntervalSection += interval.getIntervalSize(); } /* Assign the node's other information we have read previously */ newNode.fNodeEnd = end; newNode.fStringSectionOffset = stringSectionOffset; newNode.fIsOnDisk = true; return newNode; }