| 62 | } |
| 63 | |
| 64 | Status TupleFileReader::GetNext(RuntimeState *state, |
| 65 | BufferPool::ClientHandle* bpclient, RowBatch* output_row_batch, bool* eos) { |
| 66 | if (offset_ == file_size_) { |
| 67 | *eos = true; |
| 68 | return Status::OK(); |
| 69 | } |
| 70 | // Only the first rowbatch starts at the zero offset of the file. |
| 71 | // We use this for injecting errors for testing purposes. |
| 72 | bool first_rowbatch = offset_ == 0; |
| 73 | *eos = false; |
| 74 | SCOPED_TIMER(read_timer_); |
| 75 | // Each block starts with the sizes of the variable chunks of data: |
| 76 | // 1. The header size |
| 77 | // 2. The tuple data size |
| 78 | // 3. The tuple offsets size |
| 79 | size_t header_len; |
| 80 | size_t tuple_data_len; |
| 81 | size_t tuple_offsets_len; |
| 82 | |
| 83 | vector<kudu::Slice> chunk_lens_slices = { |
| 84 | kudu::Slice(reinterpret_cast<const char*>(&header_len), sizeof(header_len)), |
| 85 | kudu::Slice(reinterpret_cast<const char*>(&tuple_data_len), |
| 86 | sizeof(tuple_data_len)), |
| 87 | kudu::Slice(reinterpret_cast<const char*>(&tuple_offsets_len), |
| 88 | sizeof(tuple_offsets_len))}; |
| 89 | |
| 90 | KUDU_RETURN_IF_ERROR(reader_->ReadV(offset_, |
| 91 | kudu::ArrayView<kudu::Slice>(chunk_lens_slices)), |
| 92 | "Failed to read cache file"); |
| 93 | size_t chunk_lens_slices_size = sizeof(header_len) + sizeof(tuple_data_len) + |
| 94 | sizeof(tuple_offsets_len); |
| 95 | COUNTER_ADD(bytes_read_, chunk_lens_slices_size); |
| 96 | |
| 97 | // tuple_data_len can be zero, see IMPALA-13411. |
| 98 | if (header_len == 0 || tuple_offsets_len == 0) { |
| 99 | string err_msg = Substitute("Invalid data lengths at offset $0 in $1: " |
| 100 | "header_len=$2, tuple_data_len=$3, tuple_offsets_len=$4", offset_, path_, |
| 101 | header_len, tuple_data_len, tuple_offsets_len); |
| 102 | DCHECK(false) << err_msg; |
| 103 | return Status(Substitute("Invalid tuple cache file: $0", err_msg)); |
| 104 | } |
| 105 | offset_ += chunk_lens_slices_size; |
| 106 | |
| 107 | // Now, we know the total size of the variable-length data, and we can read |
| 108 | // it in a single chunk. |
| 109 | size_t varlen_size = header_len + tuple_data_len + tuple_offsets_len; |
| 110 | |
| 111 | // Sanity check: The varlen_size shouldn't be larger than the rest of the file. |
| 112 | // This protects us from doing very large memory allocations if any of the lengths |
| 113 | // are bogus. |
| 114 | if (offset_ + varlen_size > file_size_) { |
| 115 | string err_msg = Substitute("Invalid data lengths at offset $0 in $1 exceed " |
| 116 | "file size $2: header_len=$3, tuple_data_len=$4, tuple_offsets_len=$5", |
| 117 | offset_, path_, file_size_, header_len, tuple_data_len, tuple_offsets_len); |
| 118 | DCHECK(false) << err_msg; |
| 119 | return Status(Substitute("Invalid tuple cache file: $0", err_msg)); |
| 120 | } |
| 121 | std::unique_ptr<char []> varlen_data(new char[varlen_size]); |
nothing calls this directly
no test coverage detected