ctf: Don't include all test traces in jar
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / StateSystem.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5 *
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
10 *
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.tmf.core.statesystem;
14
15 import java.io.File;
16 import java.io.IOException;
17 import java.io.PrintWriter;
18 import java.util.ArrayList;
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.concurrent.CountDownLatch;
22 import java.util.concurrent.TimeUnit;
23
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.NullProgressMonitor;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.linuxtools.internal.tmf.core.Activator;
28 import org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.IStateHistoryBackend;
29 import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
30 import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
31 import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
32 import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
33 import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
34 import org.eclipse.linuxtools.tmf.core.interval.TmfStateInterval;
35 import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystemBuilder;
36 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
37 import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue.Type;
38 import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
39
40 /**
41 * This is the core class of the Generic State System. It contains all the
42 * methods to build and query a state history. It's exposed externally through
43 * the IStateSystemQuerier and IStateSystemBuilder interfaces, depending if the
44 * user needs read-only access or read-write access.
45 *
46 * When building, DON'T FORGET to call .closeHistory() when you are done
47 * inserting intervals, or the storage backend will have no way of knowing it
48 * can close and write itself to disk, and its thread will keep running.
49 *
50 * @author alexmont
51 *
52 */
53 public class StateSystem implements ITmfStateSystemBuilder {
54
55 private final String ssid;
56
57 /* References to the inner structures */
58 private final AttributeTree attributeTree;
59 private final TransientState transState;
60 private final IStateHistoryBackend backend;
61
62 /* Latch tracking if the state history is done building or not */
63 private final CountDownLatch finishedLatch = new CountDownLatch(1);
64
65 private boolean buildCancelled = false;
66 private boolean isDisposed = false;
67
68 /**
69 * New-file constructor. For when you build a state system with a new file,
70 * or if the back-end does not require a file on disk.
71 *
72 * @param ssid
73 * The ID of this statesystem. It should be unique.
74 * @param backend
75 * Back-end plugin to use
76 */
77 public StateSystem(@NonNull String ssid, @NonNull IStateHistoryBackend backend) {
78 this.ssid = ssid;
79 this.backend = backend;
80 this.transState = new TransientState(backend);
81 this.attributeTree = new AttributeTree(this);
82 }
83
84 /**
85 * General constructor
86 *
87 * @param ssid
88 * The ID of this statesystem. It should be unique.
89 * @param backend
90 * The "state history storage" back-end to use.
91 * @param newFile
92 * Put true if this is a new history started from scratch. It is
93 * used to tell the state system where to get its attribute tree.
94 * @throws IOException
95 * If there was a problem creating the new history file
96 */
97 public StateSystem(@NonNull String ssid, @NonNull IStateHistoryBackend backend, boolean newFile)
98 throws IOException {
99 this.ssid = ssid;
100 this.backend = backend;
101 this.transState = new TransientState(backend);
102
103 if (newFile) {
104 attributeTree = new AttributeTree(this);
105 } else {
106 /* We're opening an existing file */
107 this.attributeTree = new AttributeTree(this, backend.supplyAttributeTreeReader());
108 transState.setInactive();
109 finishedLatch.countDown(); /* The history is already built */
110 }
111 }
112
113 @Override
114 public String getSSID() {
115 return ssid;
116 }
117
118 @Override
119 public boolean isCancelled() {
120 return buildCancelled;
121 }
122
123 @Override
124 public void waitUntilBuilt() {
125 try {
126 finishedLatch.await();
127 } catch (InterruptedException e) {
128 e.printStackTrace();
129 }
130 }
131
132 @Override
133 public boolean waitUntilBuilt(long timeout) {
134 boolean ret = false;
135 try {
136 ret = finishedLatch.await(timeout, TimeUnit.MILLISECONDS);
137 } catch (InterruptedException e) {
138 e.printStackTrace();
139 }
140 return ret;
141 }
142
143 @Override
144 public synchronized void dispose() {
145 isDisposed = true;
146 if (transState.isActive()) {
147 transState.setInactive();
148 buildCancelled = true;
149 }
150 backend.dispose();
151 }
152
153 //--------------------------------------------------------------------------
154 // General methods related to the attribute tree
155 //--------------------------------------------------------------------------
156
157 /**
158 * Get the attribute tree associated with this state system. This should be
159 * the only way of accessing it (and if subclasses want to point to a
160 * different attribute tree than their own, they should only need to
161 * override this).
162 *
163 * @return The attribute tree
164 */
165 public AttributeTree getAttributeTree() {
166 return attributeTree;
167 }
168
169 /**
170 * Method used by the attribute tree when creating new attributes, to keep
171 * the attribute count in the transient state in sync.
172 */
173 protected void addEmptyAttribute() {
174 transState.addEmptyEntry();
175 }
176
177 @Override
178 public int getNbAttributes() {
179 return getAttributeTree().getNbAttributes();
180 }
181
182 @Override
183 public String getAttributeName(int attributeQuark) {
184 return getAttributeTree().getAttributeName(attributeQuark);
185 }
186
187 @Override
188 public String getFullAttributePath(int attributeQuark) {
189 return getAttributeTree().getFullAttributeName(attributeQuark);
190 }
191
192 //--------------------------------------------------------------------------
193 // Methods related to the storage backend
194 //--------------------------------------------------------------------------
195
196 @Override
197 public long getStartTime() {
198 return backend.getStartTime();
199 }
200
201 @Override
202 public long getCurrentEndTime() {
203 return backend.getEndTime();
204 }
205
206 @Override
207 public void closeHistory(long endTime) throws TimeRangeException {
208 File attributeTreeFile;
209 long attributeTreeFilePos;
210 long realEndTime = endTime;
211
212 if (realEndTime < backend.getEndTime()) {
213 /*
214 * This can happen (empty nodes pushing the border further, etc.)
215 * but shouldn't be too big of a deal.
216 */
217 realEndTime = backend.getEndTime();
218 }
219 transState.closeTransientState(realEndTime);
220 backend.finishedBuilding(realEndTime);
221
222 attributeTreeFile = backend.supplyAttributeTreeWriterFile();
223 attributeTreeFilePos = backend.supplyAttributeTreeWriterFilePosition();
224 if (attributeTreeFile != null) {
225 /*
226 * If null was returned, we simply won't save the attribute tree,
227 * too bad!
228 */
229 getAttributeTree().writeSelf(attributeTreeFile, attributeTreeFilePos);
230 }
231 finishedLatch.countDown(); /* Mark the history as finished building */
232 }
233
234 //--------------------------------------------------------------------------
235 // Quark-retrieving methods
236 //--------------------------------------------------------------------------
237
238 @Override
239 public int getQuarkAbsolute(String... attribute)
240 throws AttributeNotFoundException {
241 return getAttributeTree().getQuarkDontAdd(-1, attribute);
242 }
243
244 @Override
245 public int getQuarkAbsoluteAndAdd(String... attribute) {
246 return getAttributeTree().getQuarkAndAdd(-1, attribute);
247 }
248
249 @Override
250 public int getQuarkRelative(int startingNodeQuark, String... subPath)
251 throws AttributeNotFoundException {
252 return getAttributeTree().getQuarkDontAdd(startingNodeQuark, subPath);
253 }
254
255 @Override
256 public int getQuarkRelativeAndAdd(int startingNodeQuark, String... subPath) {
257 return getAttributeTree().getQuarkAndAdd(startingNodeQuark, subPath);
258 }
259
260 @Override
261 public List<Integer> getSubAttributes(int quark, boolean recursive)
262 throws AttributeNotFoundException {
263 return getAttributeTree().getSubAttributes(quark, recursive);
264 }
265
266 @Override
267 public List<Integer> getSubAttributes(int quark, boolean recursive, String pattern)
268 throws AttributeNotFoundException {
269 List<Integer> all = getSubAttributes(quark, recursive);
270 List<Integer> ret = new LinkedList<>();
271 for (Integer attQuark : all) {
272 String name = getAttributeName(attQuark.intValue());
273 if (name.matches(pattern)) {
274 ret.add(attQuark);
275 }
276 }
277 return ret;
278 }
279
280 @Override
281 public int getParentAttributeQuark(int quark) {
282 return getAttributeTree().getParentAttributeQuark(quark);
283 }
284
285 @Override
286 public List<Integer> getQuarks(String... pattern) {
287 List<Integer> quarks = new LinkedList<>();
288 List<String> prefix = new LinkedList<>();
289 List<String> suffix = new LinkedList<>();
290 boolean split = false;
291 String[] prefixStr;
292 String[] suffixStr;
293 List<Integer> directChildren;
294 int startingAttribute;
295
296 /* Fill the "prefix" and "suffix" parts of the pattern around the '*' */
297 for (String entry : pattern) {
298 if (entry.equals("*")) { //$NON-NLS-1$
299 if (split) {
300 /*
301 * Split was already true? This means there was more than
302 * one wildcard. This is not supported, return an empty
303 * list.
304 */
305 return quarks;
306 }
307 split = true;
308 continue;
309 }
310
311 if (split) {
312 suffix.add(entry);
313 } else {
314 prefix.add(entry);
315 }
316 }
317 prefixStr = prefix.toArray(new String[prefix.size()]);
318 suffixStr = suffix.toArray(new String[suffix.size()]);
319
320 /*
321 * If there was no wildcard, we'll only return the one matching
322 * attribute, if there is one.
323 */
324 if (!split) {
325 int quark;
326 try {
327 quark = getQuarkAbsolute(prefixStr);
328 } catch (AttributeNotFoundException e) {
329 /* It's fine, we'll just return the empty List */
330 return quarks;
331 }
332 quarks.add(quark);
333 return quarks;
334 }
335
336 try {
337 if (prefix.size() == 0) {
338 /*
339 * If 'prefix' is empty, this means the wildcard was the first
340 * element. Look for the root node's sub-attributes.
341 */
342 startingAttribute = -1;
343 } else {
344 startingAttribute = getQuarkAbsolute(prefixStr);
345 }
346 directChildren = getSubAttributes(startingAttribute, false);
347 } catch (AttributeNotFoundException e) {
348 /* That attribute path did not exist, return the empty array */
349 return quarks;
350 }
351
352 /*
353 * Iterate of all the sub-attributes, and only keep those who match the
354 * 'suffix' part of the initial pattern.
355 */
356 for (int childQuark : directChildren) {
357 int matchingQuark;
358 try {
359 matchingQuark = getQuarkRelative(childQuark, suffixStr);
360 } catch (AttributeNotFoundException e) {
361 continue;
362 }
363 quarks.add(matchingQuark);
364 }
365
366 return quarks;
367 }
368
369 //--------------------------------------------------------------------------
370 // Methods related to insertions in the history
371 //--------------------------------------------------------------------------
372
373 @Override
374 public void modifyAttribute(long t, ITmfStateValue value, int attributeQuark)
375 throws TimeRangeException, AttributeNotFoundException,
376 StateValueTypeException {
377 transState.processStateChange(t, value, attributeQuark);
378 }
379
380 @Override
381 public void incrementAttribute(long t, int attributeQuark)
382 throws StateValueTypeException, TimeRangeException,
383 AttributeNotFoundException {
384 ITmfStateValue stateValue = queryOngoingState(attributeQuark);
385 int prevValue = 0;
386 /* if the attribute was previously null, start counting at 0 */
387 if (!stateValue.isNull()) {
388 prevValue = stateValue.unboxInt();
389 }
390 modifyAttribute(t, TmfStateValue.newValueInt(prevValue + 1),
391 attributeQuark);
392 }
393
394 @Override
395 public void pushAttribute(long t, ITmfStateValue value, int attributeQuark)
396 throws TimeRangeException, AttributeNotFoundException,
397 StateValueTypeException {
398 int stackDepth;
399 int subAttributeQuark;
400 ITmfStateValue previousSV = transState.getOngoingStateValue(attributeQuark);
401
402 if (previousSV.isNull()) {
403 /*
404 * If the StateValue was null, this means this is the first time we
405 * use this attribute. Leave stackDepth at 0.
406 */
407 stackDepth = 0;
408 } else if (previousSV.getType() == Type.INTEGER) {
409 /* Previous value was an integer, all is good, use it */
410 stackDepth = previousSV.unboxInt();
411 } else {
412 /* Previous state of this attribute was another type? Not good! */
413 throw new StateValueTypeException();
414 }
415
416 if (stackDepth >= 100000) {
417 /*
418 * Limit stackDepth to 100000, to avoid having Attribute Trees grow
419 * out of control due to buggy insertions
420 */
421 String message = "Stack limit reached, not pushing"; //$NON-NLS-1$
422 throw new AttributeNotFoundException(message);
423 }
424
425 stackDepth++;
426 subAttributeQuark = getQuarkRelativeAndAdd(attributeQuark, String.valueOf(stackDepth));
427
428 modifyAttribute(t, TmfStateValue.newValueInt(stackDepth), attributeQuark);
429 modifyAttribute(t, value, subAttributeQuark);
430 }
431
432 @Override
433 public ITmfStateValue popAttribute(long t, int attributeQuark)
434 throws AttributeNotFoundException, TimeRangeException,
435 StateValueTypeException {
436 /* These are the state values of the stack-attribute itself */
437 ITmfStateValue previousSV = queryOngoingState(attributeQuark);
438
439 if (previousSV.isNull()) {
440 /*
441 * Trying to pop an empty stack. This often happens at the start of
442 * traces, for example when we see a syscall_exit, without having
443 * the corresponding syscall_entry in the trace. Just ignore
444 * silently.
445 */
446 return null;
447 }
448 if (previousSV.getType() != Type.INTEGER) {
449 /*
450 * The existing value was not an integer (which is expected for
451 * stack tops), this doesn't look like a valid stack attribute.
452 */
453 throw new StateValueTypeException();
454 }
455
456 int stackDepth = previousSV.unboxInt();
457
458 if (stackDepth <= 0) {
459 /* This on the other hand should not happen... */
460 String message = "A top-level stack attribute cannot " + //$NON-NLS-1$
461 "have a value of 0 or less."; //$NON-NLS-1$
462 throw new StateValueTypeException(message);
463 }
464
465 /* The attribute should already exist at this point */
466 int subAttributeQuark = getQuarkRelative(attributeQuark, String.valueOf(stackDepth));
467 ITmfStateValue poppedValue = queryOngoingState(subAttributeQuark);
468
469 /* Update the state value of the stack-attribute */
470 ITmfStateValue nextSV;
471 if (--stackDepth == 0) {
472 /* Store a null state value */
473 nextSV = TmfStateValue.nullValue();
474 } else {
475 nextSV = TmfStateValue.newValueInt(stackDepth);
476 }
477 modifyAttribute(t, nextSV, attributeQuark);
478
479 /* Delete the sub-attribute that contained the user's state value */
480 removeAttribute(t, subAttributeQuark);
481
482 return poppedValue;
483 }
484
485 @Override
486 public void removeAttribute(long t, int attributeQuark)
487 throws TimeRangeException, AttributeNotFoundException {
488 assert (attributeQuark >= 0);
489 List<Integer> childAttributes;
490
491 /*
492 * "Nullify our children first, recursively. We pass 'false' because we
493 * handle the recursion ourselves.
494 */
495 childAttributes = getSubAttributes(attributeQuark, false);
496 for (int childNodeQuark : childAttributes) {
497 assert (attributeQuark != childNodeQuark);
498 removeAttribute(t, childNodeQuark);
499 }
500 /* Nullify ourselves */
501 try {
502 transState.processStateChange(t, TmfStateValue.nullValue(),
503 attributeQuark);
504 } catch (StateValueTypeException e) {
505 /*
506 * Will not happen since we're inserting null values only, but poor
507 * compiler has no way of knowing this...
508 */
509 throw new IllegalStateException(e);
510 }
511 }
512
513 //--------------------------------------------------------------------------
514 // "Current" query/update methods
515 //--------------------------------------------------------------------------
516
517 @Override
518 public ITmfStateValue queryOngoingState(int attributeQuark)
519 throws AttributeNotFoundException {
520 return transState.getOngoingStateValue(attributeQuark);
521 }
522
523 @Override
524 public long getOngoingStartTime(int attribute)
525 throws AttributeNotFoundException {
526 return transState.getOngoingStartTime(attribute);
527 }
528
529 @Override
530 public void updateOngoingState(ITmfStateValue newValue, int attributeQuark)
531 throws AttributeNotFoundException {
532 transState.changeOngoingStateValue(attributeQuark, newValue);
533 }
534
535 /**
536 * Modify the whole "ongoing state" (state values + start times). This can
537 * be used when "seeking" a state system to a different point in the trace
538 * (and restoring the known stateInfo at this location). Use with care!
539 *
540 * @param newStateIntervals
541 * The new List of state values to use as ongoing state info
542 */
543 protected void replaceOngoingState(List<ITmfStateInterval> newStateIntervals) {
544 transState.replaceOngoingState(newStateIntervals);
545 }
546
547 //--------------------------------------------------------------------------
548 // Regular query methods (sent to the back-end)
549 //--------------------------------------------------------------------------
550
551 @Override
552 public synchronized List<ITmfStateInterval> queryFullState(long t)
553 throws TimeRangeException, StateSystemDisposedException {
554 if (isDisposed) {
555 throw new StateSystemDisposedException();
556 }
557
558 List<ITmfStateInterval> stateInfo = new ArrayList<>(getNbAttributes());
559
560 /* Bring the size of the array to the current number of attributes */
561 for (int i = 0; i < getNbAttributes(); i++) {
562 stateInfo.add(null);
563 }
564
565 /* Query the storage backend */
566 backend.doQuery(stateInfo, t);
567
568 /*
569 * If we are currently building the history, also query the "ongoing"
570 * states for stuff that might not yet be written to the history.
571 */
572 if (transState.isActive()) {
573 transState.doQuery(stateInfo, t);
574 }
575
576 /*
577 * We should have previously inserted an interval for every attribute.
578 * If we do happen do see a 'null' object here, just replace it with a a
579 * dummy internal with a null value, to avoid NPE's further up.
580 */
581 for (int i = 0; i < stateInfo.size(); i++) {
582 if (stateInfo.get(i) == null) {
583 stateInfo.set(i, new TmfStateInterval(t, t, i, TmfStateValue.nullValue()));
584 }
585 }
586 return stateInfo;
587 }
588
589 @Override
590 public ITmfStateInterval querySingleState(long t, int attributeQuark)
591 throws AttributeNotFoundException, TimeRangeException,
592 StateSystemDisposedException {
593 if (isDisposed) {
594 throw new StateSystemDisposedException();
595 }
596
597 ITmfStateInterval ret = transState.getIntervalAt(t, attributeQuark);
598 if (ret == null) {
599 /*
600 * The transient state did not have the information, let's look into
601 * the backend next.
602 */
603 ret = backend.doSingularQuery(t, attributeQuark);
604 }
605
606 /*
607 * Return a fake interval if we could not find anything in the history.
608 * We do NOT want to return 'null' here.
609 */
610 if (ret == null) {
611 return new TmfStateInterval(t, this.getCurrentEndTime(),
612 attributeQuark, TmfStateValue.nullValue());
613 }
614 return ret;
615 }
616
617 @Override
618 public ITmfStateInterval querySingleStackTop(long t, int stackAttributeQuark)
619 throws StateValueTypeException, AttributeNotFoundException,
620 TimeRangeException, StateSystemDisposedException {
621 ITmfStateValue curStackStateValue = querySingleState(t, stackAttributeQuark).getStateValue();
622
623 if (curStackStateValue.isNull()) {
624 /* There is nothing stored in this stack at this moment */
625 return null;
626 }
627 int curStackDepth = curStackStateValue.unboxInt();
628 if (curStackDepth <= 0) {
629 /*
630 * This attribute is an integer attribute, but it doesn't seem like
631 * it's used as a stack-attribute...
632 */
633 throw new StateValueTypeException();
634 }
635
636 int subAttribQuark = getQuarkRelative(stackAttributeQuark, String.valueOf(curStackDepth));
637 return querySingleState(t, subAttribQuark);
638 }
639
640 @Override
641 public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
642 long t1, long t2) throws TimeRangeException,
643 AttributeNotFoundException, StateSystemDisposedException {
644 if (isDisposed) {
645 throw new StateSystemDisposedException();
646 }
647
648 List<ITmfStateInterval> intervals;
649 ITmfStateInterval currentInterval;
650 long ts, tEnd;
651
652 /* Make sure the time range makes sense */
653 if (t2 < t1) {
654 throw new TimeRangeException();
655 }
656
657 /* Set the actual, valid end time of the range query */
658 if (t2 > this.getCurrentEndTime()) {
659 tEnd = this.getCurrentEndTime();
660 } else {
661 tEnd = t2;
662 }
663
664 /* Get the initial state at time T1 */
665 intervals = new ArrayList<>();
666 currentInterval = querySingleState(t1, attributeQuark);
667 intervals.add(currentInterval);
668
669 /* Get the following state changes */
670 ts = currentInterval.getEndTime();
671 while (ts != -1 && ts < tEnd) {
672 ts++; /* To "jump over" to the next state in the history */
673 currentInterval = querySingleState(ts, attributeQuark);
674 intervals.add(currentInterval);
675 ts = currentInterval.getEndTime();
676 }
677 return intervals;
678 }
679
680 @Override
681 public List<ITmfStateInterval> queryHistoryRange(int attributeQuark,
682 long t1, long t2, long resolution, IProgressMonitor monitor)
683 throws TimeRangeException, AttributeNotFoundException,
684 StateSystemDisposedException {
685 if (isDisposed) {
686 throw new StateSystemDisposedException();
687 }
688
689 List<ITmfStateInterval> intervals = new LinkedList<>();
690 ITmfStateInterval currentInterval = null;
691 long ts, tEnd;
692
693 IProgressMonitor mon = monitor;
694 if (mon == null) {
695 mon = new NullProgressMonitor();
696 }
697
698 /* Make sure the time range makes sense */
699 if (t2 < t1 || resolution <= 0) {
700 throw new TimeRangeException();
701 }
702
703 /* Set the actual, valid end time of the range query */
704 if (t2 > this.getCurrentEndTime()) {
705 tEnd = this.getCurrentEndTime();
706 } else {
707 tEnd = t2;
708 }
709
710 /*
711 * Iterate over the "resolution points". We skip unneeded queries in the
712 * case the current interval is longer than the resolution.
713 */
714 for (ts = t1; ts <= tEnd;
715 ts += ((currentInterval.getEndTime() - ts) / resolution + 1) * resolution) {
716 if (mon.isCanceled()) {
717 return intervals;
718 }
719 currentInterval = querySingleState(ts, attributeQuark);
720 intervals.add(currentInterval);
721 }
722
723 /* Add the interval at t2, if it wasn't included already. */
724 if (currentInterval != null && currentInterval.getEndTime() < tEnd) {
725 currentInterval = querySingleState(tEnd, attributeQuark);
726 intervals.add(currentInterval);
727 }
728 return intervals;
729 }
730
731 //--------------------------------------------------------------------------
732 // Debug methods
733 //--------------------------------------------------------------------------
734
735 static void logMissingInterval(int attribute, long timestamp) {
736 Activator.logInfo("No data found in history for attribute " + //$NON-NLS-1$
737 attribute + " at time " + timestamp + //$NON-NLS-1$
738 ", returning dummy interval"); //$NON-NLS-1$
739 }
740
741 /**
742 * Print out the contents of the inner structures.
743 *
744 * @param writer
745 * The PrintWriter in which to print the output
746 */
747 public void debugPrint(PrintWriter writer) {
748 getAttributeTree().debugPrint(writer);
749 transState.debugPrint(writer);
750 backend.debugPrint(writer);
751 }
752
753 }
This page took 0.049708 seconds and 5 git commands to generate.