| 254 | } |
| 255 | |
| 256 | BlockSplitBloomFilter BlockSplitBloomFilter::Deserialize( |
| 257 | const ReaderProperties& properties, ArrowInputStream* input, |
| 258 | std::optional<int64_t> bloom_filter_length) { |
| 259 | ThriftDeserializer deserializer(properties); |
| 260 | format::BloomFilterHeader header; |
| 261 | int64_t bloom_filter_header_read_size = 0; |
| 262 | if (bloom_filter_length.has_value()) { |
| 263 | bloom_filter_header_read_size = bloom_filter_length.value(); |
| 264 | } else { |
| 265 | // NOTE: we don't know the bloom filter header size upfront without |
| 266 | // bloom_filter_length, and we can't rely on InputStream::Peek() which isn't always |
| 267 | // implemented. Therefore, we must first Read() with an upper bound estimate of the |
| 268 | // header size, then once we know the bloom filter data size, we can Read() the exact |
| 269 | // number of remaining data bytes. |
| 270 | bloom_filter_header_read_size = kBloomFilterHeaderSizeGuess; |
| 271 | } |
| 272 | |
| 273 | // Read and deserialize bloom filter header |
| 274 | PARQUET_ASSIGN_OR_THROW(auto header_buf, input->Read(bloom_filter_header_read_size)); |
| 275 | // This gets used, then set by DeserializeThriftMsg |
| 276 | uint32_t header_size = static_cast<uint32_t>(header_buf->size()); |
| 277 | try { |
| 278 | deserializer.DeserializeMessage(header_buf->data(), &header_size, &header); |
| 279 | DCHECK_LE(header_size, header_buf->size()); |
| 280 | } catch (std::exception& e) { |
| 281 | std::stringstream ss; |
| 282 | ss << "Deserializing bloom filter header failed.\n" << e.what(); |
| 283 | throw ParquetException(ss.str()); |
| 284 | } |
| 285 | PARQUET_THROW_NOT_OK(ValidateBloomFilterHeader(header)); |
| 286 | |
| 287 | const int32_t bloom_filter_size = header.numBytes; |
| 288 | if (bloom_filter_size + header_size <= header_buf->size()) { |
| 289 | // The bloom filter data is entirely contained in the buffer we just read |
| 290 | // => just return it. |
| 291 | BlockSplitBloomFilter bloom_filter(properties.memory_pool()); |
| 292 | bloom_filter.Init(header_buf->data() + header_size, bloom_filter_size); |
| 293 | return bloom_filter; |
| 294 | } |
| 295 | if (bloom_filter_length && *bloom_filter_length != bloom_filter_size + header_size) { |
| 296 | // We know the bloom filter data size, but the real size is different. |
| 297 | std::stringstream ss; |
| 298 | ss << "Bloom filter length (" << bloom_filter_length.value() |
| 299 | << ") does not match the actual bloom filter (size: " |
| 300 | << bloom_filter_size + header_size << ")."; |
| 301 | throw ParquetException(ss.str()); |
| 302 | } |
| 303 | // We have read a part of the bloom filter already, copy it to the target buffer |
| 304 | // and read the remaining part from the InputStream. |
| 305 | auto buffer = AllocateBuffer(properties.memory_pool(), bloom_filter_size); |
| 306 | |
| 307 | const auto bloom_filter_bytes_in_header = header_buf->size() - header_size; |
| 308 | if (bloom_filter_bytes_in_header > 0) { |
| 309 | std::memcpy(buffer->mutable_data(), header_buf->data() + header_size, |
| 310 | static_cast<size_t>(bloom_filter_bytes_in_header)); |
| 311 | } |
| 312 | |
| 313 | const auto required_read_size = bloom_filter_size - bloom_filter_bytes_in_header; |
no test coverage detected