Ejemplo n.º 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;
  }
Ejemplo n.º 2
0
  /**
   * Get a single Interval from the information in this node If the key/timestamp pair cannot be
   * found, we return null.
   *
   * @param key The attribute quark to look for
   * @param t The timestamp
   * @return The Interval containing the information we want, or null if it wasn't found
   * @throws TimeRangeException If 't' is invalid
   */
  public HTInterval getRelevantInterval(int key, long t) throws TimeRangeException {
    fRwl.readLock().lock();
    try {
      for (int i = getStartIndexFor(t); i < fIntervals.size(); i++) {
        HTInterval curInterval = fIntervals.get(i);
        if (curInterval.getAttribute() == key
            && curInterval.getStartTime() <= t
            && curInterval.getEndTime() >= t) {
          return curInterval;
        }
      }

      /* We didn't find the relevant information in this node */
      return null;

    } finally {
      fRwl.readLock().unlock();
    }
  }
Ejemplo n.º 3
0
  /**
   * Add an interval to this node
   *
   * @param newInterval Interval to add to this node
   */
  public void addInterval(HTInterval newInterval) {
    fRwl.writeLock().lock();
    try {
      /* Just in case, should be checked before even calling this function */
      assert (newInterval.getIntervalSize() <= getNodeFreeSpace());

      /* Find the insert position to keep the list sorted */
      int index = fIntervals.size();
      while (index > 0 && newInterval.compareTo(fIntervals.get(index - 1)) < 0) {
        index--;
      }

      fIntervals.add(index, newInterval);
      fSizeOfIntervalSection += newInterval.getIntervalSize();

      /* Update the in-node offset "pointer" */
      fStringSectionOffset -= (newInterval.getStringsEntrySize());
    } finally {
      fRwl.writeLock().unlock();
    }
  }
Ejemplo n.º 4
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;
  }