| 283 | } |
| 284 | |
| 285 | Status RowBatch::SerializeInternal(int64_t size, DedupMap* distinct_tuples, |
| 286 | vector<int32_t>* tuple_offsets, char* tuple_data) { |
| 287 | DCHECK(distinct_tuples == nullptr || distinct_tuples->size() == 0); |
| 288 | |
| 289 | tuple_offsets->reserve(num_rows_ * num_tuples_per_row_); |
| 290 | |
| 291 | // Copy tuple data of unique tuples, including strings, into output_batch (converting |
| 292 | // string pointers into offsets in the process). |
| 293 | int offset = 0; // current offset into output_batch->tuple_data |
| 294 | |
| 295 | for (int i = 0; i < num_rows_; ++i) { |
| 296 | vector<TupleDescriptor*>::const_iterator desc = |
| 297 | row_desc_->tuple_descriptors().begin(); |
| 298 | for (int j = 0; desc != row_desc_->tuple_descriptors().end(); ++desc, ++j) { |
| 299 | Tuple* tuple = GetRow(i)->GetTuple(j); |
| 300 | if (UNLIKELY(tuple == nullptr)) { |
| 301 | // NULLs are encoded as -1 |
| 302 | tuple_offsets->push_back(-1); |
| 303 | continue; |
| 304 | } else if (LIKELY(i > 0) && UNLIKELY(GetRow(i - 1)->GetTuple(j) == tuple)) { |
| 305 | // Fast tuple deduplication for adjacent rows. |
| 306 | int prev_row_idx = tuple_offsets->size() - num_tuples_per_row_; |
| 307 | tuple_offsets->push_back((*tuple_offsets)[prev_row_idx]); |
| 308 | continue; |
| 309 | } else if (UNLIKELY(distinct_tuples != nullptr)) { |
| 310 | if ((*desc)->byte_size() == 0) { |
| 311 | // Zero-length tuples can be represented as nullptr. |
| 312 | tuple_offsets->push_back(-1); |
| 313 | continue; |
| 314 | } |
| 315 | int* dedupd_offset = distinct_tuples->FindOrInsert(tuple, offset); |
| 316 | if (*dedupd_offset != offset) { |
| 317 | // Repeat of tuple |
| 318 | DCHECK_GE(*dedupd_offset, 0); |
| 319 | tuple_offsets->push_back(*dedupd_offset); |
| 320 | continue; |
| 321 | } |
| 322 | } |
| 323 | // Record offset before creating copy (which increments offset and tuple_data) |
| 324 | tuple_offsets->push_back(offset); |
| 325 | tuple->DeepCopy(**desc, &tuple_data, &offset, /* convert_ptrs */ true); |
| 326 | DCHECK_LE(offset, size); |
| 327 | } |
| 328 | } |
| 329 | DCHECK_EQ(offset, size); |
| 330 | return Status::OK(); |
| 331 | } |
| 332 | |
| 333 | Status RowBatch::AllocateBuffer(BufferPool::ClientHandle* client, int64_t len, |
| 334 | BufferPool::BufferHandle* buffer_handle) { |