github-actions[bot] commented on code in PR #66758:
URL: https://github.com/apache/doris/pull/66758#discussion_r3794658406


##########
be/test/format_v2/column_mapper_test.cpp:
##########
@@ -4145,6 +4198,10 @@ TEST(ColumnMapperTest, 
PredicateAccessPathsCreateDeferredStructOutputProjection)
     EXPECT_EQ(request.local_positions.at(LocalColumnId(0)), LocalIndex(0));
     EXPECT_EQ(request.non_predicate_position(LocalColumnId(0)), LocalIndex(1));
     EXPECT_TRUE(request.is_predicate_only(LocalColumnId(0)));
+    EXPECT_EQ(request.variant_access_paths.at(LocalColumnId(0)),

Review Comment:
   [P1] Move these Variant assertions into the following Variant test
   
   This test only maps `STRUCT<a BIGINT, b BIGINT>` and never supplies any 
Variant access path. `register_root_variant_access_paths()` explicitly skips 
non-Variant roots, so both maps are empty and this first 
`.at(LocalColumnId(0))` deterministically throws, making the STRUCT test fail. 
These `typed_col` assertions belong in 
`PredicateAccessPathsCreateDeferredVariantRootProjection` (after its request 
assertions), where that path is configured.



##########
be/src/format_v2/parquet/reader/variant_column_reader.cpp:
##########
@@ -1018,6 +1623,158 @@ class ParquetVariantShreddedState final : public 
VariantShreddedState {
     }
 
 private:
+    size_t direct_seek_result_bytes(bool allocated) const {
+        size_t bytes = 0;
+        for (const auto& [path, column] : _direct_seek_multi_path_results) {
+            bytes += allocated ? path.capacity() : path.size();
+            bytes += allocated ? column->allocated_bytes() : 
column->byte_size();
+        }
+        bytes += _direct_seek_multi_path_selected_bytes.size() *
+                 
sizeof(decltype(_direct_seek_multi_path_selected_bytes)::value_type);
+        for (const auto& [path, selected] : _direct_seek_multi_path_values) {
+            bytes += allocated ? path.capacity() : path.size();
+            bytes += allocated ? selected.allocated_bytes() : 
selected.byte_size();
+        }
+        return bytes;
+    }
+
+    std::optional<ColumnPtr> find_unshredded_normalized_value(
+            std::span<const VariantShreddedPathSegment> path) const {
+        if (!_complete) {
+            return std::nullopt;
+        }
+        const auto indices = unshredded_child_indices(*_schema);
+        if (!indices.has_value()) {
+            return std::nullopt;
+        }
+
+        std::optional<std::string_view> planned_key;
+        if (path.size() == 1 && path.front().kind == 
VariantShreddedPathSegment::Kind::OBJECT_KEY &&
+            !_planned_direct_seek_paths.empty() &&
+            _physical->size() <=
+                    MAX_DIRECT_SEEK_MULTI_PATH_CELLS / 
_planned_direct_seek_paths.size()) {
+            planned_key.emplace(path.front().key.data == nullptr ? "" : 
path.front().key.data,
+                                path.front().key.size);
+            const auto planned = std::lower_bound(
+                    _planned_direct_seek_paths.begin(), 
_planned_direct_seek_paths.end(),
+                    *planned_key,
+                    [](std::string_view left, std::string_view right) { return 
left < right; });
+            if (planned == _planned_direct_seek_paths.end() || *planned != 
*planned_key) {
+                planned_key.reset();
+            }
+        }
+
+        if (planned_key.has_value()) {
+            DirectResidualMultiSeekResult root_result;
+            DirectResidualSeekResult path_result;
+            ColumnPtr column;
+            int64_t selected_value_bytes = 0;
+            bool built_root = false;
+            bool built_path = false;
+            {
+                std::lock_guard lock(_materialization_lock);
+                if (!_direct_seek_multi_path_values_ready) {
+                    // Root/container validation and exact child-interval 
lookup run once for the
+                    // complete planned set. Child payloads remain opaque 
until requested below.
+                    
SCOPED_TIMER(_profile.variant_direct_residual_seek_time.get());
+                    if (!_unshredded_metadata_cache) {
+                        _unshredded_metadata_cache = 
build_unshredded_metadata_cache(
+                                *_schema, *_physical, indices->first);
+                    }
+                    root_result = seek_unshredded_variant_paths(
+                            *_schema, *_physical, indices->second, 
*_unshredded_metadata_cache,
+                            _direct_seek_container_cache,
+                            std::span<const 
std::string_view>(_planned_direct_seek_paths),
+                            *planned_key);
+                    path_result = std::move(root_result.requested_path);
+                    _direct_seek_multi_path_values = 
std::move(root_result.paths);
+                    const auto requested_values = 
_direct_seek_multi_path_values.find(*planned_key);
+                    DORIS_CHECK(requested_values != 
_direct_seek_multi_path_values.end());
+                    _direct_seek_multi_path_values.erase(requested_values);
+                    const auto [unused, inserted] = 
_direct_seek_multi_path_results.emplace(
+                            std::string(*planned_key), 
std::move(path_result.column));
+                    static_cast<void>(unused);
+                    DORIS_CHECK(inserted);
+                    const auto [unused_bytes, inserted_bytes] =
+                            _direct_seek_multi_path_selected_bytes.emplace(
+                                    std::string(*planned_key), 
path_result.selected_value_bytes);
+                    static_cast<void>(unused_bytes);
+                    DORIS_CHECK(inserted_bytes);
+                    _direct_seek_multi_path_values_ready = true;
+                    built_root = true;
+                    built_path = true;
+                }
+                auto found = 
_direct_seek_multi_path_results.find(*planned_key);
+                if (found == _direct_seek_multi_path_results.end()) {
+                    // Preserve selected-branch corruption semantics: only the 
path that reached an
+                    // executing expression is recursively validated and 
rebuilt as an owning value.
+                    
SCOPED_TIMER(_profile.variant_direct_residual_seek_time.get());
+                    const auto selected = 
_direct_seek_multi_path_values.find(*planned_key);
+                    DORIS_CHECK(selected != 
_direct_seek_multi_path_values.end());
+                    const std::string selected_key = selected->first;
+                    path_result = 
materialize_unshredded_variant_path(selected->second,
+                                                                      
*_unshredded_metadata_cache);
+                    _direct_seek_multi_path_values.erase(selected);
+                    const auto [inserted, was_inserted] = 
_direct_seek_multi_path_results.emplace(
+                            selected_key, std::move(path_result.column));
+                    DORIS_CHECK(was_inserted);
+                    const auto [unused_bytes, inserted_bytes] =
+                            _direct_seek_multi_path_selected_bytes.emplace(
+                                    selected_key, 
path_result.selected_value_bytes);
+                    static_cast<void>(unused_bytes);
+                    DORIS_CHECK(inserted_bytes);
+                    found = inserted;
+                    built_path = true;
+                }
+                column = found->second;
+                const auto bytes = 
_direct_seek_multi_path_selected_bytes.find(*planned_key);
+                DORIS_CHECK(bytes != 
_direct_seek_multi_path_selected_bytes.end());
+                selected_value_bytes = bytes->second;
+            }
+            if (built_root) {
+                
update_counter(_profile.variant_direct_residual_seek_container_index_builds,
+                               root_result.container_index_builds);
+                
update_counter(_profile.variant_direct_residual_seek_container_index_hits,
+                               root_result.container_index_hits);
+                
update_counter(_profile.variant_direct_residual_seek_multi_path_batches, 1);
+                
update_counter(_profile.variant_direct_residual_seek_multi_path_root_rows,
+                               root_result.root_rows);
+            }
+            DORIS_CHECK_LE(_physical->size(),
+                           
static_cast<size_t>(std::numeric_limits<int64_t>::max()));
+            update_counter(_profile.variant_direct_residual_seek_rows,

Review Comment:
   [P2] Do not charge copied bytes again for a cached path result
   
   When this path already exists in `_direct_seek_multi_path_results`, the 
branch only returns the cached `ColumnPtr`: `built_path` stays false and 
neither seek/materialization timer runs. These unconditional updates 
nevertheless add the full stored byte count (and rows) again, although 
`VariantDirectResidualSeekBytes` is documented as bytes copied to the result. 
Repeated evaluation can therefore inflate reported work arbitrarily while seek 
time and `MultiPathPathRows` stay flat—the new repeated-`b` test already 
codifies 9 general rows for only 6 built path rows. Gate the work counters on 
`built_path` (and use a separate request/cache-hit counter if served-result 
frequency is useful).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to