1 /*******************************************************************************
2 * Copyright (c) 2016 École Polytechnique de Montréal
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.segmentstore
.core
.segmentHistoryTree
;
12 import java
.nio
.ByteBuffer
;
13 import java
.util
.Collection
;
14 import java
.util
.Collections
;
15 import java
.util
.Comparator
;
16 import java
.util
.HashSet
;
19 import org
.eclipse
.jdt
.annotation
.NonNull
;
20 import org
.eclipse
.jdt
.annotation
.Nullable
;
21 import org
.eclipse
.tracecompass
.internal
.provisional
.datastore
.core
.condition
.TimeRangeCondition
;
22 import org
.eclipse
.tracecompass
.internal
.provisional
.datastore
.core
.historytree
.IHTNode
;
23 import org
.eclipse
.tracecompass
.internal
.provisional
.datastore
.core
.historytree
.overlapping
.OverlappingNode
;
24 import org
.eclipse
.tracecompass
.segmentstore
.core
.BasicSegment
;
25 import org
.eclipse
.tracecompass
.segmentstore
.core
.ISegment
;
26 import org
.eclipse
.tracecompass
.segmentstore
.core
.SegmentComparators
;
29 * The history tree node class for segment history tree. This is an extension of
30 * the {@link OverlappingNode} class and keeps more information about the
31 * children of a node, that will help for sorting segments, one of the specific
32 * functionalities of the segment stores.
34 * @author Loic Prieur-Drevon
35 * @author Geneviève Bastien
37 * type of {@link ISegment}
39 public class SegmentTreeNode
<E
extends ISegment
> extends OverlappingNode
<E
> {
41 // These values represent the values for the current node only, not its
43 private long fMaxStart
= 0;
44 private long fMinEnd
= Long
.MAX_VALUE
;
45 private long fShortest
= Long
.MAX_VALUE
;
46 private long fLongest
= 0;
52 * The type of this node
54 * The size (in bytes) of a serialized node on disk
56 * The maximum allowed number of children per node
58 * The (unique) sequence number assigned to this particular node
59 * @param parentSeqNumber
60 * The sequence number of this node's parent node
62 * The earliest timestamp stored in this node
64 public SegmentTreeNode(NodeType type
, int blockSize
, int maxChildren
, int seqNumber
, int parentSeqNumber
, long start
) {
65 super(type
, blockSize
, maxChildren
, seqNumber
, parentSeqNumber
, start
);
70 * Adds the data concerning the segment nodes, max start/min end and
73 * @param <E> type of {@link ISegment}
75 protected static class OverlappingSegmentCoreData
<E
extends ISegment
> extends OverlappingExtraData
{
77 // These values cover the full subtrees of the child nodes
78 // Max start of an interval
79 private final long[] fChildMaxStart
;
80 // minimum end of an interval
81 private final long[] fChildMinEnd
;
83 private final long[] fMinLength
;
85 private final long[] fMaxLength
;
88 * Segment history tree node data constructor
91 * The node containing this extra data.
93 public OverlappingSegmentCoreData(SegmentTreeNode
<?
> node
) {
95 int size
= getNode().getMaxChildren();
97 * We instantiate the following arrays at full size right away,
98 * since we want to reserve that space in the node's header.
99 * "this.nbChildren" will tell us how many relevant entries there
100 * are in those tables.
102 fChildMaxStart
= new long[size
];
103 fChildMinEnd
= new long[size
];
104 fMinLength
= new long[size
];
105 fMaxLength
= new long[size
];
106 for (int i
= 0; i
< size
; i
++) {
107 fChildMaxStart
[i
] = 0;
108 fChildMinEnd
[i
] = Long
.MAX_VALUE
;
109 fMinLength
[i
] = Long
.MAX_VALUE
;
110 fMaxLength
[i
] = Long
.MIN_VALUE
;
115 protected SegmentTreeNode
<?
> getNode() {
116 /* Type enforced by constructor */
117 return (SegmentTreeNode
<?
>) super.getNode();
121 public void readSpecificHeader(@NonNull ByteBuffer buffer
) {
122 super.readSpecificHeader(buffer
);
123 int size
= getNode().getMaxChildren();
125 for (int i
= 0; i
< size
; i
++) {
126 fChildMaxStart
[i
] = buffer
.getLong();
127 fChildMinEnd
[i
] = buffer
.getLong();
128 fMinLength
[i
] = buffer
.getLong();
129 fMaxLength
[i
] = buffer
.getLong();
134 protected void writeSpecificHeader(@NonNull ByteBuffer buffer
) {
135 getNode().takeReadLock();
137 super.writeSpecificHeader(buffer
);
139 int size
= getNode().getMaxChildren();
142 * Write the children array
144 for (int i
= 0; i
< size
; i
++) {
145 buffer
.putLong(fChildMaxStart
[i
]);
146 buffer
.putLong(fChildMinEnd
[i
]);
147 buffer
.putLong(fMinLength
[i
]);
148 buffer
.putLong(fMaxLength
[i
]);
151 getNode().releaseReadLock();
156 protected int getSpecificHeaderSize() {
157 int maxChildren
= getNode().getMaxChildren();
158 int specificSize
= super.getSpecificHeaderSize();
160 * MAX_NB * Timevalue (max starts, min ends, min length, max length
163 specificSize
+= 4 * Long
.BYTES
* maxChildren
;
169 public void linkNewChild(IHTNode
<?
> childNode
) {
170 // The child node should be a SegmentTreeNode
171 if (!(childNode
instanceof SegmentTreeNode
)) {
172 throw new IllegalArgumentException("Adding a node that is not an segment tree node to an segment tree!"); //$NON-NLS-1$
174 getNode().takeWriteLock();
177 super.linkNewChild(childNode
);
178 final int childIndex
= getNbChildren() - 1;
180 // The child node should be a SegmentTreeNode, but in case it
181 // isn't, just return here
182 if (!(childNode
instanceof SegmentTreeNode
<?
>)) {
186 SegmentTreeNode
<E
> segmentNode
= (SegmentTreeNode
<E
>) childNode
;
187 // The child node may already have segments, so we update
188 // child's data with what is already in there
189 updateChild(segmentNode
, childIndex
);
191 // Add a listener on the child node to update its data in the
193 segmentNode
.addListener((node
, endtime
) -> updateChild((SegmentTreeNode
<E
>) node
, childIndex
));
196 getNode().releaseWriteLock();
200 private void updateChild(SegmentTreeNode
<E
> child
, int childIndex
) {
201 fChildMaxStart
[childIndex
] = child
.getMaxStart();
202 fChildMinEnd
[childIndex
] = child
.getMinEnd();
203 fMinLength
[childIndex
] = child
.getShortest();
204 fMaxLength
[childIndex
] = child
.getLongest();
205 // The child node's extra data applies to the child and its subtree,
206 // so also update with the child's children
207 for (int i
= 0; i
< child
.getNbChildren(); i
++) {
208 fChildMaxStart
[childIndex
] = Math
.max(fChildMaxStart
[childIndex
], child
.getMaxStart(i
));
209 fChildMinEnd
[childIndex
] = Math
.min(fChildMinEnd
[childIndex
], child
.getMinEnd(i
));
210 fMinLength
[childIndex
] = Math
.min(fMinLength
[childIndex
], child
.getShortest(i
));
211 fMaxLength
[childIndex
] = Math
.max(fMaxLength
[childIndex
], child
.getLongest(i
));
215 /* Make sure it is visible to the enclosing class */
217 protected Collection
<Integer
> selectNextIndices(TimeRangeCondition rc
) {
218 return super.selectNextIndices(rc
);
222 * Get the maximum start value of a child and its subtree
226 * @return The maximum start value of the child at index and its subtree
228 public long getMaxStart(int index
) {
229 getNode().takeReadLock();
231 if (index
>= getNbChildren()) {
232 throw new IndexOutOfBoundsException("The child at index " + index
+ " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
234 return fChildMaxStart
[index
];
236 getNode().releaseReadLock();
241 * Get the minimum end value of a child and its subtree
245 * @return The minimum end value of the child at index and its subtree
247 public long getMinEnd(int index
) {
248 getNode().takeReadLock();
250 if (index
>= getNbChildren()) {
251 throw new IndexOutOfBoundsException("The child at index " + index
+ " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
253 return fChildMinEnd
[index
];
255 getNode().releaseReadLock();
260 * Get the shortest element length of a child and its subtree
264 * @return The shortest length of the child at index and its subtree
266 public long getShortest(int index
) {
267 getNode().takeReadLock();
269 if (index
>= getNbChildren()) {
270 throw new IndexOutOfBoundsException("The child at index " + index
+ " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
272 return fMinLength
[index
];
274 getNode().releaseReadLock();
279 * Get the longest element length of a child and its subtree
283 * @return The longest length of the child at index and its subtree
285 public long getLongest(int index
) {
286 getNode().takeReadLock();
288 if (index
>= getNbChildren()) {
289 throw new IndexOutOfBoundsException("The child at index " + index
+ " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$
291 return fMaxLength
[index
];
293 getNode().releaseReadLock();
298 * Get the segment for a child node with the least value for the field
299 * corresponding to the comparator's field.
302 * The index of the child node
304 * The comparator with which to sort segments
305 * @return A segment whose value for the field that correspond to the
306 * comparator is the least value of the child node
308 public ISegment
getIndex(int index
, Comparator
<E
> order
) {
309 if (order
.equals(SegmentComparators
.INTERVAL_START_COMPARATOR
)) {
310 return new BasicSegment(getChildStart(index
), getChildStart(index
));
311 } else if (order
.equals(SegmentComparators
.INTERVAL_START_COMPARATOR
.reversed())) {
312 return new BasicSegment(fChildMaxStart
[index
], fChildMaxStart
[index
]);
313 } else if (order
.equals(SegmentComparators
.INTERVAL_END_COMPARATOR
)) {
314 return new BasicSegment(fChildMinEnd
[index
], fChildMinEnd
[index
]);
315 } else if (order
.equals(SegmentComparators
.INTERVAL_END_COMPARATOR
.reversed())) {
316 return new BasicSegment(getChildEnd(index
), getChildEnd(index
));
317 } else if (order
.equals(SegmentComparators
.INTERVAL_LENGTH_COMPARATOR
)) {
318 return new BasicSegment(0, fMinLength
[index
]);
319 } else if (order
.equals(SegmentComparators
.INTERVAL_LENGTH_COMPARATOR
.reversed())) {
320 return new BasicSegment(0, fMaxLength
[index
]);
322 // TODO: Don't know what to do with other comparators yet
323 return new BasicSegment(getChild(index
), getChild(index
));
329 protected @Nullable OverlappingSegmentCoreData
<E
> createNodeExtraData(final NodeType type
) {
330 if (type
== NodeType
.CORE
) {
331 return new OverlappingSegmentCoreData
<>(this);
337 * Get the number of intervals in this node
339 * @return The number of intervals
341 public int getNumIntervals() {
342 return getIntervals().size();
346 public void add(E newInterval
) {
347 super.add(newInterval
);
348 updateBoundaries(newInterval
);
352 * Get the maximum start time of an interval in this node
354 * @return the latest start time of this node's intervals
356 public long getMaxStart() {
361 * Get the earliest end time of an interval in this node
363 * @return the earliest end time of this node's intervals
365 public long getMinEnd() {
370 * Get the shortest duration of the intervals of this node
372 * @return the shortest duration of this node's intervals
374 public long getShortest() {
379 * Get the longest duration of the intervals of this node
381 * @return the longest duration of this node's intervals
383 public long getLongest() {
388 * Get the children intersecting the given time range, and return the least
389 * element for each child wrt to the comparator
392 * The range condition (start, end times) of the children
394 * The comparator to use to compare segments in child nodes
395 * @return For each intersecting child, a Tuple with the segment with the
396 * least value for the comparator
398 public Set
<Tuple
<ISegment
>> selectNextChildren(TimeRangeCondition range
, Comparator
<E
> order
) {
399 OverlappingSegmentCoreData
<E
> extraData
= getCoreNodeData();
400 if (extraData
!= null) {
401 Set
<Tuple
<ISegment
>> set
= new HashSet
<>();
402 for (Integer index
: extraData
.selectNextIndices(range
)) {
403 set
.add(new Tuple
<>(extraData
.getIndex(index
, order
), extraData
.getChild(index
)));
407 return Collections
.emptySet();
411 protected @Nullable OverlappingSegmentCoreData
<E
> getCoreNodeData() {
412 return (OverlappingSegmentCoreData
<E
>) super.getCoreNodeData();
416 * Get the maximum start value of a child subtree of this node
419 * The index of the child subtree
420 * @return The child subtree's maximal start value
422 protected long getMaxStart(int index
) {
423 OverlappingSegmentCoreData
<E
> extraData
= getCoreNodeData();
424 if (extraData
!= null) {
425 return extraData
.getMaxStart(index
);
427 throw new UnsupportedOperationException("A leaf node does not have children"); //$NON-NLS-1$
431 * Get the minimum end value of a child subtree of this node
434 * The index of the child subtree
435 * @return The child subtree's minimum end value
437 protected long getMinEnd(int index
) {
438 OverlappingSegmentCoreData
<E
> extraData
= getCoreNodeData();
439 if (extraData
!= null) {
440 return extraData
.getMinEnd(index
);
442 throw new UnsupportedOperationException("A leaf node does not have children"); //$NON-NLS-1$
446 * Get the length of the shortest element of a child subtree of this node
449 * The index of the child subtree
450 * @return The child subtree's shortest element length
452 protected long getShortest(int index
) {
453 OverlappingSegmentCoreData
<E
> extraData
= getCoreNodeData();
454 if (extraData
!= null) {
455 return extraData
.getShortest(index
);
457 throw new UnsupportedOperationException("A leaf node does not have children"); //$NON-NLS-1$
461 * Get the length of the longest element of a child subtree of this node
464 * The index of the child subtree
465 * @return The child subtree's longest element length
467 protected long getLongest(int index
) {
468 OverlappingSegmentCoreData
<E
> extraData
= getCoreNodeData();
469 if (extraData
!= null) {
470 return extraData
.getLongest(index
);
472 throw new UnsupportedOperationException("A leaf node does not have children"); //$NON-NLS-1$
476 * Class to store the node sequence numbers and Index element for
477 * sortedIterators PriorityQueue
479 static class Tuple
<E
> {
480 private final E fSegment
;
481 private final int fNodeSequenceNumber
;
485 * segment to use to order nodes in PriorityQueue
486 * @param nodeSequenceNumber
487 * sequence number of the node we want to read
489 public Tuple(E segment
, int nodeSequenceNumber
) {
491 fNodeSequenceNumber
= nodeSequenceNumber
;
495 * @return the element to compare or <code>null</code> if this node is
498 public E
getSegment() {
503 * @return the sequence number to read the node
505 public int getSequenceNumber() {
506 return fNodeSequenceNumber
;
511 * Get the tuples of minimal segments and sequence number for this node. If
512 * the current node is empty, <code>null</code> is returned.
515 * Comparator for which we need the key
516 * @return Tuple to sort nodes in iterator, <code>null</code> if not is
519 @Nullable Tuple
<E
> key(Comparator
<@NonNull E
> order
) {
523 return new Tuple
<>(Collections
.min(this.getIntervals(), order
), getSequenceNumber());
526 private void updateBoundaries(E segment
) {
527 fMaxStart
= Math
.max(fMaxStart
, segment
.getStart());
528 fMinEnd
= Math
.min(fMinEnd
, segment
.getEnd());
529 fShortest
= Math
.min(fShortest
, segment
.getLength());
530 fLongest
= Math
.max(fLongest
, segment
.getLength());