/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 | 63.7k | size_t right = (single_byte) ? (left + num_bits) : 8; |
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 > 0; ++bit) { |
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]) { |
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]) { |
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; ++bit) { |
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_bits; ++i) { |
141 | 72 | for (int j = 0; j < 8 && index < num_bits; ++j) { |
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 | 1.26M | void OneWayBitmap::Set(size_t bit) { |
153 | 1.26M | if (bit < fully_filled_bits_) { |
154 | 157 | return; |
155 | 157 | } |
156 | 1.26M | bit -= fully_filled_bits_; |
157 | 1.26M | data_.resize(std::max(data_.size(), bit / kBitsPerElement + 1)); |
158 | 1.26M | auto& element = data_[bit / kBitsPerElement]; |
159 | 1.26M | auto mask = 1ULL << (bit % kBitsPerElement); |
160 | 1.26M | if ((element & mask) != 0) { |
161 | 1.84k | return; |
162 | 1.84k | } |
163 | | |
164 | 1.26M | element |= mask; |
165 | 1.26M | ++ones_counter_; |
166 | | |
167 | 1.26M | size_t i = 0; |
168 | 1.29M | while (i < data_.size() && data_[i] == kAllOnes) { |
169 | 31.9k | ++i; |
170 | 31.9k | } |
171 | | |
172 | 1.26M | if (i) { |
173 | 31.8k | fully_filled_bits_ += kBitsPerElement * i; |
174 | 31.8k | data_.erase(data_.begin(), data_.begin() + i); |
175 | 31.8k | } |
176 | 1.26M | } |
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 | 3.12M | } |
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; ++idx) { |
195 | 128 | if (Test(idx)) { |
196 | 3 | values.push_back(idx); |
197 | 3 | } |
198 | 128 | } |
199 | 2 | return AsString(values); |
200 | 2 | } |
201 | | |
202 | 1.10M | void OneWayBitmap::EncodeTo(boost::container::small_vector_base<uint8_t>* out) const { |
203 | 1.10M | uint8_t buf[16]; |
204 | 1.10M | auto fully_filled_bytes_size = EncodeVarint64(buf, fully_filled_bits_ / 8) - buf; |
205 | | |
206 | 1.10M | size_t len = data_.size(); |
207 | 1.10M | size_t body_len = len + fully_filled_bytes_size; |
208 | 1.10M | PutVarint64(out, body_len); |
209 | 1.10M | size_t new_size = out->size() + body_len; |
210 | 1.10M | out->resize(new_size); |
211 | 1.10M | memcpy(out->data() + new_size - body_len, buf, fully_filled_bytes_size); |
212 | 1.10M | #ifdef IS_LITTLE_ENDIAN |
213 | 1.10M | memcpy(out->data() + out->size() - len, data_.data(), len); |
214 | | #else |
215 | | #error Not implemented |
216 | | #endif |
217 | 1.10M | } |
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 | 3.46k | 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() == 0) { |
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 |