| 553 | Block getHeader() const override { return metadata_snapshot->getSampleBlock(); } |
| 554 | |
| 555 | void write(const Block & block) override |
| 556 | { |
| 557 | if (!block) |
| 558 | return; |
| 559 | |
| 560 | // Check table structure. |
| 561 | metadata_snapshot->check(block, true); |
| 562 | |
| 563 | size_t rows = block.rows(); |
| 564 | if (!rows) |
| 565 | return; |
| 566 | |
| 567 | StoragePtr destination; |
| 568 | if (storage.destination_id) |
| 569 | { |
| 570 | destination = DatabaseCatalog::instance().tryGetTable(storage.destination_id, storage.getContext()); |
| 571 | if (destination.get() == &storage) |
| 572 | throw Exception("Destination table is myself. Write will cause infinite loop.", ErrorCodes::INFINITE_LOOP); |
| 573 | } |
| 574 | |
| 575 | size_t bytes = block.bytes(); |
| 576 | |
| 577 | storage.lifetime_writes.rows += rows; |
| 578 | storage.lifetime_writes.bytes += bytes; |
| 579 | |
| 580 | /// If the block already exceeds the maximum limit, then we skip the buffer. |
| 581 | if (rows > storage.max_thresholds.rows || bytes > storage.max_thresholds.bytes) |
| 582 | { |
| 583 | if (storage.destination_id) |
| 584 | { |
| 585 | LOG_DEBUG(storage.log, "Writing block with {} rows, {} bytes directly.", rows, bytes); |
| 586 | storage.writeBlockToDestination(block, destination); |
| 587 | } |
| 588 | return; |
| 589 | } |
| 590 | |
| 591 | /// We distribute the load on the shards by the stream number. |
| 592 | const auto start_shard_num = getThreadId() % storage.num_shards; |
| 593 | |
| 594 | /// We loop through the buffers, trying to lock mutex. No more than one lap. |
| 595 | auto shard_num = start_shard_num; |
| 596 | |
| 597 | StorageBuffer::Buffer * least_busy_buffer = nullptr; |
| 598 | std::unique_lock<std::mutex> least_busy_lock; |
| 599 | size_t least_busy_shard_rows = 0; |
| 600 | |
| 601 | for (size_t try_no = 0; try_no < storage.num_shards; ++try_no) |
| 602 | { |
| 603 | std::unique_lock lock(storage.buffers[shard_num].tryLock()); |
| 604 | |
| 605 | if (lock.owns_lock()) |
| 606 | { |
| 607 | size_t num_rows = storage.buffers[shard_num].data.rows(); |
| 608 | if (!least_busy_buffer || num_rows < least_busy_shard_rows) |
| 609 | { |
| 610 | least_busy_buffer = &storage.buffers[shard_num]; |
| 611 | least_busy_lock = std::move(lock); |
| 612 | least_busy_shard_rows = num_rows; |
nothing calls this directly
no test coverage detected