Example #1
0
  /**
   * 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;
  }
Example #2
0
  /**
   * Constructor
   *
   * @param config Configuration of the History Tree
   * @param seqNumber The (unique) sequence number assigned to this particular node
   * @param parentSeqNumber The sequence number of this node's parent node
   * @param start The earliest timestamp stored in this node
   */
  protected HTNode(HTConfig config, int seqNumber, int parentSeqNumber, long start) {
    fConfig = config;
    fNodeStart = start;
    fSequenceNumber = seqNumber;
    fParentSequenceNumber = parentSeqNumber;

    fStringSectionOffset = config.getBlockSize();
    fSizeOfIntervalSection = 0;
    fIsOnDisk = false;
    fIntervals = new ArrayList<>();
  }
Example #3
0
  /**
   * Constructor
   *
   * @param config Configuration of the History Tree
   * @param seqNumber The (unique) sequence number assigned to this particular node
   * @param parentSeqNumber The sequence number of this node's parent node
   * @param start The earliest timestamp stored in this node
   */
  protected HTNode(HTConfig config, int seqNumber, int parentSeqNumber, long start) {
    this.config = config;
    this.nodeStart = start;
    this.sequenceNumber = seqNumber;
    this.parentSequenceNumber = parentSeqNumber;

    this.stringSectionOffset = config.getBlockSize();
    this.sizeOfIntervalSection = 0;
    this.isOnDisk = false;
    this.intervals = new ArrayList<>();
  }
Example #4
0
  /**
   * Returns the current space utilization of this node, as a percentage. (used space / total usable
   * space, which excludes the header)
   *
   * @return The percentage (value between 0 and 100) of space utilization in in this node.
   */
  public long getNodeUsagePercent() {
    fRwl.readLock().lock();
    try {
      final int blockSize = fConfig.getBlockSize();
      float freePercent =
          (float) getNodeFreeSpace() / (float) (blockSize - getTotalHeaderSize()) * 100F;
      return (long) (100L - freePercent);

    } finally {
      fRwl.readLock().unlock();
    }
  }
Example #5
0
  /**
   * Write this node to the given file channel.
   *
   * @param fc The file channel to write to (should be sought to be correct position)
   * @throws IOException If there was an error writing
   */
  public final void writeSelf(FileChannel fc) throws IOException {
    /*
     * Yes, we are taking the *read* lock here, because we are reading the
     * information in the node to write it to disk.
     */
    fRwl.readLock().lock();
    try {
      final int blockSize = fConfig.getBlockSize();
      int curStringsEntryEndPos = blockSize;

      ByteBuffer buffer = ByteBuffer.allocate(blockSize);
      buffer.order(ByteOrder.LITTLE_ENDIAN);
      buffer.clear();

      /* Write the common header part */
      buffer.put(getNodeType().toByte());
      buffer.putLong(fNodeStart);
      buffer.putLong(fNodeEnd);
      buffer.putInt(fSequenceNumber);
      buffer.putInt(fParentSequenceNumber);
      buffer.putInt(fIntervals.size());
      buffer.putInt(fStringSectionOffset);
      buffer.put((byte) 1); // TODO Used to be "isDone", to be removed from header

      /* Now call the inner method to write the specific header part */
      writeSpecificHeader(buffer);

      /* Back to us, we write the intervals */
      for (HTInterval interval : fIntervals) {
        int size = interval.writeInterval(buffer, curStringsEntryEndPos);
        curStringsEntryEndPos -= size;
      }

      /*
       * Write padding between the end of the Data section and the start
       * of the Strings section (needed to fill the node in case there is
       * no Strings section)
       */
      while (buffer.position() < fStringSectionOffset) {
        buffer.put((byte) 0);
      }

      /*
       * If the offsets were right, the size of the Strings section should
       * be == to the expected size
       */
      assert (curStringsEntryEndPos == fStringSectionOffset);

      /* Finally, write everything in the Buffer to disk */

      // if we don't do this, flip() will lose what's after.
      buffer.position(blockSize);

      buffer.flip();
      int res = fc.write(buffer);
      assert (res == blockSize);

    } finally {
      fRwl.readLock().unlock();
    }
    fIsOnDisk = true;
  }