| 733 | } |
| 734 | |
| 735 | Future<int64_t> AsyncScanner::CountRowsAsync(Executor* executor) { |
| 736 | ARROW_ASSIGN_OR_RAISE(auto fragment_gen, GetFragments()); |
| 737 | |
| 738 | compute::ExecContext exec_context(scan_options_->pool, executor); |
| 739 | |
| 740 | ARROW_ASSIGN_OR_RAISE(auto plan, acero::ExecPlan::Make(exec_context)); |
| 741 | // Drop projection since we only need to count rows |
| 742 | const auto options = std::make_shared<ScanOptions>(*scan_options_); |
| 743 | ARROW_ASSIGN_OR_RAISE(auto empty_projection, |
| 744 | ProjectionDescr::FromNames(std::vector<std::string>(), |
| 745 | *scan_options_->dataset_schema, |
| 746 | scan_options_->add_augmented_fields)); |
| 747 | SetProjection(options.get(), empty_projection); |
| 748 | |
| 749 | auto total = std::make_shared<std::atomic<int64_t>>(0); |
| 750 | |
| 751 | fragment_gen = MakeMappedGenerator( |
| 752 | std::move(fragment_gen), |
| 753 | [options, total](const std::shared_ptr<Fragment>& fragment) { |
| 754 | return fragment->CountRows(options->filter, options) |
| 755 | .Then([options, total, fragment](std::optional<int64_t> fast_count) mutable |
| 756 | -> std::shared_ptr<Fragment> { |
| 757 | if (fast_count) { |
| 758 | // fast path: got row count directly; skip scanning this fragment |
| 759 | (*total) += *fast_count; |
| 760 | return std::make_shared<InMemoryFragment>(options->dataset_schema, |
| 761 | RecordBatchVector{}); |
| 762 | } |
| 763 | |
| 764 | // slow path: actually filter this fragment's batches |
| 765 | return std::move(fragment); |
| 766 | }); |
| 767 | }); |
| 768 | |
| 769 | acero::Declaration count_plan = acero::Declaration::Sequence( |
| 770 | {{"scan", |
| 771 | ScanNodeOptions{std::make_shared<FragmentDataset>(scan_options_->dataset_schema, |
| 772 | std::move(fragment_gen)), |
| 773 | options}}, |
| 774 | {"project", acero::ProjectNodeOptions{{options->filter}, {"mask"}}}, |
| 775 | {"aggregate", acero::AggregateNodeOptions{{compute::Aggregate{ |
| 776 | "sum", nullptr, "mask", "selected_count"}}}}}); |
| 777 | |
| 778 | return acero::DeclarationToBatchesAsync(std::move(count_plan), exec_context) |
| 779 | .Then([total](const RecordBatchVector& batches) -> Result<int64_t> { |
| 780 | DCHECK_EQ(1, batches.size()); |
| 781 | ARROW_ASSIGN_OR_RAISE(std::shared_ptr<Scalar> count_scalar, |
| 782 | batches[0]->column(0)->GetScalar(0)); |
| 783 | return total->load() + |
| 784 | static_cast<int64_t>( |
| 785 | ::arrow::internal::checked_pointer_cast<UInt64Scalar>(count_scalar) |
| 786 | ->value); |
| 787 | }); |
| 788 | } |
| 789 | |
| 790 | Future<int64_t> AsyncScanner::CountRowsAsync() { |
| 791 | return CountRowsAsync(scan_options_->cpu_executor |
nothing calls this directly
no test coverage detected