YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/memcmpable_varint-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include <glog/logging.h>
34
#include <glog/stl_logging.h>
35
#include <gtest/gtest.h>
36
37
#include "yb/util/hexdump.h"
38
#include "yb/util/memcmpable_varint.h"
39
#include "yb/util/random.h"
40
#include "yb/util/stopwatch.h" // Required in NDEBUG mode
41
#include "yb/util/test_macros.h"
42
#include "yb/util/test_util.h"
43
44
namespace yb {
45
46
class TestMemcmpableVarint : public YBTest {
47
 protected:
48
3
  TestMemcmpableVarint() : random_(SeedRandom()) {}
49
50
  // Random number generator that generates different length integers
51
  // with equal probability -- i.e it is equally as likely to generate
52
  // a number with 8 bits as it is to generate one with 64 bits.
53
  // This is useful for testing varint implementations, where a uniform
54
  // random is skewed towards generating longer integers.
55
4.00k
  uint64_t Rand64WithRandomBitLength() {
56
4.00k
    return random_.Next64() >> random_.Uniform(64);
57
4.00k
  }
58
59
  Random random_;
60
};
61
62
200k
static void DoRoundTripTest(uint64_t to_encode) {
63
200k
  static faststring buf;
64
200k
  buf.clear();
65
200k
  PutMemcmpableVarint64(&buf, to_encode);
66
67
200k
  uint64_t decoded;
68
200k
  Slice slice(buf);
69
200k
  auto status = GetMemcmpableVarint64(&slice, &decoded);
70
200k
  ASSERT_OK(status);
71
200k
  ASSERT_EQ(to_encode, decoded);
72
200k
  ASSERT_TRUE(slice.empty());
73
200k
}
74
75
76
1
TEST_F(TestMemcmpableVarint, TestRoundTrip) {
77
  // Test the first 100K integers
78
  // (exercises the special cases for <= 67823 in the code)
79
100k
  for (int i = 0; i < 100000; i++) {
80
100k
    DoRoundTripTest(i);
81
100k
  }
82
83
  // Test a bunch of random integers (which are likely to be many bytes)
84
100k
  for (int i = 0; i < 100000; i++) {
85
100k
    DoRoundTripTest(random_.Next64());
86
100k
  }
87
1
}
88
89
90
// Test that a composite key can be made up of multiple memcmpable
91
// varints strung together, and that the resulting key compares the
92
// same as the original pair of integers (i.e left-to-right).
93
1
TEST_F(TestMemcmpableVarint, TestCompositeKeys) {
94
1
  faststring buf1;
95
1
  faststring buf2;
96
97
1
  const int n_trials = 1000;
98
99
1.00k
  for (int i = 0; i < n_trials; i++) {
100
1.00k
    buf1.clear();
101
1.00k
    buf2.clear();
102
103
1.00k
    pair<uint64_t, uint64_t> p1 =
104
1.00k
      make_pair(Rand64WithRandomBitLength(), Rand64WithRandomBitLength());
105
1.00k
    PutMemcmpableVarint64(&buf1, p1.first);
106
1.00k
    PutMemcmpableVarint64(&buf1, p1.second);
107
108
1.00k
    pair<uint64_t, uint64_t> p2 =
109
1.00k
      make_pair(Rand64WithRandomBitLength(), Rand64WithRandomBitLength());
110
1.00k
    PutMemcmpableVarint64(&buf2, p2.first);
111
1.00k
    PutMemcmpableVarint64(&buf2, p2.second);
112
113
1.00k
    SCOPED_TRACE(testing::Message() << p1 << "\n" << HexDump(Slice(buf1))
114
1.00k
                 << "  vs\n" << p2 << "\n" << HexDump(Slice(buf2)));
115
1.00k
    if (p1 < p2) {
116
522
      ASSERT_LT(Slice(buf1).compare(Slice(buf2)), 0);
117
478
    } else if (p1 > p2) {
118
478
      ASSERT_GT(Slice(buf1).compare(Slice(buf2)), 0);
119
0
    } else {
120
0
      ASSERT_EQ(Slice(buf1).compare(Slice(buf2)), 0);
121
0
    }
122
1.00k
  }
123
1
}
124
125
// Similar to the above test, but instead of being randomized, specifically
126
// tests "interesting" values -- i.e values around the boundaries of where
127
// the encoding changes its number of bytes.
128
1
TEST_F(TestMemcmpableVarint, TestInterestingCompositeKeys) {
129
1
  vector<uint64_t> interesting_values = { 0, 1, 240, // 1 byte
130
1
                                          241, 2000, 2287, // 2 bytes
131
1
                                          2288, 40000, 67823, // 3 bytes
132
1
                                          67824, 1ULL << 23, (1ULL << 24) - 1, // 4 bytes
133
1
                                          1ULL << 24, 1ULL << 30, (1ULL << 32) - 1 }; // 5 bytes
134
135
1
  faststring buf1;
136
1
  faststring buf2;
137
138
15
  for (uint64_t v1 : interesting_values) {
139
225
    for (uint64_t v2 : interesting_values) {
140
225
      buf1.clear();
141
225
      pair<uint64_t, uint64_t> p1 = make_pair(v1, v2);
142
225
      PutMemcmpableVarint64(&buf1, p1.first);
143
225
      PutMemcmpableVarint64(&buf1, p1.second);
144
145
3.37k
      for (uint64_t v3 : interesting_values) {
146
50.6k
        for (uint64_t v4 : interesting_values) {
147
50.6k
          buf2.clear();
148
50.6k
          pair<uint64_t, uint64_t> p2 = make_pair(v3, v4);
149
50.6k
          PutMemcmpableVarint64(&buf2, p2.first);
150
50.6k
          PutMemcmpableVarint64(&buf2, p2.second);
151
152
50.6k
          SCOPED_TRACE(testing::Message() << p1 << "\n" << HexDump(Slice(buf1))
153
50.6k
                       << "  vs\n" << p2 << "\n" << HexDump(Slice(buf2)));
154
50.6k
          if (p1 < p2) {
155
25.2k
            ASSERT_LT(Slice(buf1).compare(Slice(buf2)), 0);
156
25.4k
          } else if (p1 > p2) {
157
25.2k
            ASSERT_GT(Slice(buf1).compare(Slice(buf2)), 0);
158
225
          } else {
159
225
            ASSERT_EQ(Slice(buf1).compare(Slice(buf2)), 0);
160
225
          }
161
50.6k
        }
162
3.37k
      }
163
225
    }
164
15
  }
165
1
}
166
167
////////////////////////////////////////////////////////////
168
// Benchmarks
169
////////////////////////////////////////////////////////////
170
171
#ifdef NDEBUG
172
TEST_F(TestMemcmpableVarint, BenchmarkEncode) {
173
  faststring buf;
174
175
  int sum_sizes = 0; // need to do something with results to force evaluation
176
177
  LOG_TIMING(INFO, "Encoding integers") {
178
    for (int trial = 0; trial < 100; trial++) {
179
      for (uint64_t i = 0; i < 1000000; i++) {
180
        buf.clear();
181
        PutMemcmpableVarint64(&buf, i);
182
        sum_sizes += buf.size();
183
      }
184
    }
185
  }
186
  ASSERT_GT(sum_sizes, 1); // use 'sum_sizes' to avoid optimizing it out.
187
}
188
189
TEST_F(TestMemcmpableVarint, BenchmarkDecode) {
190
  faststring buf;
191
192
  // Encode 1M integers into the buffer
193
  for (uint64_t i = 0; i < 1000000; i++) {
194
    PutMemcmpableVarint64(&buf, i);
195
  }
196
197
  // Decode the whole buffer 100 times.
198
  LOG_TIMING(INFO, "Decoding integers") {
199
    uint64_t sum_vals = 0;
200
    for (int trial = 0; trial < 100; trial++) {
201
      Slice s(buf);
202
      while (!s.empty()) {
203
        uint64_t decoded;
204
        CHECK(GetMemcmpableVarint64(&s, &decoded).ok());
205
        sum_vals += decoded;
206
      }
207
    }
208
    ASSERT_GT(sum_vals, 1); // use 'sum_vals' to avoid optimizing it out.
209
  }
210
}
211
212
#endif
213
214
} // namespace yb