Use this function after careful estimation, and reserve enough memory according to the max size of the bitmap string to prevent OOM.
| 137 | // Use this function after careful estimation, and reserve enough memory |
| 138 | // according to the max size of the bitmap string to prevent OOM. |
| 139 | rocksdb::Status Bitmap::GetString(engine::Context &ctx, const Slice &user_key, const uint32_t max_btos_size, |
| 140 | std::string *value) { |
| 141 | value->clear(); |
| 142 | std::string raw_value; |
| 143 | std::string ns_key = AppendNamespacePrefix(user_key); |
| 144 | |
| 145 | BitmapMetadata metadata(false); |
| 146 | rocksdb::Status s = GetMetadata(ctx, ns_key, &metadata, &raw_value); |
| 147 | if (!s.ok()) return s; |
| 148 | if (metadata.size > max_btos_size) { |
| 149 | return rocksdb::Status::Aborted(kErrBitmapStringOutOfRange); |
| 150 | } |
| 151 | value->assign(metadata.size, 0); |
| 152 | |
| 153 | std::string prefix_key = InternalKey(ns_key, "", metadata.version, storage_->IsSlotIdEncoded()).Encode(); |
| 154 | |
| 155 | rocksdb::ReadOptions read_options = ctx.DefaultScanOptions(); |
| 156 | Slice prefix_key_slice(prefix_key); |
| 157 | read_options.iterate_lower_bound = &prefix_key_slice; |
| 158 | |
| 159 | auto iter = util::UniqueIterator(ctx, read_options); |
| 160 | for (iter->Seek(prefix_key); iter->Valid() && iter->key().starts_with(prefix_key); iter->Next()) { |
| 161 | InternalKey ikey(iter->key(), storage_->IsSlotIdEncoded()); |
| 162 | auto parse_result = ParseInt<uint32_t>(ikey.GetSubKey().ToString(), 10); |
| 163 | if (!parse_result) { |
| 164 | return rocksdb::Status::InvalidArgument(parse_result.Msg()); |
| 165 | } |
| 166 | uint32_t frag_index = *parse_result; |
| 167 | std::string fragment = iter->value().ToString(); |
| 168 | // To be compatible with data written before the commit d603b0e(#338) |
| 169 | // and avoid returning extra null char after expansion. |
| 170 | uint32_t valid_size = std::min( |
| 171 | {fragment.size(), static_cast<size_t>(kBitmapSegmentBytes), static_cast<size_t>(metadata.size - frag_index)}); |
| 172 | |
| 173 | for (uint32_t i = 0; i < valid_size; i++) { |
| 174 | if (!fragment[i]) continue; |
| 175 | fragment[i] = static_cast<char>(kBitSwapTable[static_cast<uint8_t>(fragment[i])]); |
| 176 | } |
| 177 | value->replace(frag_index, valid_size, fragment.data(), valid_size); |
| 178 | } |
| 179 | return rocksdb::Status::OK(); |
| 180 | } |
| 181 | |
| 182 | rocksdb::Status Bitmap::SetBit(engine::Context &ctx, const Slice &user_key, uint32_t bit_offset, bool new_bit, |
| 183 | bool *old_bit) { |
no test coverage detected