aboutsummaryrefslogtreecommitdiffstats
path: root/storage/src/tests/visiting/memory_bounded_trace_test.cpp
blob: 59e28bb43fce84fd2deb435441f01db10021fff6 (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/storage/visiting/memory_bounded_trace.h>
#include <vespa/vespalib/gtest/gtest.h>

using namespace ::testing;

namespace storage {

constexpr vespalib::system_time epoch;

TEST(MemoryBoundedTraceTest, no_memory_reported_used_when_empty) {
    MemoryBoundedTrace trace(100);
    EXPECT_EQ(0, trace.getApproxMemoryUsed());
}

TEST(MemoryBoundedTraceTest, memory_used_is_string_length_for_leaf_node) {
    MemoryBoundedTrace trace(100);
    EXPECT_TRUE(trace.add(mbus::TraceNode("hello world", epoch)));
    EXPECT_EQ(11, trace.getApproxMemoryUsed());
}

TEST(MemoryBoundedTraceTest, memory_used_is_accumulated_recursively_for_non_leaf_nodes) {
    MemoryBoundedTrace trace(100);
    mbus::TraceNode innerNode;
    innerNode.addChild("hello world");
    innerNode.addChild("goodbye moon");
    EXPECT_TRUE(trace.add(innerNode));
    EXPECT_EQ(23, trace.getApproxMemoryUsed());
}

TEST(MemoryBoundedTraceTest, trace_nodes_can_be_moved_and_implicitly_cleared) {
    MemoryBoundedTrace trace(100);
    EXPECT_TRUE(trace.add(mbus::TraceNode("hello world", epoch)));
    mbus::Trace target;
    trace.moveTraceTo(target);
    EXPECT_EQ(1, target.getNumChildren());
    EXPECT_EQ(0, trace.getApproxMemoryUsed());
    
    mbus::Trace emptinessCheck;
    trace.moveTraceTo(emptinessCheck);
    EXPECT_EQ(0, emptinessCheck.getNumChildren());
}

/**
 * We want trace subtrees to be strictly ordered so that the message about
 * omitted traces will remain soundly as the last ordered node. There is no
 * particular performance reason for not having strict mode enabled to the
 * best of my knowledge, since the internal backing data structure is an
 * ordered vector anyhow.
 */
TEST(MemoryBoundedTraceTest, moved_trace_tree_is_marked_as_strict) {
    MemoryBoundedTrace trace(100);
    EXPECT_TRUE(trace.add(mbus::TraceNode("hello world", epoch)));
    mbus::Trace target;
    trace.moveTraceTo(target);
    EXPECT_EQ(1, target.getNumChildren());
    EXPECT_TRUE(target.getChild(0).isStrict());
}

TEST(MemoryBoundedTraceTest, can_not_add_more_nodes_when_memory_used_exceeds_upper_bound) {
    // Note: we allow one complete node tree to exceed the bounds, but as soon
    // as the bound is exceeded no further nodes can be added.
    MemoryBoundedTrace trace(10);
    EXPECT_TRUE(trace.add(mbus::TraceNode("hello world", epoch)));
    EXPECT_EQ(11, trace.getApproxMemoryUsed());

    EXPECT_FALSE(trace.add(mbus::TraceNode("the quick red fox runs across "
                                           "the freeway", epoch)));
    EXPECT_EQ(11, trace.getApproxMemoryUsed());

    mbus::Trace target;
    trace.moveTraceTo(target);
    // Twice nested node (root -> added trace tree -> leaf with txt).
    EXPECT_EQ(1, target.getNumChildren());
    EXPECT_GE(target.getChild(0).getNumChildren(), 1);
    EXPECT_EQ("hello world", target.getChild(0).getChild(0).getNote());
}

TEST(MemoryBoundedTraceTest, moved_tree_includes_stats_node_when_nodes_omitted) {
    MemoryBoundedTrace trace(5);
    EXPECT_TRUE(trace.add(mbus::TraceNode("abcdef", epoch)));
    EXPECT_FALSE(trace.add(mbus::TraceNode("ghijkjlmn", epoch)));

    mbus::Trace target;
    trace.moveTraceTo(target);
    EXPECT_EQ(1, target.getNumChildren());
    EXPECT_EQ(2, target.getChild(0).getNumChildren());
    vespalib::string expected("Trace too large; omitted 1 subsequent trace "
                              "trees containing a total of 9 bytes");
    EXPECT_EQ(expected, target.getChild(0).getChild(1).getNote());
}

} // storage