tmf: Remove back-reference from HT-Node to HT-Tree
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / backends / historytree / HistoryTree.java
CommitLineData
a52fde77 1/*******************************************************************************
61759503 2 * Copyright (c) 2012, 2013 Ericsson
a52fde77
AM
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
3b7f5abe 5 *
a52fde77
AM
6 * All rights reserved. This program and the accompanying materials are
7 * made available under the terms of the Eclipse Public License v1.0 which
8 * accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
3b7f5abe 10 *
a52fde77
AM
11 *******************************************************************************/
12
f9a76cac 13package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree;
a52fde77
AM
14
15import java.io.File;
16import java.io.FileInputStream;
17import java.io.IOException;
18import java.io.PrintWriter;
19import java.nio.ByteBuffer;
20import java.nio.ByteOrder;
3b7f5abe 21import java.nio.channels.ClosedChannelException;
a52fde77 22import java.nio.channels.FileChannel;
cb42195c
AM
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.List;
a52fde77 26
6d08acca 27import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
0fe46f2a 28import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateProvider;
a52fde77
AM
29
30/**
31 * Meta-container for the History Tree. This structure contains all the
32 * high-level data relevant to the tree.
3b7f5abe 33 *
ffd0aa67 34 * @author Alexandre Montplaisir
3b7f5abe 35 *
a52fde77
AM
36 */
37class HistoryTree {
38
cb42195c
AM
39 /**
40 * Size of the "tree header" in the tree-file The nodes will use this offset
41 * to know where they should be in the file. This should always be a
42 * multiple of 4K.
43 */
44 public static final int TREE_HEADER_SIZE = 4096;
45
a52fde77
AM
46 private static final int HISTORY_FILE_MAGIC_NUMBER = 0x05FFA900;
47
a96cc6be
AM
48 /** File format version. Increment when breaking compatibility. */
49 private static final int FILE_VERSION = 3;
a52fde77 50
dbdc452f
AM
51 // ------------------------------------------------------------------------
52 // Tree-specific configuration
53 // ------------------------------------------------------------------------
54
55 /** Container for all the configuration constants */
cb42195c 56 private final HTConfig config;
a52fde77 57
dbdc452f 58 /** Reader/writer object */
a52fde77
AM
59 private final HT_IO treeIO;
60
dbdc452f 61 // ------------------------------------------------------------------------
ecb12461 62 // Variable Fields (will change throughout the existence of the SHT)
dbdc452f
AM
63 // ------------------------------------------------------------------------
64
65 /** Latest timestamp found in the tree (at any given moment) */
a52fde77
AM
66 private long treeEnd;
67
dbdc452f 68 /** How many nodes exist in this tree, total */
a52fde77
AM
69 private int nodeCount;
70
dbdc452f 71 /** "Cache" to keep the active nodes in memory */
cb42195c 72 private List<CoreNode> latestBranch;
a52fde77 73
dbdc452f
AM
74 // ------------------------------------------------------------------------
75 // Constructors/"Destructors"
76 // ------------------------------------------------------------------------
77
a52fde77
AM
78 /**
79 * Create a new State History from scratch, using a SHTConfig object for
80 * configuration
a52fde77 81 */
7453b40e 82 HistoryTree(HTConfig conf) throws IOException {
a52fde77 83 /*
dbdc452f 84 * Simple check to make sure we have enough place in the 0th block
a52fde77
AM
85 * for the tree configuration
86 */
cb42195c 87 if (conf.getBlockSize() < TREE_HEADER_SIZE) {
dbdc452f
AM
88 throw new IllegalArgumentException();
89 }
a52fde77
AM
90
91 config = conf;
cb42195c 92 treeEnd = conf.getTreeStart();
a52fde77 93 nodeCount = 0;
cb42195c 94 latestBranch = new ArrayList<CoreNode>();
a52fde77
AM
95
96 /* Prepare the IO object */
97 treeIO = new HT_IO(this, true);
98
99 /* Add the first node to the tree */
cb42195c 100 CoreNode firstNode = initNewCoreNode(-1, conf.getTreeStart());
a52fde77
AM
101 latestBranch.add(firstNode);
102 }
103
a52fde77
AM
104 /**
105 * "Reader" constructor : instantiate a SHTree from an existing tree file on
106 * disk
3b7f5abe 107 *
a52fde77
AM
108 * @param existingFileName
109 * Path/filename of the history-file we are to open
a96cc6be
AM
110 * @param expProviderVersion
111 * The expected version of the state provider
a52fde77
AM
112 * @throws IOException
113 */
a96cc6be 114 HistoryTree(File existingStateFile, int expProviderVersion) throws IOException {
a52fde77
AM
115 /*
116 * Open the file ourselves, get the tree header information we need,
117 * then pass on the descriptor to the TreeIO object.
118 */
119 int rootNodeSeqNb, res;
120 int bs, maxc;
fb12b0c2 121 long startTime;
a52fde77
AM
122
123 /* Java I/O mumbo jumbo... */
fee997a5
AM
124 if (!existingStateFile.exists()) {
125 throw new IOException("Selected state file does not exist"); //$NON-NLS-1$
126 }
fb12b0c2 127 if (existingStateFile.length() <= 0) {
a96cc6be 128 throw new IOException("Empty target file"); //$NON-NLS-1$
a52fde77
AM
129 }
130
131 FileInputStream fis = new FileInputStream(existingStateFile);
cb42195c 132 ByteBuffer buffer = ByteBuffer.allocate(TREE_HEADER_SIZE);
a52fde77
AM
133 FileChannel fc = fis.getChannel();
134 buffer.order(ByteOrder.LITTLE_ENDIAN);
135 buffer.clear();
136 fc.read(buffer);
137 buffer.flip();
138
139 /*
140 * Check the magic number,to make sure we're opening the right type of
141 * file
142 */
143 res = buffer.getInt();
144 if (res != HISTORY_FILE_MAGIC_NUMBER) {
6f04204e
AM
145 fc.close();
146 fis.close();
a96cc6be 147 throw new IOException("Wrong magic number"); //$NON-NLS-1$
a52fde77
AM
148 }
149
a96cc6be
AM
150 res = buffer.getInt(); /* File format version number */
151 if (res != FILE_VERSION) {
6f04204e
AM
152 fc.close();
153 fis.close();
a96cc6be 154 throw new IOException("Mismatching History Tree file format versions"); //$NON-NLS-1$
a52fde77
AM
155 }
156
a96cc6be
AM
157 res = buffer.getInt(); /* Event handler's version number */
158 if (res != expProviderVersion &&
0fe46f2a 159 expProviderVersion != ITmfStateProvider.IGNORE_PROVIDER_VERSION) {
a96cc6be
AM
160 /*
161 * The existing history was built using a event handler that doesn't
162 * match the current one in the framework. Information could be all
163 * wrong, so we'll force a rebuild of the history file instead.
164 */
165 fc.close();
166 fis.close();
167 throw new IOException("Mismatching event handler versions"); //$NON-NLS-1$
168 }
a52fde77
AM
169
170 bs = buffer.getInt(); /* Block Size */
171 maxc = buffer.getInt(); /* Max nb of children per node */
172
173 this.nodeCount = buffer.getInt();
174 rootNodeSeqNb = buffer.getInt();
fb12b0c2 175 startTime = buffer.getLong();
a52fde77 176
a96cc6be 177 this.config = new HTConfig(existingStateFile, bs, maxc, expProviderVersion, startTime);
6f04204e 178 fc.close();
a52fde77
AM
179 fis.close();
180 /*
181 * FIXME We close fis here and the TreeIO will then reopen the same
182 * file, not extremely elegant. But how to pass the information here to
183 * the SHT otherwise?
184 */
185 this.treeIO = new HT_IO(this, false);
186
187 rebuildLatestBranch(rootNodeSeqNb);
cb42195c 188 this.treeEnd = latestBranch.get(0).getNodeEnd();
fb12b0c2
AM
189
190 /*
191 * Make sure the history start time we read previously is consistent
192 * with was is actually in the root node.
193 */
cb42195c 194 if (startTime != latestBranch.get(0).getNodeStart()) {
fb12b0c2
AM
195 fc.close();
196 fis.close();
197 throw new IOException("Inconsistent start times in the" + //$NON-NLS-1$
198 "history file, it might be corrupted."); //$NON-NLS-1$
199 }
a52fde77
AM
200 }
201
202 /**
203 * "Save" the tree to disk. This method will cause the treeIO object to
204 * commit all nodes to disk and then return the RandomAccessFile descriptor
205 * so the Tree object can save its configuration into the header of the
206 * file.
3b7f5abe 207 *
a52fde77 208 * @param requestedEndTime
d862bcb3 209 * The greatest timestamp present in the history tree
a52fde77 210 */
6a1074ce 211 void closeTree(long requestedEndTime) {
a52fde77
AM
212 FileChannel fc;
213 ByteBuffer buffer;
214 int i, res;
215
3b7f5abe 216 /*
6a1074ce
AM
217 * Work-around the "empty branches" that get created when the root node
218 * becomes full. Overwrite the tree's end time with the original wanted
219 * end-time, to ensure no queries are sent into those empty nodes.
3b7f5abe 220 *
6a1074ce
AM
221 * This won't be needed once extended nodes are implemented.
222 */
223 this.treeEnd = requestedEndTime;
224
a52fde77
AM
225 /* Close off the latest branch of the tree */
226 for (i = 0; i < latestBranch.size(); i++) {
227 latestBranch.get(i).closeThisNode(treeEnd);
228 treeIO.writeNode(latestBranch.get(i));
229 }
230
a52fde77 231 fc = treeIO.getFcOut();
cb42195c 232 buffer = ByteBuffer.allocate(TREE_HEADER_SIZE);
a52fde77
AM
233 buffer.order(ByteOrder.LITTLE_ENDIAN);
234 buffer.clear();
235
236 /* Save the config of the tree to the header of the file */
237 try {
238 fc.position(0);
239
240 buffer.putInt(HISTORY_FILE_MAGIC_NUMBER);
241
a96cc6be 242 buffer.putInt(FILE_VERSION);
cb42195c 243 buffer.putInt(config.getProviderVersion());
a52fde77 244
cb42195c
AM
245 buffer.putInt(config.getBlockSize());
246 buffer.putInt(config.getMaxChildren());
a52fde77
AM
247
248 buffer.putInt(nodeCount);
249
250 /* root node seq. nb */
cb42195c 251 buffer.putInt(latestBranch.get(0).getSequenceNumber());
a52fde77 252
fb12b0c2 253 /* start time of this history */
cb42195c 254 buffer.putLong(latestBranch.get(0).getNodeStart());
fb12b0c2 255
a52fde77
AM
256 buffer.flip();
257 res = fc.write(buffer);
cb42195c 258 assert (res <= TREE_HEADER_SIZE);
a52fde77
AM
259 /* done writing the file header */
260
261 } catch (IOException e) {
6f04204e 262 /* We should not have any problems at this point... */
6f04204e
AM
263 } finally {
264 try {
265 fc.close();
266 } catch (IOException e) {
6f04204e 267 }
a52fde77
AM
268 }
269 return;
270 }
271
dbdc452f
AM
272 // ------------------------------------------------------------------------
273 // Accessors
274 // ------------------------------------------------------------------------
ab604305 275
cb42195c
AM
276 HTConfig getConfig() {
277 return config;
278 }
279
a52fde77 280 long getTreeStart() {
cb42195c 281 return config.getTreeStart();
a52fde77
AM
282 }
283
284 long getTreeEnd() {
285 return treeEnd;
286 }
287
288 int getNodeCount() {
289 return nodeCount;
290 }
291
292 HT_IO getTreeIO() {
293 return treeIO;
294 }
295
cb42195c
AM
296 List<CoreNode> getLatestBranch() {
297 return Collections.unmodifiableList(latestBranch);
298 }
299
dbdc452f
AM
300 // ------------------------------------------------------------------------
301 // Operations
302 // ------------------------------------------------------------------------
303
a52fde77
AM
304 /**
305 * Rebuild the latestBranch "cache" object by reading the nodes from disk
306 * (When we are opening an existing file on disk and want to append to it,
307 * for example).
3b7f5abe 308 *
a52fde77
AM
309 * @param rootNodeSeqNb
310 * The sequence number of the root node, so we know where to
311 * start
3b7f5abe 312 * @throws ClosedChannelException
a52fde77 313 */
3b7f5abe 314 private void rebuildLatestBranch(int rootNodeSeqNb) throws ClosedChannelException {
a52fde77
AM
315 HTNode nextChildNode;
316
cb42195c 317 this.latestBranch = new ArrayList<CoreNode>();
a52fde77
AM
318
319 nextChildNode = treeIO.readNodeFromDisk(rootNodeSeqNb);
320 latestBranch.add((CoreNode) nextChildNode);
cb42195c
AM
321 while (latestBranch.get(latestBranch.size() - 1).getNbChildren() > 0) {
322 nextChildNode = treeIO.readNodeFromDisk(latestBranch.get(latestBranch.size() - 1).getLatestChild());
a52fde77
AM
323 latestBranch.add((CoreNode) nextChildNode);
324 }
325 }
326
327 /**
328 * Insert an interval in the tree
3b7f5abe 329 *
a52fde77 330 * @param interval
d862bcb3 331 * The interval to be inserted
a52fde77
AM
332 */
333 void insertInterval(HTInterval interval) throws TimeRangeException {
cb42195c 334 if (interval.getStartTime() < config.getTreeStart()) {
a52fde77
AM
335 throw new TimeRangeException();
336 }
337 tryInsertAtNode(interval, latestBranch.size() - 1);
338 }
339
340 /**
341 * Inner method to find in which node we should add the interval.
3b7f5abe 342 *
a52fde77
AM
343 * @param interval
344 * The interval to add to the tree
345 * @param indexOfNode
346 * The index *in the latestBranch* where we are trying the
347 * insertion
348 */
349 private void tryInsertAtNode(HTInterval interval, int indexOfNode) {
350 HTNode targetNode = latestBranch.get(indexOfNode);
351
352 /* Verify if there is enough room in this node to store this interval */
353 if (interval.getIntervalSize() > targetNode.getNodeFreeSpace()) {
354 /* Nope, not enough room. Insert in a new sibling instead. */
355 addSiblingNode(indexOfNode);
356 tryInsertAtNode(interval, latestBranch.size() - 1);
357 return;
358 }
359
360 /* Make sure the interval time range fits this node */
361 if (interval.getStartTime() < targetNode.getNodeStart()) {
362 /*
363 * No, this interval starts before the startTime of this node. We
364 * need to check recursively in parents if it can fit.
365 */
366 assert (indexOfNode >= 1);
367 tryInsertAtNode(interval, indexOfNode - 1);
368 return;
369 }
370
371 /*
372 * Ok, there is room, and the interval fits in this time slot. Let's add
373 * it.
374 */
375 targetNode.addInterval(interval);
376
377 /* Update treeEnd if needed */
378 if (interval.getEndTime() > this.treeEnd) {
379 this.treeEnd = interval.getEndTime();
380 }
a52fde77
AM
381 }
382
383 /**
384 * Method to add a sibling to any node in the latest branch. This will add
385 * children back down to the leaf level, if needed.
3b7f5abe 386 *
a52fde77
AM
387 * @param indexOfNode
388 * The index in latestBranch where we start adding
389 */
390 private void addSiblingNode(int indexOfNode) {
391 int i;
392 CoreNode newNode, prevNode;
393 long splitTime = treeEnd;
394
395 assert (indexOfNode < latestBranch.size());
396
397 /* Check if we need to add a new root node */
398 if (indexOfNode == 0) {
399 addNewRootNode();
400 return;
401 }
402
403 /* Check if we can indeed add a child to the target parent */
cb42195c 404 if (latestBranch.get(indexOfNode - 1).getNbChildren() == config.getMaxChildren()) {
a52fde77
AM
405 /* If not, add a branch starting one level higher instead */
406 addSiblingNode(indexOfNode - 1);
407 return;
408 }
409
410 /* Split off the new branch from the old one */
411 for (i = indexOfNode; i < latestBranch.size(); i++) {
412 latestBranch.get(i).closeThisNode(splitTime);
413 treeIO.writeNode(latestBranch.get(i));
414
415 prevNode = latestBranch.get(i - 1);
416 newNode = initNewCoreNode(prevNode.getSequenceNumber(),
417 splitTime + 1);
418 prevNode.linkNewChild(newNode);
419
420 latestBranch.set(i, newNode);
421 }
a52fde77
AM
422 }
423
424 /**
425 * Similar to the previous method, except here we rebuild a completely new
426 * latestBranch
427 */
428 private void addNewRootNode() {
429 int i, depth;
430 CoreNode oldRootNode, newRootNode, newNode, prevNode;
431 long splitTime = this.treeEnd;
432
cb42195c
AM
433 oldRootNode = latestBranch.get(0);
434 newRootNode = initNewCoreNode(-1, config.getTreeStart());
a52fde77
AM
435
436 /* Tell the old root node that it isn't root anymore */
437 oldRootNode.setParentSequenceNumber(newRootNode.getSequenceNumber());
438
439 /* Close off the whole current latestBranch */
440 for (i = 0; i < latestBranch.size(); i++) {
441 latestBranch.get(i).closeThisNode(splitTime);
442 treeIO.writeNode(latestBranch.get(i));
443 }
444
445 /* Link the new root to its first child (the previous root node) */
446 newRootNode.linkNewChild(oldRootNode);
447
448 /* Rebuild a new latestBranch */
449 depth = latestBranch.size();
cb42195c 450 latestBranch = new ArrayList<CoreNode>();
a52fde77
AM
451 latestBranch.add(newRootNode);
452 for (i = 1; i < depth + 1; i++) {
453 prevNode = latestBranch.get(i - 1);
454 newNode = initNewCoreNode(prevNode.getParentSequenceNumber(),
455 splitTime + 1);
456 prevNode.linkNewChild(newNode);
457 latestBranch.add(newNode);
458 }
459 }
460
461 /**
462 * Add a new empty node to the tree.
3b7f5abe 463 *
a52fde77
AM
464 * @param parentSeqNumber
465 * Sequence number of this node's parent
466 * @param startTime
467 * Start time of the new node
468 * @return The newly created node
469 */
470 private CoreNode initNewCoreNode(int parentSeqNumber, long startTime) {
ffd0aa67 471 CoreNode newNode = new CoreNode(config, this.nodeCount, parentSeqNumber,
a52fde77
AM
472 startTime);
473 this.nodeCount++;
474
475 /* Update the treeEnd if needed */
476 if (startTime >= this.treeEnd) {
477 this.treeEnd = startTime + 1;
478 }
479 return newNode;
480 }
481
482 /**
483 * Inner method to select the next child of the current node intersecting
484 * the given timestamp. Useful for moving down the tree following one
485 * branch.
3b7f5abe 486 *
a52fde77 487 * @param currentNode
d862bcb3 488 * The node on which the request is made
a52fde77 489 * @param t
d862bcb3 490 * The timestamp to choose which child is the next one
a52fde77 491 * @return The child node intersecting t
3b7f5abe
AM
492 * @throws ClosedChannelException
493 * If the file channel was closed while we were reading the tree
a52fde77 494 */
3b7f5abe 495 HTNode selectNextChild(CoreNode currentNode, long t) throws ClosedChannelException {
a52fde77
AM
496 assert (currentNode.getNbChildren() > 0);
497 int potentialNextSeqNb = currentNode.getSequenceNumber();
498
499 for (int i = 0; i < currentNode.getNbChildren(); i++) {
500 if (t >= currentNode.getChildStart(i)) {
501 potentialNextSeqNb = currentNode.getChild(i);
502 } else {
503 break;
504 }
505 }
d862bcb3 506
a52fde77
AM
507 /*
508 * Once we exit this loop, we should have found a children to follow. If
509 * we didn't, there's a problem.
510 */
511 assert (potentialNextSeqNb != currentNode.getSequenceNumber());
512
513 /*
514 * Since this code path is quite performance-critical, avoid iterating
515 * through the whole latestBranch array if we know for sure the next
516 * node has to be on disk
517 */
518 if (currentNode.isDone()) {
519 return treeIO.readNodeFromDisk(potentialNextSeqNb);
520 }
521 return treeIO.readNode(potentialNextSeqNb);
522 }
523
a52fde77 524 long getFileSize() {
cb42195c 525 return config.getStateFile().length();
a52fde77
AM
526 }
527
3b7f5abe
AM
528 // ------------------------------------------------------------------------
529 // Test/debugging methods
530 // ------------------------------------------------------------------------
a52fde77
AM
531
532 /* Only used for debugging, shouldn't be externalized */
533 @SuppressWarnings("nls")
534 boolean checkNodeIntegrity(HTNode zenode) {
ab604305 535
a52fde77
AM
536 HTNode otherNode;
537 CoreNode node;
ab604305 538 StringBuffer buf = new StringBuffer();
a52fde77
AM
539 boolean ret = true;
540
541 // FIXME /* Only testing Core Nodes for now */
542 if (!(zenode instanceof CoreNode)) {
543 return true;
544 }
545
546 node = (CoreNode) zenode;
547
3b7f5abe
AM
548 try {
549 /*
550 * Test that this node's start and end times match the start of the
551 * first child and the end of the last child, respectively
552 */
553 if (node.getNbChildren() > 0) {
554 otherNode = treeIO.readNode(node.getChild(0));
555 if (node.getNodeStart() != otherNode.getNodeStart()) {
556 buf.append("Start time of node (" + node.getNodeStart() + ") "
557 + "does not match start time of first child " + "("
558 + otherNode.getNodeStart() + "), " + "node #"
ab604305 559 + otherNode.getSequenceNumber() + ")\n");
a52fde77
AM
560 ret = false;
561 }
3b7f5abe
AM
562 if (node.isDone()) {
563 otherNode = treeIO.readNode(node.getLatestChild());
564 if (node.getNodeEnd() != otherNode.getNodeEnd()) {
565 buf.append("End time of node (" + node.getNodeEnd()
566 + ") does not match end time of last child ("
567 + otherNode.getNodeEnd() + ", node #"
568 + otherNode.getSequenceNumber() + ")\n");
569 ret = false;
570 }
571 }
a52fde77 572 }
a52fde77 573
3b7f5abe
AM
574 /*
575 * Test that the childStartTimes[] array matches the real nodes' start
576 * times
577 */
578 for (int i = 0; i < node.getNbChildren(); i++) {
579 otherNode = treeIO.readNode(node.getChild(i));
580 if (otherNode.getNodeStart() != node.getChildStart(i)) {
581 buf.append(" Expected start time of child node #"
582 + node.getChild(i) + ": " + node.getChildStart(i)
583 + "\n" + " Actual start time of node #"
584 + otherNode.getSequenceNumber() + ": "
585 + otherNode.getNodeStart() + "\n");
586 ret = false;
587 }
a52fde77 588 }
3b7f5abe
AM
589
590 } catch (ClosedChannelException e) {
591 e.printStackTrace();
a52fde77
AM
592 }
593
594 if (!ret) {
595 System.out.println("");
596 System.out.println("SHT: Integrity check failed for node #"
597 + node.getSequenceNumber() + ":");
ab604305 598 System.out.println(buf.toString());
a52fde77
AM
599 }
600 return ret;
601 }
602
603 void checkIntegrity() {
3b7f5abe
AM
604 try {
605 for (int i = 0; i < nodeCount; i++) {
606 checkNodeIntegrity(treeIO.readNode(i));
607 }
608 } catch (ClosedChannelException e) {
a52fde77
AM
609 }
610 }
611
612 /* Only used for debugging, shouldn't be externalized */
613 @SuppressWarnings("nls")
614 @Override
615 public String toString() {
616 return "Information on the current tree:\n\n" + "Blocksize: "
cb42195c
AM
617 + config.getBlockSize() + "\n" + "Max nb. of children per node: "
618 + config.getMaxChildren() + "\n" + "Number of nodes: " + nodeCount
a52fde77
AM
619 + "\n" + "Depth of the tree: " + latestBranch.size() + "\n"
620 + "Size of the treefile: " + this.getFileSize() + "\n"
621 + "Root node has sequence number: "
cb42195c 622 + latestBranch.get(0).getSequenceNumber() + "\n"
a52fde77 623 + "'Latest leaf' has sequence number: "
cb42195c 624 + latestBranch.get(latestBranch.size() - 1).getSequenceNumber();
a52fde77
AM
625 }
626
a52fde77
AM
627 /**
628 * Start at currentNode and print the contents of all its children, in
629 * pre-order. Give the root node in parameter to visit the whole tree, and
630 * have a nice overview.
631 */
d862bcb3 632 /* Only used for debugging, shouldn't be externalized */
a52fde77
AM
633 @SuppressWarnings("nls")
634 private void preOrderPrint(PrintWriter writer, boolean printIntervals,
d862bcb3 635 CoreNode currentNode, int curDepth) {
a52fde77
AM
636
637 writer.println(currentNode.toString());
638 if (printIntervals) {
639 currentNode.debugPrintIntervals(writer);
640 }
a52fde77 641
3b7f5abe 642 try {
d862bcb3
EB
643 for (int i = 0; i < currentNode.getNbChildren(); i++) {
644 HTNode nextNode = treeIO.readNode(currentNode.getChild(i));
3b7f5abe 645 assert (nextNode instanceof CoreNode); // TODO temporary
d862bcb3 646 for (int j = 0; j < curDepth; j++) {
3b7f5abe
AM
647 writer.print(" ");
648 }
649 writer.print("+-");
d862bcb3
EB
650 preOrderPrint(writer, printIntervals, (CoreNode) nextNode,
651 curDepth + 1);
a52fde77 652 }
3b7f5abe
AM
653 } catch (ClosedChannelException e) {
654 e.printStackTrace();
a52fde77 655 }
a52fde77
AM
656 }
657
658 /**
659 * Print out the full tree for debugging purposes
3b7f5abe 660 *
a52fde77
AM
661 * @param writer
662 * PrintWriter in which to write the output
663 * @param printIntervals
d862bcb3 664 * Flag to enable full output of the interval information
a52fde77
AM
665 */
666 void debugPrintFullTree(PrintWriter writer, boolean printIntervals) {
667 /* Only used for debugging, shouldn't be externalized */
d862bcb3
EB
668
669 this.preOrderPrint(writer, false, latestBranch.get(0), 0);
a52fde77
AM
670
671 if (printIntervals) {
672 writer.println("\nDetails of intervals:"); //$NON-NLS-1$
d862bcb3 673 this.preOrderPrint(writer, true, latestBranch.get(0), 0);
a52fde77
AM
674 }
675 writer.println('\n');
676 }
677
678}
This page took 0.07084 seconds and 5 git commands to generate.