YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/bitmap-test.cc
Line
Count
Source
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 <bitset>
34
#include <random>
35
#include <vector>
36
37
#include <gtest/gtest.h>
38
39
#include "yb/gutil/strings/join.h"
40
41
#include "yb/util/bitmap.h"
42
#include "yb/util/random_util.h"
43
#include "yb/util/result.h"
44
#include "yb/util/slice.h"
45
#include "yb/util/test_macros.h"
46
47
namespace yb {
48
49
static int ReadBackBitmap(uint8_t *bm, size_t bits,
50
2
                           std::vector<size_t> *result) {
51
2
  int iters = 0;
52
2
  for (TrueBitIterator iter(bm, bits);
53
9
       !iter.done();
54
7
       ++iter) {
55
7
    size_t val = *iter;
56
7
    result->push_back(val);
57
58
7
    iters++;
59
7
  }
60
2
  return iters;
61
2
}
62
63
1
TEST(TestBitMap, TestIteration) {
64
1
  uint8_t bm[8];
65
1
  memset(bm, 0, sizeof(bm));
66
1
  BitmapSet(bm, 0);
67
1
  BitmapSet(bm, 8);
68
1
  BitmapSet(bm, 31);
69
1
  BitmapSet(bm, 32);
70
1
  BitmapSet(bm, 33);
71
1
  BitmapSet(bm, 63);
72
73
1
  EXPECT_EQ("   0: 10000000 10000000 00000000 00000001 11000000 00000000 00000000 00000001 \n",
74
1
            BitmapToString(bm, sizeof(bm) * 8));
75
76
1
  std::vector<size_t> read_back;
77
78
1
  int iters = ReadBackBitmap(bm, sizeof(bm)*8, &read_back);
79
1
  ASSERT_EQ(6, iters);
80
1
  ASSERT_EQ("0,8,31,32,33,63", JoinElements(read_back, ","));
81
1
}
82
83
84
1
TEST(TestBitMap, TestIteration2) {
85
1
  uint8_t bm[1];
86
1
  memset(bm, 0, sizeof(bm));
87
1
  BitmapSet(bm, 1);
88
89
1
  std::vector<size_t> read_back;
90
91
1
  int iters = ReadBackBitmap(bm, 3, &read_back);
92
1
  ASSERT_EQ(1, iters);
93
1
  ASSERT_EQ("1", JoinElements(read_back, ","));
94
1
}
95
96
1
TEST(TestBitmap, TestSetAndTestBits) {
97
1
  uint8_t bm[1];
98
1
  memset(bm, 0, sizeof(bm));
99
100
1
  size_t num_bits = sizeof(bm) * 8;
101
9
  for (size_t i = 0; i < num_bits; i++) {
102
8
    ASSERT_FALSE(BitmapTest(bm, i));
103
104
8
    BitmapSet(bm, i);
105
8
    ASSERT_TRUE(BitmapTest(bm, i));
106
107
8
    BitmapClear(bm, i);
108
8
    ASSERT_FALSE(BitmapTest(bm, i));
109
110
8
    BitmapChange(bm, i, true);
111
8
    ASSERT_TRUE(BitmapTest(bm, i));
112
113
8
    BitmapChange(bm, i, false);
114
8
    ASSERT_FALSE(BitmapTest(bm, i));
115
8
  }
116
117
  // Set the other bit: 01010101
118
9
  for (size_t i = 0; i < num_bits; ++i) {
119
8
    ASSERT_FALSE(BitmapTest(bm, i));
120
8
    if (i & 1) BitmapSet(bm, i);
121
8
  }
122
123
  // Check and Clear the other bit: 0000000
124
9
  for (size_t i = 0; i < num_bits; ++i) {
125
8
    ASSERT_EQ(!!(i & 1), BitmapTest(bm, i));
126
8
    if (i & 1) BitmapClear(bm, i);
127
8
  }
128
129
  // Check if bits are zero and change the other to one
130
9
  for (size_t i = 0; i < num_bits; ++i) {
131
8
    ASSERT_FALSE(BitmapTest(bm, i));
132
8
    BitmapChange(bm, i, i & 1);
133
8
  }
134
135
  // Check the bits change them again
136
9
  for (size_t i = 0; i < num_bits; ++i) {
137
8
    ASSERT_EQ(!!(i & 1), BitmapTest(bm, i));
138
8
    BitmapChange(bm, i, !(i & 1));
139
8
  }
140
141
  // Check the last setup
142
9
  for (size_t i = 0; i < num_bits; ++i) {
143
8
    ASSERT_EQ(!(i & 1), BitmapTest(bm, i));
144
8
  }
145
1
}
146
147
1
TEST(TestBitMap, TestBulkSetAndTestBits) {
148
1
  uint8_t bm[16];
149
1
  size_t total_size = sizeof(bm) * 8;
150
151
  // Test Bulk change bits and test bits
152
5
  for (int i = 0; i < 4; ++i) {
153
4
    bool value = i & 1;
154
4
    size_t num_bits = total_size;
155
516
    while (num_bits > 0) {
156
33.5k
      for (size_t offset = 0; offset < num_bits; ++offset) {
157
33.0k
        BitmapChangeBits(bm, 0, total_size, !value);
158
33.0k
        BitmapChangeBits(bm, offset, num_bits - offset, value);
159
160
33.0k
        ASSERT_EQ(value, BitMapIsAllSet(bm, offset, num_bits));
161
33.0k
        ASSERT_EQ(!value, BitmapIsAllZero(bm, offset, num_bits));
162
163
33.0k
        if (offset > 1) {
164
32.0k
          ASSERT_EQ(value, BitmapIsAllZero(bm, 0, offset - 1));
165
32.0k
          ASSERT_EQ(!value, BitMapIsAllSet(bm, 0, offset - 1));
166
32.0k
        }
167
168
33.0k
        if ((offset + num_bits) < total_size) {
169
16.3k
          ASSERT_EQ(value, BitmapIsAllZero(bm, num_bits, total_size));
170
16.3k
          ASSERT_EQ(!value, BitMapIsAllSet(bm, num_bits, total_size));
171
16.3k
        }
172
33.0k
      }
173
512
      num_bits--;
174
512
    }
175
4
  }
176
1
}
177
178
1
TEST(TestBitMap, TestFindBit) {
179
1
  uint8_t bm[16];
180
181
1
  size_t num_bits = sizeof(bm) * 8;
182
1
  BitmapChangeBits(bm, 0, num_bits, false);
183
129
  while (num_bits > 0) {
184
8.38k
    for (size_t offset = 0; offset < num_bits; ++offset) {
185
8.25k
      size_t idx;
186
8.25k
      ASSERT_FALSE(BitmapFindFirstSet(bm, offset, num_bits, &idx));
187
8.25k
      ASSERT_TRUE(BitmapFindFirstZero(bm, offset, num_bits, &idx));
188
8.25k
      ASSERT_EQ(idx, offset);
189
8.25k
    }
190
128
    num_bits--;
191
128
  }
192
193
1
  num_bits = sizeof(bm) * 8;
194
129
  for (size_t i = 0; i < num_bits; ++i) {
195
128
    BitmapChange(bm, i, i & 3);
196
128
  }
197
198
129
  while (num_bits--) {
199
8.25k
    for (size_t offset = 0; offset < num_bits; ++offset) {
200
8.12k
      size_t idx;
201
202
      // Find a set bit
203
8.12k
      bool res = BitmapFindFirstSet(bm, offset, num_bits, &idx);
204
8.12k
      size_t expected_set_idx = (offset + !(offset & 3));
205
8.12k
      bool expect_set_found = (expected_set_idx < num_bits);
206
8.12k
      ASSERT_EQ(expect_set_found, res);
207
8.12k
      if (expect_set_found) {
208
8.09k
        ASSERT_EQ(expected_set_idx, idx);
209
8.09k
      }
210
211
      // Find a zero bit
212
8.12k
      res = BitmapFindFirstZero(bm, offset, num_bits, &idx);
213
6.04k
      size_t expected_zero_idx = offset + ((offset & 3) ? (4 - (offset & 3)) : 0);
214
8.12k
      bool expect_zero_found = (expected_zero_idx < num_bits);
215
8.12k
      ASSERT_EQ(expect_zero_found, res);
216
8.12k
      if (expect_zero_found) {
217
7.93k
        ASSERT_EQ(expected_zero_idx, idx);
218
7.93k
      }
219
8.12k
    }
220
128
  }
221
1
}
222
223
1
TEST(TestBitMap, TestBitmapIteration) {
224
1
  uint8_t bm[8];
225
1
  memset(bm, 0, sizeof(bm));
226
1
  BitmapSet(bm, 0);
227
1
  BitmapSet(bm, 8);
228
1
  BitmapSet(bm, 31);
229
1
  BitmapSet(bm, 32);
230
1
  BitmapSet(bm, 33);
231
1
  BitmapSet(bm, 63);
232
233
1
  BitmapIterator biter(bm, sizeof(bm) * 8);
234
235
1
  size_t i = 0;
236
1
  size_t size;
237
1
  bool value = false;
238
1
  bool expected_value = true;
239
1
  size_t expected_sizes[] = {1, 7, 1, 22, 3, 29, 1, 0};
240
8
  while ((size = biter.Next(&value)) > 0) {
241
7
    ASSERT_LT(i, 8);
242
7
    ASSERT_EQ(expected_value, value);
243
7
    ASSERT_EQ(expected_sizes[i], size);
244
7
    expected_value = !expected_value;
245
7
    i++;
246
7
  }
247
1
  ASSERT_EQ(expected_sizes[i], size);
248
1
}
249
250
1
TEST(TestBitMap, OneWayBitmapSimple) {
251
1
  OneWayBitmap bitmap;
252
1
  ASSERT_FALSE(bitmap.Test(0));
253
254
1
  bitmap.Set(0);
255
1
  ASSERT_TRUE(bitmap.Test(0));
256
1
  ASSERT_FALSE(bitmap.Test(1));
257
1
  ASSERT_EQ(bitmap.CountSet(), 1);
258
1
  ASSERT_EQ(bitmap.EncodeToHexString(), "020001");
259
1
  ASSERT_EQ(bitmap.ToString(), "[0]");
260
261
1
  bitmap.Set(2);
262
1
  ASSERT_TRUE(bitmap.Test(0));
263
1
  ASSERT_TRUE(bitmap.Test(2));
264
1
  ASSERT_FALSE(bitmap.Test(1));
265
1
  ASSERT_EQ(bitmap.CountSet(), 2);
266
1
  ASSERT_EQ(bitmap.EncodeToHexString(), "020005");
267
1
  ASSERT_EQ(bitmap.ToString(), "[0, 2]");
268
1
}
269
270
template<size_t N>
271
6.92k
void CheckSame(const OneWayBitmap& bitmap, const std::bitset<N>& bitset) {
272
6.92k
  EXPECT_EQ(bitmap.CountSet(), bitset.count());
273
7.09M
  for (size_t bit = 0; bit != N; ++bit) {
274
14.1M
    EXPECT_EQ(bitmap.Test(bit), bitset.test(bit)) << "Bit: " << bit;
275
7.08M
  }
276
449k
  for (size_t bit = N; bit != N + sizeof(size_t) * 8; ++bit) {
277
443k
    EXPECT_FALSE(bitmap.Test(N));
278
443k
  }
279
6.92k
}
280
281
template<size_t N>
282
3.46k
void CheckBitmap(const OneWayBitmap& bitmap, const std::bitset<N>& bitset) {
283
3.46k
  ASSERT_NO_FATALS(CheckSame(bitmap, bitset));
284
3.46k
  boost::container::small_vector<uint8_t, 8> buffer;
285
3.46k
  bitmap.EncodeTo(&buffer);
286
3.46k
  Slice slice(buffer.data(), buffer.size());
287
288
3.46k
  auto decoded_bitmap = ASSERT_RESULT_FAST(OneWayBitmap::Decode(&slice));
289
3.46k
  ASSERT_TRUE(slice.empty());
290
3.46k
  ASSERT_NO_FATALS(CheckSame(decoded_bitmap, bitset));
291
292
3.46k
  slice = Slice(buffer.data(), buffer.size());
293
3.46k
  ASSERT_OK_FAST(OneWayBitmap::Skip(&slice));
294
3.46k
  ASSERT_TRUE(slice.empty());
295
3.46k
}
296
297
template<size_t N>
298
2
void CheckBitSequence(const std::vector<size_t>& bits_to_set) {
299
2
  std::bitset<N> bitset;
300
2
  OneWayBitmap bitmap;
301
302
2
  ASSERT_NO_FATALS(CheckBitmap(bitmap, bitset));
303
304
3.45k
  for (auto i : bits_to_set) {
305
3.45k
    bitmap.Set(i);
306
3.45k
    bitset.set(i, true);
307
308
3.45k
    ASSERT_NO_FATALS(CheckBitmap(bitmap, bitset));
309
3.45k
  }
310
2
}
311
312
// Test OneWayBitmap when bits are set randomly.
313
1
TEST(TestBitMap, OneWayBitmapRandom) {
314
1
  std::mt19937_64 rng(123456);
315
316
1
  constexpr size_t kTotalBits = 1024;
317
1
  std::vector<size_t> bits_to_set;
318
1
  bits_to_set.reserve(kTotalBits * 2);
319
1.02k
  for (size_t i = 0; i != kTotalBits; ++i) {
320
1.02k
    bits_to_set.push_back(i);
321
1.02k
    if (RandomUniformBool(&rng)) {
322
483
      bits_to_set.push_back(i);
323
483
    }
324
1.02k
  }
325
326
1
  std::shuffle(bits_to_set.begin(), bits_to_set.end(), rng);
327
328
1
  ASSERT_NO_FATALS(CheckBitSequence<kTotalBits>(bits_to_set));
329
1
}
330
331
// Test OneWayBitmap when bits are set in nearly increasing order.
332
1
TEST(TestBitMap, OneWayBitmapMetaIncreasing) {
333
1
  std::mt19937_64 rng(123456);
334
335
1
  constexpr size_t kTotalBits = 1024;
336
1
  std::vector<size_t> bits_to_set;
337
1
  bits_to_set.reserve(kTotalBits * 2);
338
1.02k
  for (size_t i = 0; i != kTotalBits; ++i) {
339
1.02k
    size_t extra_index = i + RandomUniformInt(10, 20, &rng) - 10;
340
1.02k
    if (extra_index > i && extra_index < kTotalBits) {
341
928
      bits_to_set.push_back(extra_index);
342
928
    }
343
1.02k
    bits_to_set.push_back(i);
344
1.02k
  }
345
346
1
  ASSERT_NO_FATALS(CheckBitSequence<kTotalBits>(bits_to_set));
347
1
}
348
349
} // namespace yb