/******************************************************************************* * Copyright (c) 2017 École Polytechnique de Montréal * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.tracecompass.internal.provisional.datastore.core.historytree; import java.io.IOException; import java.nio.channels.FileChannel; import java.util.Collection; import java.util.Collections; import java.util.function.Predicate; import org.eclipse.tracecompass.internal.provisional.datastore.core.condition.RangeCondition; import org.eclipse.tracecompass.internal.provisional.datastore.core.exceptions.RangeException; import org.eclipse.tracecompass.internal.provisional.datastore.core.interval.IHTInterval; /** * Interface for history tree nodes * * @author Geneviève Bastien * @param <E> * The type of objects that will be saved in the tree */ public interface IHTNode<E extends IHTInterval> { /** * The type of node */ public enum NodeType { /** * Core node, which is a "front" node, at any level of the tree except * the bottom-most one. It has children, and may have extensions. */ CORE((byte) 1), /** * Leaf node, which is a node at the last bottom level of the tree. It * cannot have any children or extensions. */ LEAF((byte) 2); private final byte fByte; NodeType(byte rep) { fByte = rep; } /** * Determine a node type by reading a serialized byte. * * @param rep * The byte representation of the node type * @return The corresponding NodeType */ public static NodeType fromByte(byte rep) { switch (rep) { case 1: return CORE; case 2: return LEAF; default: throw new IllegalArgumentException("The NodeType byte " + rep + " is not a valid type"); //$NON-NLS-1$ //$NON-NLS-2$ } } /** * Get the byte representation of this node type. It can then be read * with {@link #fromByte}. * * @return The byte matching this node type */ public byte toByte() { return fByte; } } /** * 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 */ void writeSelf(FileChannel fc) throws IOException; /** * Get the start time of this node. * * @return The start time of this node */ long getNodeStart(); /** * Get the end time of this node. Will return {@link Long#MAX_VALUE} if the * node is not yet written to disk, as the real end time is not yet known. * * @return The end time of this node. */ long getNodeEnd(); /** * Get the sequence number of this node. * * @return The sequence number of this node */ int getSequenceNumber(); /** * Get the sequence number of this node's parent. * * @return The parent sequence number */ int getParentSequenceNumber(); /** * Change this node's parent. Used when we create a new root node for * example. * * @param newParent * The sequence number of the node that is the new parent */ void setParentSequenceNumber(int newParent); /** * Return if this node is "done" (full and written to disk). * * @return If this node is done or not */ boolean isOnDisk(); /** * Add an interval to this node. The caller of this method must make sure that * there is enough space on this node to add this object. Also, it is the * responsibility of the caller to make sure that the element to add is * within the boundary of this node. No check on start and end is expected * to be done in this method. * * @param newInterval * Interval to add to this node */ void add(E newInterval); /** * We've received word from the containerTree that newest nodes now exist to * our right. (Puts isDone = true and sets the endtime) * * @param endtime * The nodeEnd time that the node will have */ void closeThisNode(long endtime); /** * Retrieve the intervals inside this node that match the given conditions. * * @param timeCondition * The time-based RangeCondition * @param extraPredicate * Extra predicate to run on the elements. Only those also * matching this predicate will be returned. * @return Iterable of the elements in this node matching the condtions */ Iterable<E> getMatchingIntervals(RangeCondition<Long> timeCondition, Predicate<E> extraPredicate); /** * Return the total header size of this node (will depend on the node type). * * @return The total header size */ int getTotalHeaderSize(); /** * Returns the free space left in the node to write objects * * @return The amount of free space in the node (in bytes) */ int getNodeFreeSpace(); /** * 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 * this node. */ long getNodeUsagePercent(); /** * Get the type of this node * * @return The node type */ NodeType getNodeType(); /** * Return whether this node has elements in it or is empty * * @return <code>true</code> if the node is empty */ boolean isEmpty(); // --------------------------------------- // Methods for nodes with children. Leaf nodes can use these default methods // --------------------------------------- /** * Return the number of child nodes this node has. * * @return The number of child nodes */ default int getNbChildren() { return 0; } /** * Get the child node corresponding to the specified index. It will throw an * {@link IndexOutOfBoundsException} if there is no children at this index. * * @param index * The index of the child to lookup * @return The child node */ default int getChild(int index) { throw new IndexOutOfBoundsException("This node does not have any children"); //$NON-NLS-1$ } /** * Get the latest (right-most) child node of this node. This applies only if * the node is allowed to have children, ie is a {@link NodeType#CORE} node, * otherwise this method is not supported. * * @return The latest child node */ default int getLatestChild() { throw new UnsupportedOperationException("This node does not support children"); //$NON-NLS-1$ } /** * Tell this node that it has a new child. This applies only if the node is * allowed to have children, ie is a {@link NodeType#CORE} node, otherwise * this method is not supported. * * @param childNode * The new child node to add to this one */ default void linkNewChild(IHTNode<E> childNode) { throw new UnsupportedOperationException("This node does not support children"); //$NON-NLS-1$ } /** * Method to select the sequence numbers for the children of the current * node that intersect the given timestamp. Useful when navigating the tree. * * @param timeCondition * The time-based range condition to choose which child is the next one * @return Collection of sequence numbers of the child nodes that intersect * the time condition, non-null empty collection if this is a Leaf Node * @throws RangeException * If t is out of the node's range */ default Collection<Integer> selectNextChildren(RangeCondition<Long> timeCondition) { return Collections.emptyList(); } }