YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/util/bitmap.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
#include "yb/util/bitmap.h"
33
34
#include <string>
35
36
#include <glog/logging.h>
37
38
#include "yb/gutil/stringprintf.h"
39
#include "yb/util/coding.h"
40
#include "yb/util/result.h"
41
#include "yb/util/status_format.h"
42
43
namespace yb {
44
45
66.0k
void BitmapChangeBits(uint8_t *bitmap, size_t offset, size_t num_bits, bool value) {
46
66.0k
  DCHECK_GT(num_bits, 0);
47
48
66.0k
  size_t start_byte = (offset >> 3);
49
66.0k
  size_t end_byte = (offset + num_bits - 1) >> 3;
50
66.0k
  int single_byte = (start_byte == end_byte);
51
52
  // Change the last bits of the first byte
53
66.0k
  size_t left = offset & 0x7;
54
66.0k
  size_t right = (single_byte) ? 
(left + num_bits)2.30k
:
863.7k
;
55
66.0k
  uint8_t mask = ((0xff << left) & (0xff >> (8 - right)));
56
66.0k
  if (value) {
57
33.0k
    bitmap[start_byte++] |= mask;
58
33.0k
  } else {
59
33.0k
    bitmap[start_byte++] &= ~mask;
60
33.0k
  }
61
62
  // Nothing left... I'm done
63
66.0k
  if (single_byte) {
64
2.30k
    return;
65
2.30k
  }
66
67
  // change the middle bits
68
63.7k
  if (end_byte > start_byte) {
69
59.9k
    const uint8_t pattern8[2] = { 0x00, 0xff };
70
59.9k
    memset(bitmap + start_byte, pattern8[value], end_byte - start_byte);
71
59.9k
  }
72
73
  // change the first bits of the last byte
74
63.7k
  right = offset + num_bits - (end_byte << 3);
75
63.7k
  mask = (0xff >> (8 - right));
76
63.7k
  if (value) {
77
31.8k
    bitmap[end_byte] |= mask;
78
31.8k
  } else {
79
31.8k
    bitmap[end_byte] &= ~mask;
80
31.8k
  }
81
63.7k
}
82
83
bool BitmapFindFirst(const uint8_t *bitmap, size_t offset, size_t bitmap_size,
84
195k
                     bool value, size_t *idx) {
85
195k
  const uint64_t pattern64[2] = { 0xffffffffffffffff, 0x0000000000000000 };
86
195k
  const uint8_t pattern8[2] = { 0xff, 0x00 };
87
195k
  size_t bit;
88
89
195k
  DCHECK_LE(offset, bitmap_size);
90
91
  // Jump to the byte at specified offset
92
195k
  const uint8_t *p = bitmap + (offset >> 3);
93
195k
  size_t num_bits = bitmap_size - offset;
94
95
  // Find a 'value' bit at the end of the first byte
96
195k
  if ((bit = offset & 0x7)) {
97
325k
    for (; bit < 8 && 
num_bits > 0274k
;
++bit211k
) {
98
272k
      if (BitmapTest(p, bit) == value) {
99
61.2k
        *idx = ((p - bitmap) << 3) + bit;
100
61.2k
        return true;
101
61.2k
      }
102
103
211k
      num_bits--;
104
211k
    }
105
106
53.2k
    p++;
107
53.2k
  }
108
109
  // check 64bit at the time for a 'value' bit
110
134k
  const uint64_t *u64 = (const uint64_t *)p;
111
160k
  while (num_bits >= 64 && 
*u64 == pattern64[value]37.9k
) {
112
25.9k
    num_bits -= 64;
113
25.9k
    u64++;
114
25.9k
  }
115
116
  // check 8bit at the time for a 'value' bit
117
134k
  p = (const uint8_t *)u64;
118
395k
  while (num_bits >= 8 && 
*p == pattern8[value]301k
) {
119
261k
    num_bits -= 8;
120
261k
    p++;
121
261k
  }
122
123
  // Find a 'value' bit at the beginning of the last byte
124
383k
  for (bit = 0; num_bits > 0; 
++bit248k
) {
125
293k
    if (BitmapTest(p, bit) == value) {
126
44.4k
      *idx = ((p - bitmap) << 3) + bit;
127
44.4k
      return true;
128
44.4k
    }
129
248k
    num_bits--;
130
248k
  }
131
132
89.8k
  return false;
133
134k
}
134
135
1
std::string BitmapToString(const uint8_t *bitmap, size_t num_bits) {
136
1
  std::string s;
137
1
  size_t index = 0;
138
2
  while (index < num_bits) {
139
1
    StringAppendF(&s, "%4zu: ", index);
140
9
    for (int i = 0; i < 8 && 
index < num_bits8
;
++i8
) {
141
72
      for (int j = 0; j < 8 && 
index < num_bits64
;
++j64
) {
142
64
        StringAppendF(&s, "%d", BitmapTest(bitmap, index));
143
64
        index++;
144
64
      }
145
8
      StringAppendF(&s, " ");
146
8
    }
147
1
    StringAppendF(&s, "\n");
148
1
  }
149
1
  return s;
150
1
}
151
152
2.31M
void OneWayBitmap::Set(size_t bit) {
153
2.31M
  if (bit < fully_filled_bits_) {
154
157
    return;
155
157
  }
156
2.31M
  bit -= fully_filled_bits_;
157
2.31M
  data_.resize(std::max(data_.size(), bit / kBitsPerElement + 1));
158
2.31M
  auto& element = data_[bit / kBitsPerElement];
159
2.31M
  auto mask = 1ULL << (bit % kBitsPerElement);
160
2.31M
  if ((element & mask) != 0) {
161
1.84k
    return;
162
1.84k
  }
163
164
2.31M
  element |= mask;
165
2.31M
  ++ones_counter_;
166
167
2.31M
  size_t i = 0;
168
2.37M
  while (i < data_.size() && 
data_[i] == kAllOnes2.31M
) {
169
62.0k
    ++i;
170
62.0k
  }
171
172
2.31M
  if (i) {
173
61.9k
    fully_filled_bits_ += kBitsPerElement * i;
174
61.9k
    data_.erase(data_.begin(), data_.begin() + i);
175
61.9k
  }
176
2.31M
}
177
178
7.53M
bool OneWayBitmap::Test(size_t bit) const {
179
7.53M
  if (bit < fully_filled_bits_) {
180
2.00M
    return true;
181
2.00M
  }
182
5.52M
  bit -= fully_filled_bits_;
183
5.52M
  size_t idx = bit / kBitsPerElement;
184
5.52M
  if (idx >= data_.size()) {
185
2.40M
    return false;
186
2.40M
  }
187
188
3.12M
  return (data_[idx] & 1ULL << (bit % kBitsPerElement)) != 0;
189
5.52M
}
190
191
2
std::string OneWayBitmap::ToString() const {
192
2
  std::vector<size_t> values;
193
2
  size_t max = fully_filled_bits_ + data_.size() * 8 * sizeof(size_t);
194
130
  for (size_t idx = 0; idx != max; 
++idx128
) {
195
128
    if (Test(idx)) {
196
3
      values.push_back(idx);
197
3
    }
198
128
  }
199
2
  return AsString(values);
200
2
}
201
202
2.31M
void OneWayBitmap::EncodeTo(boost::container::small_vector_base<uint8_t>* out) const {
203
2.31M
  uint8_t buf[16];
204
2.31M
  auto fully_filled_bytes_size = EncodeVarint64(buf, fully_filled_bits_ / 8) - buf;
205
206
2.31M
  size_t len = data_.size();
207
2.31M
  size_t body_len = len + fully_filled_bytes_size;
208
2.31M
  PutVarint64(out, body_len);
209
2.31M
  size_t new_size = out->size() + body_len;
210
2.31M
  out->resize(new_size);
211
2.31M
  memcpy(out->data() + new_size - body_len, buf, fully_filled_bytes_size);
212
2.31M
#ifdef IS_LITTLE_ENDIAN
213
2.31M
  memcpy(out->data() + out->size() - len, data_.data(), len);
214
#else
215
  #error Not implemented
216
#endif
217
2.31M
}
218
219
2
std::string OneWayBitmap::EncodeToHexString() const {
220
2
  boost::container::small_vector<uint8_t, 16> buffer;
221
2
  EncodeTo(&buffer);
222
2
  return Slice(buffer.data(), buffer.size()).ToDebugHexString();
223
2
}
224
225
6.92k
Result<Slice> DecodeBody(Slice* slice) {
226
6.92k
  uint64_t body_len;
227
6.92k
  if (!GetVarint64(slice, &body_len)) {
228
0
    return STATUS(Corruption, "Unable to decode data bytes");
229
0
  }
230
6.92k
  Slice body(slice->data(), body_len);
231
6.92k
  if (body.end() > slice->end()) {
232
0
    return STATUS(Corruption, "Not enough body bytes");
233
0
  }
234
6.92k
  slice->remove_prefix(body.size());
235
6.92k
  return body;
236
6.92k
}
237
238
3.46k
Status OneWayBitmap::Skip(Slice* slice) {
239
3.46k
  return ResultToStatus(DecodeBody(slice));
240
3.46k
}
241
242
3.46k
Result<OneWayBitmap> OneWayBitmap::Decode(Slice* slice) {
243
3.46k
  OneWayBitmap result;
244
245
3.46k
  auto body = VERIFY_RESULT(DecodeBody(slice));
246
247
0
  uint64_t fully_filled_bytes;
248
3.46k
  if (!GetVarint64(&body, &fully_filled_bytes)) {
249
0
    return STATUS(Corruption, "Unable to decode fully filled bytes");
250
0
  }
251
3.46k
  result.fully_filled_bits_ = fully_filled_bytes * 8;
252
3.46k
  result.ones_counter_ = result.fully_filled_bits_;
253
3.46k
#ifdef IS_LITTLE_ENDIAN
254
3.46k
  result.data_.resize(body.size());
255
3.46k
  memcpy(result.data_.data(), body.data(), body.size());
256
#else
257
  #error Not implemented
258
#endif
259
195k
  for (auto v : result.data_) {
260
195k
    result.ones_counter_ += __builtin_popcount(v);
261
195k
  }
262
  // Data was
263
3.46k
  if (!result.data_.empty() && 
result.data_.back() == 03.44k
) {
264
0
    return STATUS_FORMAT(Corruption, "Last bitmap byte is zero: $0", body.ToDebugHexString());
265
0
  }
266
267
3.46k
  return result;
268
3.46k
}
269
270
} // namespace yb