aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/trace/tracenode.h
blob: 2877bf280476735f2b18bf2361ee383f478abf17 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include <vespa/vespalib/stllike/string.h>
#include <vespa/vespalib/util/time.h>
#include <vector>

namespace vespalib {

struct TraceVisitor;

/**
 * This class contains the actual trace information of a {@link Trace} object.
 * A trace node can be encoded to, and decoded from a string representation to
 * allow transport across the network. Each node contains a list of children, a
 * strictness flag and an optional note. The child list is what forms the trace
 * tree, the strictness flag dictates whether or not the ordering of the
 * children is important, and the note is the actual traced data.
 *
 * The most important feature to notice is the {@link #normalize()} method that
 * will compact, sort and 'rootify' the trace tree so that trees become
 * well-formed (and can be compared for equality).
 */
class TraceNode {
private:
    string                 _note;
    std::vector<TraceNode> _children;
    TraceNode             *_parent;
    system_time            _timestamp;
    bool                   _strict;
    bool                   _hasNote;

public:
    /**
     * Create an empty trace tree.
     */
    TraceNode() noexcept;

    /**
     * Create a leaf node with the given note and timestamp.
     * @param note The note for this node.
     * @param timestamp The timestamp to give to node.
     */
    explicit TraceNode(const string &note, system_time timestamp);

    /**
     * Create a leaf node with no note and a time stamp.
     * @param timestamp The timestamp to give to node.
     */
    explicit TraceNode(system_time timestamp) noexcept;

    TraceNode & operator =(const TraceNode &);
    TraceNode(TraceNode &&) noexcept;
    TraceNode & operator =(TraceNode &&) noexcept;
    ~TraceNode();

    /**
     * Create a trace tree which is a copy of another.
     *
     * @param rhs The tree to copy.
     */
    TraceNode(const TraceNode &rhs);

    /**
     * Swap the internals of this tree with another.
     *
     * @param other The tree to swap internals with.
     * @return This, to allow chaining.
     */
    TraceNode &swap(TraceNode &t);

    /**
     * Remove all trace information from this tree.
     *
     * @return This, to allow chaining.
     */
    TraceNode &clear();

    /**
     * Sort non-strict children recursively down the tree.
     *
     * @return This, to allow chaining.
     */
    TraceNode &sort();

    /**
     * Compact this tree. This will reduce the height of this tree as much as
     * possible without removing information stored in it.
     *
     * @return This, to allow chaining.
     */
    TraceNode &compact();

    /**
     * Normalize this tree. This will transform all equivalent trees into the
     * same form. Note that this will also perform an implicit compaction of
     * the tree.
     *
     * @return This, to allow chaining.
     */
    TraceNode &normalize();

    /**
     * Check whether or not this is a root node.
     *
     * @return True if this has no parent.
     */
    bool isRoot() const { return _parent == nullptr; }

    /**
     * Check whether or not this is a leaf node.
     *
     * @return True if this has no children.
     */
    bool isLeaf() const { return _children.empty(); }

    /**
     * Check whether or not this node is empty, i.e. it has no note and no
     * children.
     *
     * @return True if this node is empty.
     */
    bool isEmpty() const { return !_hasNote && _children.empty(); }

    /**
     * Check whether or not the children of this node are strictly ordered.
     *
     * @return True if this node is strict.
     */
    bool isStrict() const { return _strict; }

    /**
     * Sets whether or not the children of this node are strictly ordered.
     *
     * @param strict True to order children strictly.
     * @return This, to allow chaining.
     */
    TraceNode &setStrict(bool strict) { _strict = strict; return *this; }

    /**
     * Returns whether or not a note is assigned to this node.
     *
     * @return True if a note is assigned.
     */
    bool hasNote() const { return _hasNote; }

    /**
     * Returns the note assigned to this node.
     *
     * @return The note.
     */
    const string & getNote() const { return _note; }

    /**
     * Returns the timestamp assigned to this node.
     *
     * @return The timestamp.
     */
    system_time getTimestamp() const { return _timestamp; }


    /**
     * Returns the number of child nodes of this.
     *
     * @return The number of children.
     */
    uint32_t getNumChildren() const { return _children.size(); }

    /**
     * Returns the child trace node at the given index.
     *
     * @param i The index of the child to return.
     * @return The child at the given index.
     */
    const TraceNode &getChild(uint32_t i) const {  return _children[i]; }

    /**
     * Convenience method to add a child node containing a note to this.
     * A timestamp of 0 will be assigned to the new node.
     *
     * @param note The note to assign to the child.
     * @return This, to allow chaining.
     */
    TraceNode &addChild(const string &note);

    /**
     * Convenience method to add a child node containing a note to this and a timestamp.
     *
     * @param note The note to assign to the child.
     * @param timestamp The timestamp to give this child.
     * @return This, to allow chaining.
     */
    TraceNode &addChild(const string &note, system_time timestamp);

    /**
     * Adds a child node to this.
     *
     * @param child The child to add.
     * @return This, to allow chaining.
     */
    TraceNode &addChild(TraceNode child);

    /**
     * Adds a list of child nodes to this.
     *
     * @param children The children to add.
     * @return This, to allow chaining.
     */
    TraceNode &addChildren(std::vector<TraceNode> children);

    /**
     * Generate a non-parseable, human-readable string representation of
     * this trace node.
     *
     * @return generated string
     * @param limit soft cap for maximum size of generated string
     **/
    string toString(size_t limit = -1) const;

    /**
     * Writes a non-parseable, human-readable string representation of
     * this trace node to the given string.
     *
     * @return false if string was capped, true otherwise
     * @param dst output string
     * @param indent number of spaces to be used for indent
     * @param limit soft cap for maximum size of generated string
     **/
    bool writeString(string &dst, size_t indent, size_t limit) const;

    /**
     * Returns a parseable (using {@link #decode(String)}) string
     * representation of this trace node.
     *
     * @return A string representation of this tree.
     */
    string encode() const;

    /**
     * Build a trace tree from the given string representation (possibly
     * encoded using {@link #encode()}).
     *
     * @param str The string to parse.
     * @return The corresponding trace tree, or an empty node if parsing failed.
     */
    static TraceNode decode(const string &str);

    /**
     * Visits this TraceNode and all of its descendants in depth-first, prefix order.
     *
     * @param visitor The visitor to accept.
     * @return The visitor parameter.
     */
    TraceVisitor & accept(TraceVisitor & visitor) const;

    size_t computeMemoryUsage() const;

};

} // namespace vespalib