This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 07f911248e6 [opt](build) Declare extern template for existing explicit 
instantiations (#66807)
07f911248e6 is described below

commit 07f911248e65f785510ac0d039609b0229f688f1
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Mon Aug 17 11:02:32 2026 +0800

    [opt](build) Declare extern template for existing explicit instantiations 
(#66807)
    
    > Part of the BE build-time optimization series tracked in #66715.
    >
    > Split out of **https://github.com/apache/doris/pull/66510**. With the
    include-edge
    > surgery (#66400, #66672) and the unity-build line (#66712, #66776,
    #66789) merged,
    > this PR opens the third mechanism of the batch: making the **explicit
    template
    > instantiations we already have** actually pay for themselves by
    declaring them
    > `extern template` in the headers.
    
    ### What problem does this PR solve?
    
    Related PR: #66510, #66789
    
    Problem Summary:
    
    `be/src` already contains ~221 `template class` **explicit instantiation
    definitions** (columns, DataTypes, SerDes, the operator families, …).
    But almost
    none of them are announced in the corresponding headers with an
    `extern template` declaration. The result: every consumer TU that
    touches
    `ColumnVector<T>` / `DataTypeDecimalSerDe<T>` / `AsyncWriterSink<W, P>`
    still
    **implicitly instantiates the whole class again**, compiles the member
    functions
    as weak symbols, and the linker then throws all the duplicates away. The
    explicit-instantiation TU does the same work one more time. We pay the
    template
    instantiation cost N+1 times and keep exactly one copy.
    
    `extern template` is the standard C++11 tool for this: it suppresses
    implicit
    instantiation in consumers and pins code generation to the one TU that
    already
    carries the explicit definition. **It changes symbol ownership only, not
    generated code** — a consumer TU compiled before/after this PR produces
    byte-identical code for its own functions (verified on a control TU
    during the
    original measurement round).
    
    What the commits do:
    
    1. **Column classes** (`column_vector.h` 18, `column_decimal.h` 5,
    `column_string.h` 2): declare extern the 25 instantiations defined in
    the
       matching `.cpp` files.
    2. **DataType / SerDe surface** (6 headers): 47 externs for the
       date/datetime/decimal/number/string SerDe instantiation sets.
    3. **Exec operator families** (39 headers, 99 externs):
    `AsyncWriterSink`,
    `DataSinkOperatorX`, `OperatorX`, partitioners,
    aggregation/table-function
    operators — all instantiated centrally (mostly in `operator.cpp`) since
    the
       operator refactor, never externed.
    4. **Narrow surfaces** (17 headers, 75 externs): parquet/orc readers,
    segment
       iterators, frame-of-reference coding, phrase queries, JSON parser.
    5. **`DataTypeNumber<T>`**: the base class was explicitly instantiated
    but the
    derived class itself was not — instantiations existed nowhere, so every
    user
       built the full class. Adds the 8 explicit definitions in
       `data_type_number_base.cpp` plus matching externs.
    6. **One-line correctness fix** the externs exposed:
    `inverted_index_writer.h`
    forward-declared `CppTypeTraits` itself; triggering class-level
    instantiation
    from the extern requires the real definition, and exactly one storage
    unity
       batch (of 13k+ TUs) lacked it transitively. Include `storage/types.h`
       directly.
    
    ### Measured results
    
    Numbers below were taken on the original development branch **before the
    unity
    line landed** (macOS arm64, clang 20, `-j6`, no PCH for the sentinel
    probes),
    because that is where the mechanism was isolated. Landing after unity
    (#66789), part of the win is already absorbed — sibling files inside one
    unity
    batch share a single implicit instantiation — so the remaining surface
    here is
    the SKIP-listed heavy individual TUs, cross-batch dedup, and the BE UT
    tree:
    
    | metric | before | after |
    |---|---|---|
    | full cold build (`-j6`) | 33m15s | **32m36s (−2.0%)** |
    | `multiply.cpp` sentinel TU (no PCH) | 78.7s | **73.0s (−7.3%)** |
    | `plus.cpp` sentinel TU (no PCH) | 56.3s | **52.0s (−7.6%)** |
    | weak-symbol overlap multiply∩plus | 1552 | **491 (−68%)** |
    | `doris_be` size (pre-unity layout) | 1856MB | **1809MB (−2.5%)** |
    
    Validation of this PR's tree (master + these 6 commits, macOS arm64
    clang20,
    unity=ON + PCH=ON):
    
    - full BE build: 7446/7446 edges, **zero failures**, `doris_be` links at
    319MB
      (same as current master);
    - static pairing audit: all **266 `extern template` declarations** added
    here
    resolve to an existing explicit instantiation definition in the current
    tree;
    - BE UT (`BUILD_TYPE_UT=Debug`): 8501/8501 edges compiled,
    `doris_be_test`
    links with **zero duplicate/undefined symbols** — the sensitive surface
    for
    an extern-template change, since tests link the full static-library set;
    - `git clang-format` clean against master.
    
    ### Methodology, and what we deliberately did NOT extern
    
    The go/no-go gauge for each candidate was **weak symbols owned by
    consumer
    `.o` files** (`llvm-nm -C | grep ' [VvWw] '` filtered by the class
    prefix), not
    the count of instantiation statements. By that gauge three whole
    families were
    rejected as free-of-benefit and are intentionally absent here:
    
    - `Allocator` (48 instantiation sites): consumers own ≈0 weak symbols of
    it;
    - `PODArray`: same;
    - `COWHelper` base-class instantiations: same.
    
    Three further individual candidates were dropped because their include
    topology would have needed real surgery for a mechanism whose gain there
    is ≈0.
    
    ### Risks / disclosures
    
    - **Runtime impact: none by construction.** `extern template` moves
    symbol
    ownership; it does not change what code is generated for the anchor TU,
    and
    inline/constexpr members remain inlinable at call sites exactly as
    before.
    - **Cross-platform**: all local validation is macOS/clang20. gcc handles
      `extern template` + in-class-defined members slightly differently in
      diagnostics; the Performance pipeline (the only gcc lane) is the
      authoritative check. Please watch its first round.
    - The `DORIS_DEV_DEBUG_INFO` developer knob that rode along in the
    original
    branch is intentionally **not** in this PR (unrelated mechanism, will be
      proposed separately).
    
    ---------
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 be/src/core/column/column_decimal.h                |  7 ++++
 be/src/core/column/column_string.h                 |  5 +++
 be/src/core/column/column_vector.h                 | 20 +++++++++++
 be/src/core/data_type/data_type_decimal.h          |  7 ++++
 be/src/core/data_type/data_type_number.h           | 10 ++++++
 be/src/core/data_type/data_type_number_base.cpp    | 10 ++++++
 be/src/core/data_type/data_type_number_base.h      | 19 ++++++++++
 .../data_type_date_or_datetime_serde.h             |  6 ++++
 .../core/data_type_serde/data_type_decimal_serde.h | 10 ++++--
 .../core/data_type_serde/data_type_number_serde.h  | 18 ++++++++++
 .../core/data_type_serde/data_type_string_serde.h  |  6 ++++
 be/src/core/value/vdatetime_value.h                |  5 +++
 be/src/exec/operator/analytic_sink_operator.h      |  4 +++
 be/src/exec/operator/assert_num_rows_operator.h    |  3 ++
 .../distinct_streaming_aggregation_operator.h      |  3 ++
 be/src/exec/operator/file_scan_operator.h          |  4 +++
 be/src/exec/operator/group_commit_scan_operator.h  |  4 +++
 be/src/exec/operator/hashjoin_build_sink.h         |  5 +++
 be/src/exec/operator/hashjoin_probe_operator.h     |  6 ++++
 be/src/exec/operator/hive_table_sink_operator.h    |  3 ++
 .../exec/operator/iceberg_delete_sink_operator.h   |  3 ++
 be/src/exec/operator/iceberg_merge_sink_operator.h |  3 ++
 be/src/exec/operator/iceberg_table_sink_operator.h |  3 ++
 be/src/exec/operator/jdbc_scan_operator.h          |  4 +++
 be/src/exec/operator/jdbc_table_sink_operator.h    |  3 ++
 be/src/exec/operator/materialization_opertor.h     |  3 ++
 .../exec/operator/maxcompute_table_sink_operator.h |  3 ++
 be/src/exec/operator/meta_scan_operator.h          |  4 +++
 be/src/exec/operator/mock_scan_operator.h          |  5 +++
 .../operator/nested_loop_join_build_operator.h     |  6 ++++
 .../operator/nested_loop_join_probe_operator.h     |  6 ++++
 be/src/exec/operator/olap_scan_operator.h          |  4 +++
 be/src/exec/operator/olap_table_sink_operator.h    |  3 ++
 be/src/exec/operator/olap_table_sink_v2_operator.h |  3 ++
 be/src/exec/operator/operator.h                    | 40 ++++++++++++++++++++++
 .../partitioned_hash_join_probe_operator.h         |  7 ++++
 .../operator/partitioned_hash_join_sink_operator.h |  6 ++++
 .../exec/operator/rec_cte_anchor_sink_operator.h   |  3 ++
 be/src/exec/operator/rec_cte_sink_operator.h       |  3 ++
 be/src/exec/operator/rec_cte_source_operator.h     |  3 ++
 be/src/exec/operator/repeat_operator.h             |  3 ++
 be/src/exec/operator/result_file_sink_operator.h   |  3 ++
 be/src/exec/operator/select_operator.h             |  3 ++
 be/src/exec/operator/set_probe_sink_operator.h     |  7 ++++
 be/src/exec/operator/set_sink_operator.h           |  6 ++++
 be/src/exec/operator/set_source_operator.h         |  7 ++++
 .../operator/spill_iceberg_table_sink_operator.h   |  3 ++
 .../exec/operator/streaming_aggregation_operator.h |  3 ++
 be/src/exec/operator/table_function_operator.h     |  3 ++
 be/src/exec/operator/tvf_table_sink_operator.h     |  3 ++
 be/src/exec/partitioner/partitioner.h              |  5 +++
 be/src/exprs/table_function/vjson_each.h           |  4 +++
 .../format/parquet/vparquet_column_chunk_reader.h  |  6 ++++
 be/src/format/parquet/vparquet_column_reader.h     |  6 ++++
 be/src/format/parquet/vparquet_page_reader.h       |  6 ++++
 .../parquet/reader/native/column_chunk_reader.h    |  6 ++++
 .../parquet/reader/native/column_reader.h          |  6 ++++
 .../format_v2/parquet/reader/native/page_reader.h  |  6 ++++
 be/src/storage/cache/page_cache.h                  |  3 ++
 .../storage/index/inverted/inverted_index_writer.h | 30 ++++++++++++++--
 .../query_v2/boolean_query/occur_boolean_weight.h  |  5 +++
 .../index/inverted/query_v2/disjunction_scorer.h   |  5 +++
 .../index/inverted/query_v2/exclude_scorer.h       |  3 ++
 .../inverted/query_v2/phrase_query/phrase_scorer.h |  4 +++
 .../index/inverted/query_v2/union/simple_union.h   |  5 +++
 be/src/util/frame_of_reference_coding.h            | 28 +++++++++++++++
 be/src/util/json/json_parser.h                     |  4 +++
 67 files changed, 438 insertions(+), 5 deletions(-)

diff --git a/be/src/core/column/column_decimal.h 
b/be/src/core/column/column_decimal.h
index 9d6ec34c8b8..8cd7be991a7 100644
--- a/be/src/core/column/column_decimal.h
+++ b/be/src/core/column/column_decimal.h
@@ -306,4 +306,11 @@ using ColumnDecimal128V2 = ColumnDecimal<TYPE_DECIMALV2>;
 using ColumnDecimal128V3 = ColumnDecimal<TYPE_DECIMAL128I>;
 using ColumnDecimal256 = ColumnDecimal<TYPE_DECIMAL256>;
 
+/// Instantiated once in column_decimal.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ColumnDecimal<TYPE_DECIMAL32>;
+extern template class ColumnDecimal<TYPE_DECIMAL64>;
+extern template class ColumnDecimal<TYPE_DECIMALV2>;
+extern template class ColumnDecimal<TYPE_DECIMAL128I>;
+extern template class ColumnDecimal<TYPE_DECIMAL256>;
+
 } // namespace doris
diff --git a/be/src/core/column/column_string.h 
b/be/src/core/column/column_string.h
index 616d6ef9df3..54d224c0c22 100644
--- a/be/src/core/column/column_string.h
+++ b/be/src/core/column/column_string.h
@@ -656,4 +656,9 @@ public:
 
 using ColumnString = ColumnStr<UInt32>;
 using ColumnString64 = ColumnStr<UInt64>;
+
+/// Instantiated once in column_string.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ColumnStr<UInt32>;
+extern template class ColumnStr<UInt64>;
+
 } // namespace doris
diff --git a/be/src/core/column/column_vector.h 
b/be/src/core/column/column_vector.h
index 4f3a7a6c46f..5c6b6f294f5 100644
--- a/be/src/core/column/column_vector.h
+++ b/be/src/core/column/column_vector.h
@@ -446,4 +446,24 @@ using ColumnTimeStampTz = ColumnVector<TYPE_TIMESTAMPTZ>;
 using ColumnOffset32 = ColumnVector<TYPE_UINT32>;
 using ColumnOffset64 = ColumnVector<TYPE_UINT64>;
 
+/// Instantiated once in column_vector.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ColumnVector<TYPE_BOOLEAN>;
+extern template class ColumnVector<TYPE_TINYINT>;
+extern template class ColumnVector<TYPE_SMALLINT>;
+extern template class ColumnVector<TYPE_INT>;
+extern template class ColumnVector<TYPE_BIGINT>;
+extern template class ColumnVector<TYPE_LARGEINT>;
+extern template class ColumnVector<TYPE_FLOAT>;
+extern template class ColumnVector<TYPE_DOUBLE>;
+extern template class ColumnVector<TYPE_IPV4>;
+extern template class ColumnVector<TYPE_IPV6>;
+extern template class ColumnVector<TYPE_DATE>;
+extern template class ColumnVector<TYPE_DATEV2>;
+extern template class ColumnVector<TYPE_DATETIME>;
+extern template class ColumnVector<TYPE_DATETIMEV2>;
+extern template class ColumnVector<TYPE_TIMEV2>;
+extern template class ColumnVector<TYPE_TIMESTAMPTZ>;
+extern template class ColumnVector<TYPE_UINT32>;
+extern template class ColumnVector<TYPE_UINT64>;
+
 } // namespace doris
diff --git a/be/src/core/data_type/data_type_decimal.h 
b/be/src/core/data_type/data_type_decimal.h
index 69fae16be82..a863316cbce 100644
--- a/be/src/core/data_type/data_type_decimal.h
+++ b/be/src/core/data_type/data_type_decimal.h
@@ -526,4 +526,11 @@ 
static_assert(!has_original_precision_and_scale<DataTypeDecimal64>);
 static_assert(!has_original_precision_and_scale<DataTypeDecimal128>);
 static_assert(!has_original_precision_and_scale<DataTypeDecimal256>);
 
+/// Instantiated once in data_type_decimal.cpp; suppresses per-TU implicit 
instantiation.
+extern template class DataTypeDecimal<TYPE_DECIMAL32>;
+extern template class DataTypeDecimal<TYPE_DECIMAL64>;
+extern template class DataTypeDecimal<TYPE_DECIMALV2>;
+extern template class DataTypeDecimal<TYPE_DECIMAL128I>;
+extern template class DataTypeDecimal<TYPE_DECIMAL256>;
+
 } // namespace doris
diff --git a/be/src/core/data_type/data_type_number.h 
b/be/src/core/data_type/data_type_number.h
index 99b8bb42880..87d9ae925c7 100644
--- a/be/src/core/data_type/data_type_number.h
+++ b/be/src/core/data_type/data_type_number.h
@@ -77,4 +77,14 @@ inline constexpr bool IsDataTypeFloat<DataTypeFloat32> = 
true;
 template <>
 inline constexpr bool IsDataTypeFloat<DataTypeFloat64> = true;
 
+/// Instantiated once in data_type_number_base.cpp; suppresses per-TU implicit 
instantiation.
+extern template class DataTypeNumber<TYPE_BOOLEAN>;
+extern template class DataTypeNumber<TYPE_TINYINT>;
+extern template class DataTypeNumber<TYPE_SMALLINT>;
+extern template class DataTypeNumber<TYPE_INT>;
+extern template class DataTypeNumber<TYPE_BIGINT>;
+extern template class DataTypeNumber<TYPE_LARGEINT>;
+extern template class DataTypeNumber<TYPE_FLOAT>;
+extern template class DataTypeNumber<TYPE_DOUBLE>;
+
 } // namespace doris
diff --git a/be/src/core/data_type/data_type_number_base.cpp 
b/be/src/core/data_type/data_type_number_base.cpp
index dcd167bce1d..5f60f7afcbb 100644
--- a/be/src/core/data_type/data_type_number_base.cpp
+++ b/be/src/core/data_type/data_type_number_base.cpp
@@ -36,6 +36,7 @@
 #include "core/column/column.h"
 #include "core/column/column_const.h"
 #include "core/column/column_vector.h"
+#include "core/data_type/data_type_number.h"
 #include "core/data_type/primitive_type.h"
 #include "core/string_buffer.hpp"
 #include "core/types.h"
@@ -208,4 +209,13 @@ template class DataTypeNumberBase<TYPE_IPV6>;
 template class DataTypeNumberBase<TYPE_TIMEV2>;
 template class DataTypeNumberBase<TYPE_TIMESTAMPTZ>;
 
+template class DataTypeNumber<TYPE_BOOLEAN>;
+template class DataTypeNumber<TYPE_TINYINT>;
+template class DataTypeNumber<TYPE_SMALLINT>;
+template class DataTypeNumber<TYPE_INT>;
+template class DataTypeNumber<TYPE_BIGINT>;
+template class DataTypeNumber<TYPE_LARGEINT>;
+template class DataTypeNumber<TYPE_FLOAT>;
+template class DataTypeNumber<TYPE_DOUBLE>;
+
 } // namespace doris
diff --git a/be/src/core/data_type/data_type_number_base.h 
b/be/src/core/data_type/data_type_number_base.h
index f3fe2544196..63fd4968583 100644
--- a/be/src/core/data_type/data_type_number_base.h
+++ b/be/src/core/data_type/data_type_number_base.h
@@ -94,4 +94,23 @@ protected:
 private:
     bool _is_null_literal = false;
 };
+
+/// Instantiated once in data_type_number_base.cpp; suppresses per-TU implicit 
instantiation.
+extern template class DataTypeNumberBase<TYPE_BOOLEAN>;
+extern template class DataTypeNumberBase<TYPE_TINYINT>;
+extern template class DataTypeNumberBase<TYPE_SMALLINT>;
+extern template class DataTypeNumberBase<TYPE_INT>;
+extern template class DataTypeNumberBase<TYPE_BIGINT>;
+extern template class DataTypeNumberBase<TYPE_LARGEINT>;
+extern template class DataTypeNumberBase<TYPE_FLOAT>;
+extern template class DataTypeNumberBase<TYPE_DOUBLE>;
+extern template class DataTypeNumberBase<TYPE_DATE>;
+extern template class DataTypeNumberBase<TYPE_DATEV2>;
+extern template class DataTypeNumberBase<TYPE_DATETIME>;
+extern template class DataTypeNumberBase<TYPE_DATETIMEV2>;
+extern template class DataTypeNumberBase<TYPE_IPV4>;
+extern template class DataTypeNumberBase<TYPE_IPV6>;
+extern template class DataTypeNumberBase<TYPE_TIMEV2>;
+extern template class DataTypeNumberBase<TYPE_TIMESTAMPTZ>;
+
 } // namespace doris
diff --git a/be/src/core/data_type_serde/data_type_date_or_datetime_serde.h 
b/be/src/core/data_type_serde/data_type_date_or_datetime_serde.h
index 693bfca7385..e8ce3f41069 100644
--- a/be/src/core/data_type_serde/data_type_date_or_datetime_serde.h
+++ b/be/src/core/data_type_serde/data_type_date_or_datetime_serde.h
@@ -145,4 +145,10 @@ public:
     Status read_column_from_arrow(IColumn& column, const arrow::Array* 
arrow_array, int64_t start,
                                   int64_t end, const cctz::time_zone& ctz) 
const override;
 };
+
+/// Instantiated once in data_type_date_or_datetime_serde.cpp; suppresses 
per-TU implicit
+/// instantiation.
+extern template class DataTypeDateSerDe<TYPE_DATE>;
+extern template class DataTypeDateSerDe<TYPE_DATETIME>;
+
 } // namespace doris
diff --git a/be/src/core/data_type_serde/data_type_decimal_serde.h 
b/be/src/core/data_type_serde/data_type_decimal_serde.h
index b475923c83f..424c837a7ca 100644
--- a/be/src/core/data_type_serde/data_type_decimal_serde.h
+++ b/be/src/core/data_type_serde/data_type_decimal_serde.h
@@ -25,6 +25,7 @@
 #include "common/status.h"
 #include "core/column/column.h"
 #include "core/column/column_const.h"
+#include "core/column/column_decimal.h"
 #include "core/data_type/define_primitive_type.h"
 #include "core/data_type_serde/data_type_serde.h"
 #include "core/string_ref.h"
@@ -32,8 +33,6 @@
 
 namespace doris {
 
-template <PrimitiveType T>
-class ColumnDecimal;
 class Arena;
 
 template <PrimitiveType T>
@@ -219,4 +218,11 @@ Status 
DataTypeDecimalSerDe<T>::read_column_from_pb(IColumn& column, const PValu
     return Status::OK();
 }
 
+/// Instantiated once in data_type_decimal_serde.cpp; suppresses per-TU 
implicit instantiation.
+extern template class DataTypeDecimalSerDe<TYPE_DECIMAL32>;
+extern template class DataTypeDecimalSerDe<TYPE_DECIMAL64>;
+extern template class DataTypeDecimalSerDe<TYPE_DECIMAL128I>;
+extern template class DataTypeDecimalSerDe<TYPE_DECIMALV2>;
+extern template class DataTypeDecimalSerDe<TYPE_DECIMAL256>;
+
 } // namespace doris
diff --git a/be/src/core/data_type_serde/data_type_number_serde.h 
b/be/src/core/data_type_serde/data_type_number_serde.h
index 9c0de8cb0c0..2090a5d936a 100644
--- a/be/src/core/data_type_serde/data_type_number_serde.h
+++ b/be/src/core/data_type_serde/data_type_number_serde.h
@@ -348,4 +348,22 @@ Status DataTypeNumberSerDe<T>::write_column_to_pb(const 
IColumn& column, PValues
     return Status::OK();
 }
 
+/// Instantiated once in data_type_number_serde.cpp; suppresses per-TU 
implicit instantiation.
+extern template class DataTypeNumberSerDe<TYPE_BOOLEAN>;
+extern template class DataTypeNumberSerDe<TYPE_TINYINT>;
+extern template class DataTypeNumberSerDe<TYPE_SMALLINT>;
+extern template class DataTypeNumberSerDe<TYPE_INT>;
+extern template class DataTypeNumberSerDe<TYPE_BIGINT>;
+extern template class DataTypeNumberSerDe<TYPE_LARGEINT>;
+extern template class DataTypeNumberSerDe<TYPE_FLOAT>;
+extern template class DataTypeNumberSerDe<TYPE_DOUBLE>;
+extern template class DataTypeNumberSerDe<TYPE_DATE>;
+extern template class DataTypeNumberSerDe<TYPE_DATEV2>;
+extern template class DataTypeNumberSerDe<TYPE_DATETIME>;
+extern template class DataTypeNumberSerDe<TYPE_DATETIMEV2>;
+extern template class DataTypeNumberSerDe<TYPE_IPV4>;
+extern template class DataTypeNumberSerDe<TYPE_IPV6>;
+extern template class DataTypeNumberSerDe<TYPE_TIMEV2>;
+extern template class DataTypeNumberSerDe<TYPE_TIMESTAMPTZ>;
+
 } // namespace doris
diff --git a/be/src/core/data_type_serde/data_type_string_serde.h 
b/be/src/core/data_type_serde/data_type_string_serde.h
index c81f6d37aa4..5a95816243a 100644
--- a/be/src/core/data_type_serde/data_type_string_serde.h
+++ b/be/src/core/data_type_serde/data_type_string_serde.h
@@ -282,4 +282,10 @@ private:
 
 using DataTypeStringSerDe = DataTypeStringSerDeBase<ColumnString>;
 using DataTypeFixedLengthObjectSerDe = 
DataTypeStringSerDeBase<ColumnFixedLengthObject>;
+
+/// Instantiated once in data_type_string_serde.cpp; suppresses per-TU 
implicit instantiation.
+extern template class DataTypeStringSerDeBase<ColumnString>;
+extern template class DataTypeStringSerDeBase<ColumnString64>;
+extern template class DataTypeStringSerDeBase<ColumnFixedLengthObject>;
+
 } // namespace doris
diff --git a/be/src/core/value/vdatetime_value.h 
b/be/src/core/value/vdatetime_value.h
index da0bba19bcb..e906c4f842a 100644
--- a/be/src/core/value/vdatetime_value.h
+++ b/be/src/core/value/vdatetime_value.h
@@ -1804,6 +1804,11 @@ struct DateTraits<uint64_t> {
     using DateType = DataTypeDateTimeV2;
 };
 #include "common/compile_check_avoid_end.h"
+
+/// Instantiated once in vdatetime_value.cpp; suppresses per-TU implicit 
instantiation.
+extern template class DateV2Value<DateV2ValueType>;
+extern template class DateV2Value<DateTimeV2ValueType>;
+
 } // namespace doris
 
 template <>
diff --git a/be/src/exec/operator/analytic_sink_operator.h 
b/be/src/exec/operator/analytic_sink_operator.h
index 488bdc156f0..dfed9476b49 100644
--- a/be/src/exec/operator/analytic_sink_operator.h
+++ b/be/src/exec/operator/analytic_sink_operator.h
@@ -267,4 +267,8 @@ private:
     std::vector<bool> _change_to_nullable_flags;
 };
 
+/// Instantiated once in analytic_sink_operator.cpp; suppresses per-TU implicit
+/// instantiation.
+extern template class DataSinkOperatorX<AnalyticSinkLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/assert_num_rows_operator.h 
b/be/src/exec/operator/assert_num_rows_operator.h
index 4c71266c626..0a7417abffc 100644
--- a/be/src/exec/operator/assert_num_rows_operator.h
+++ b/be/src/exec/operator/assert_num_rows_operator.h
@@ -59,4 +59,7 @@ private:
     bool _should_convert_output_to_nullable;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class StreamingOperatorX<AssertNumRowsLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/distinct_streaming_aggregation_operator.h 
b/be/src/exec/operator/distinct_streaming_aggregation_operator.h
index a5c2f46c267..3d5304aff1e 100644
--- a/be/src/exec/operator/distinct_streaming_aggregation_operator.h
+++ b/be/src/exec/operator/distinct_streaming_aggregation_operator.h
@@ -161,4 +161,7 @@ private:
     bool _is_streaming_preagg = false;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class StatefulOperatorX<DistinctStreamingAggLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/file_scan_operator.h 
b/be/src/exec/operator/file_scan_operator.h
index 7d8fae51b78..ac422a4e6af 100644
--- a/be/src/exec/operator/file_scan_operator.h
+++ b/be/src/exec/operator/file_scan_operator.h
@@ -132,4 +132,8 @@ private:
     bool _batch_split_mode = false;
 };
 
+/// Instantiated once in scan_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ScanOperatorX<FileScanLocalState>;
+extern template class ScanLocalState<FileScanLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/group_commit_scan_operator.h 
b/be/src/exec/operator/group_commit_scan_operator.h
index 679b46b1125..0b43554c673 100644
--- a/be/src/exec/operator/group_commit_scan_operator.h
+++ b/be/src/exec/operator/group_commit_scan_operator.h
@@ -61,4 +61,8 @@ protected:
     const int64_t _table_id;
 };
 
+/// Instantiated once in scan_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ScanOperatorX<GroupCommitLocalState>;
+extern template class ScanLocalState<GroupCommitLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/hashjoin_build_sink.h 
b/be/src/exec/operator/hashjoin_build_sink.h
index 3550f77c752..a7df04eddb8 100644
--- a/be/src/exec/operator/hashjoin_build_sink.h
+++ b/be/src/exec/operator/hashjoin_build_sink.h
@@ -277,4 +277,9 @@ private:
     RuntimeState* _state = nullptr;
 };
 
+/// Instantiated once in join_build_sink_operator.cpp; suppresses per-TU 
implicit
+/// instantiation.
+extern template class JoinBuildSinkOperatorX<HashJoinBuildSinkLocalState>;
+extern template class JoinBuildSinkLocalState<HashJoinSharedState, 
HashJoinBuildSinkLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/hashjoin_probe_operator.h 
b/be/src/exec/operator/hashjoin_probe_operator.h
index 2542efe9c88..903a9209c46 100644
--- a/be/src/exec/operator/hashjoin_probe_operator.h
+++ b/be/src/exec/operator/hashjoin_probe_operator.h
@@ -220,4 +220,10 @@ private:
     size_t _right_col_idx;
 };
 
+/// Instantiated once in operator.cpp / join_probe_operator.cpp; suppresses 
per-TU
+/// implicit instantiation.
+extern template class StatefulOperatorX<HashJoinProbeLocalState>;
+extern template class JoinProbeLocalState<HashJoinSharedState, 
HashJoinProbeLocalState>;
+extern template class JoinProbeOperatorX<HashJoinProbeLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/hive_table_sink_operator.h 
b/be/src/exec/operator/hive_table_sink_operator.h
index 51161809e68..ffb331064bf 100644
--- a/be/src/exec/operator/hive_table_sink_operator.h
+++ b/be/src/exec/operator/hive_table_sink_operator.h
@@ -83,4 +83,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VHiveTableWriter, 
HiveTableSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/iceberg_delete_sink_operator.h 
b/be/src/exec/operator/iceberg_delete_sink_operator.h
index 12f93bfc8b6..25167f4236e 100644
--- a/be/src/exec/operator/iceberg_delete_sink_operator.h
+++ b/be/src/exec/operator/iceberg_delete_sink_operator.h
@@ -82,4 +82,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VIcebergDeleteSink, 
IcebergDeleteSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/iceberg_merge_sink_operator.h 
b/be/src/exec/operator/iceberg_merge_sink_operator.h
index 0cf64681c1d..5d48911ad8e 100644
--- a/be/src/exec/operator/iceberg_merge_sink_operator.h
+++ b/be/src/exec/operator/iceberg_merge_sink_operator.h
@@ -81,4 +81,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VIcebergMergeSink, 
IcebergMergeSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/iceberg_table_sink_operator.h 
b/be/src/exec/operator/iceberg_table_sink_operator.h
index 0dec306edeb..a91950af7a7 100644
--- a/be/src/exec/operator/iceberg_table_sink_operator.h
+++ b/be/src/exec/operator/iceberg_table_sink_operator.h
@@ -82,4 +82,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VIcebergTableWriter, 
IcebergTableSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/jdbc_scan_operator.h 
b/be/src/exec/operator/jdbc_scan_operator.h
index feb11ff331a..696da3df26e 100644
--- a/be/src/exec/operator/jdbc_scan_operator.h
+++ b/be/src/exec/operator/jdbc_scan_operator.h
@@ -61,4 +61,8 @@ private:
     bool _is_tvf;
 };
 
+/// Instantiated once in scan_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ScanOperatorX<JDBCScanLocalState>;
+extern template class ScanLocalState<JDBCScanLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/jdbc_table_sink_operator.h 
b/be/src/exec/operator/jdbc_table_sink_operator.h
index a557ec80a8d..1c339119671 100644
--- a/be/src/exec/operator/jdbc_table_sink_operator.h
+++ b/be/src/exec/operator/jdbc_table_sink_operator.h
@@ -58,4 +58,7 @@ private:
     VExprContextSPtrs _output_vexpr_ctxs;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VJdbcTableWriter, 
JdbcTableSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/materialization_opertor.h 
b/be/src/exec/operator/materialization_opertor.h
index 7dfdf69f823..1390aae0bdc 100644
--- a/be/src/exec/operator/materialization_opertor.h
+++ b/be/src/exec/operator/materialization_opertor.h
@@ -151,4 +151,7 @@ private:
     VExprContextSPtrs _rowid_exprs;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class StatefulOperatorX<MaterializationLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/maxcompute_table_sink_operator.h 
b/be/src/exec/operator/maxcompute_table_sink_operator.h
index 3332143080b..c1aebf8004f 100644
--- a/be/src/exec/operator/maxcompute_table_sink_operator.h
+++ b/be/src/exec/operator/maxcompute_table_sink_operator.h
@@ -80,4 +80,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VMCTableWriter, MCTableSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/meta_scan_operator.h 
b/be/src/exec/operator/meta_scan_operator.h
index 05829c76a19..e14e9282f4f 100644
--- a/be/src/exec/operator/meta_scan_operator.h
+++ b/be/src/exec/operator/meta_scan_operator.h
@@ -63,4 +63,8 @@ private:
     TUserIdentity _user_identity;
 };
 
+/// Instantiated once in scan_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ScanOperatorX<MetaScanLocalState>;
+extern template class ScanLocalState<MetaScanLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/mock_scan_operator.h 
b/be/src/exec/operator/mock_scan_operator.h
index 3eaa78366a8..609e631ce8c 100644
--- a/be/src/exec/operator/mock_scan_operator.h
+++ b/be/src/exec/operator/mock_scan_operator.h
@@ -102,5 +102,10 @@ public:
 private:
     std::list<Block> _output_blocks;
 };
+
+/// Instantiated once in scan_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ScanOperatorX<MockScanLocalState>;
+extern template class ScanLocalState<MockScanLocalState>;
+
 } // namespace doris
 #endif
diff --git a/be/src/exec/operator/nested_loop_join_build_operator.h 
b/be/src/exec/operator/nested_loop_join_build_operator.h
index 6001d05af29..ba91a60486b 100644
--- a/be/src/exec/operator/nested_loop_join_build_operator.h
+++ b/be/src/exec/operator/nested_loop_join_build_operator.h
@@ -82,4 +82,10 @@ private:
     RowDescriptor _row_descriptor;
 };
 
+/// Instantiated once in join_build_sink_operator.cpp; suppresses per-TU 
implicit
+/// instantiation.
+extern template class 
JoinBuildSinkOperatorX<NestedLoopJoinBuildSinkLocalState>;
+extern template class JoinBuildSinkLocalState<NestedLoopJoinSharedState,
+                                              
NestedLoopJoinBuildSinkLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/nested_loop_join_probe_operator.h 
b/be/src/exec/operator/nested_loop_join_probe_operator.h
index 02a51e91dbc..b9d283c18ad 100644
--- a/be/src/exec/operator/nested_loop_join_probe_operator.h
+++ b/be/src/exec/operator/nested_loop_join_probe_operator.h
@@ -308,4 +308,10 @@ private:
     std::set<int> _materialize_column_ids;
 };
 
+/// Instantiated once in operator.cpp / join_probe_operator.cpp; suppresses 
per-TU
+/// implicit instantiation.
+extern template class StatefulOperatorX<NestedLoopJoinProbeLocalState>;
+extern template class JoinProbeLocalState<NestedLoopJoinSharedState, 
NestedLoopJoinProbeLocalState>;
+extern template class JoinProbeOperatorX<NestedLoopJoinProbeLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/olap_scan_operator.h 
b/be/src/exec/operator/olap_scan_operator.h
index 9f7ddca0527..46c65f06286 100644
--- a/be/src/exec/operator/olap_scan_operator.h
+++ b/be/src/exec/operator/olap_scan_operator.h
@@ -394,4 +394,8 @@ private:
     TabletSchemaSPtr _tablet_schema;
 };
 
+/// Instantiated once in scan_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ScanOperatorX<OlapScanLocalState>;
+extern template class ScanLocalState<OlapScanLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/olap_table_sink_operator.h 
b/be/src/exec/operator/olap_table_sink_operator.h
index 9567b82e082..aad18fa3318 100644
--- a/be/src/exec/operator/olap_table_sink_operator.h
+++ b/be/src/exec/operator/olap_table_sink_operator.h
@@ -75,4 +75,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VTabletWriter, OlapTableSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/olap_table_sink_v2_operator.h 
b/be/src/exec/operator/olap_table_sink_v2_operator.h
index 038484c83ee..7ba63a1aad2 100644
--- a/be/src/exec/operator/olap_table_sink_v2_operator.h
+++ b/be/src/exec/operator/olap_table_sink_v2_operator.h
@@ -81,4 +81,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VTabletWriterV2, 
OlapTableSinkV2OperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/operator.h b/be/src/exec/operator/operator.h
index bb5cab376e6..5e23f737509 100644
--- a/be/src/exec/operator/operator.h
+++ b/be/src/exec/operator/operator.h
@@ -1260,4 +1260,44 @@ private:
 };
 #endif
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class PipelineXSinkLocalState<HashJoinSharedState>;
+extern template class PipelineXSinkLocalState<PartitionedHashJoinSharedState>;
+extern template class PipelineXSinkLocalState<SortSharedState>;
+extern template class PipelineXSinkLocalState<SpillSortSharedState>;
+extern template class PipelineXSinkLocalState<NestedLoopJoinSharedState>;
+extern template class PipelineXSinkLocalState<AnalyticSharedState>;
+extern template class PipelineXSinkLocalState<AggSharedState>;
+extern template class PipelineXSinkLocalState<BucketedAggSharedState>;
+extern template class PipelineXSinkLocalState<PartitionedAggSharedState>;
+extern template class PipelineXSinkLocalState<FakeSharedState>;
+extern template class PipelineXSinkLocalState<UnionSharedState>;
+extern template class PipelineXSinkLocalState<PartitionSortNodeSharedState>;
+extern template class PipelineXSinkLocalState<MultiCastSharedState>;
+extern template class PipelineXSinkLocalState<SetSharedState>;
+extern template class PipelineXSinkLocalState<LocalExchangeSharedState>;
+extern template class PipelineXSinkLocalState<BasicSharedState>;
+extern template class PipelineXSinkLocalState<DataQueueSharedState>;
+extern template class PipelineXLocalState<HashJoinSharedState>;
+extern template class PipelineXLocalState<PartitionedHashJoinSharedState>;
+extern template class PipelineXLocalState<SortSharedState>;
+extern template class PipelineXLocalState<SpillSortSharedState>;
+extern template class PipelineXLocalState<NestedLoopJoinSharedState>;
+extern template class PipelineXLocalState<AnalyticSharedState>;
+extern template class PipelineXLocalState<AggSharedState>;
+extern template class PipelineXLocalState<BucketedAggSharedState>;
+extern template class PipelineXLocalState<PartitionedAggSharedState>;
+extern template class PipelineXLocalState<FakeSharedState>;
+extern template class PipelineXLocalState<UnionSharedState>;
+extern template class PipelineXLocalState<DataQueueSharedState>;
+extern template class PipelineXLocalState<MultiCastSharedState>;
+extern template class PipelineXLocalState<PartitionSortNodeSharedState>;
+extern template class PipelineXLocalState<SetSharedState>;
+extern template class PipelineXLocalState<LocalExchangeSharedState>;
+extern template class PipelineXLocalState<BasicSharedState>;
+#ifdef BE_TEST
+extern template class OperatorX<DummyOperatorLocalState>;
+extern template class DataSinkOperatorX<DummySinkLocalState>;
+#endif
+
 } // namespace doris
diff --git a/be/src/exec/operator/partitioned_hash_join_probe_operator.h 
b/be/src/exec/operator/partitioned_hash_join_probe_operator.h
index 1a3564706c0..faaceda48e3 100644
--- a/be/src/exec/operator/partitioned_hash_join_probe_operator.h
+++ b/be/src/exec/operator/partitioned_hash_join_probe_operator.h
@@ -295,4 +295,11 @@ private:
     int _repartition_max_depth = SpillRepartitioner::MAX_DEPTH;
 };
 
+/// Instantiated once in operator.cpp / join_probe_operator.cpp; suppresses 
per-TU
+/// implicit instantiation.
+extern template class StatefulOperatorX<PartitionedHashJoinProbeLocalState>;
+extern template class JoinProbeLocalState<PartitionedHashJoinSharedState,
+                                          PartitionedHashJoinProbeLocalState>;
+extern template class JoinProbeOperatorX<PartitionedHashJoinProbeLocalState>;
+
 } // namespace doris
\ No newline at end of file
diff --git a/be/src/exec/operator/partitioned_hash_join_sink_operator.h 
b/be/src/exec/operator/partitioned_hash_join_sink_operator.h
index bfa3d62a27b..4ad33dbcd05 100644
--- a/be/src/exec/operator/partitioned_hash_join_sink_operator.h
+++ b/be/src/exec/operator/partitioned_hash_join_sink_operator.h
@@ -181,4 +181,10 @@ private:
     std::unique_ptr<PartitionerBase> _partitioner;
 };
 
+/// Instantiated once in join_build_sink_operator.cpp; suppresses per-TU 
implicit
+/// instantiation.
+extern template class 
JoinBuildSinkOperatorX<PartitionedHashJoinSinkLocalState>;
+extern template class JoinBuildSinkLocalState<PartitionedHashJoinSharedState,
+                                              
PartitionedHashJoinSinkLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/rec_cte_anchor_sink_operator.h 
b/be/src/exec/operator/rec_cte_anchor_sink_operator.h
index 05e070ef470..5eb74d84073 100644
--- a/be/src/exec/operator/rec_cte_anchor_sink_operator.h
+++ b/be/src/exec/operator/rec_cte_anchor_sink_operator.h
@@ -121,4 +121,7 @@ private:
     bool _need_notify_rec_side_ready = true;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class PipelineXSinkLocalState<RecCTESharedState>;
+
 } // namespace doris
\ No newline at end of file
diff --git a/be/src/exec/operator/rec_cte_sink_operator.h 
b/be/src/exec/operator/rec_cte_sink_operator.h
index cf5d36239f6..d7dda6ceca3 100644
--- a/be/src/exec/operator/rec_cte_sink_operator.h
+++ b/be/src/exec/operator/rec_cte_sink_operator.h
@@ -97,4 +97,7 @@ private:
     VExprContextSPtrs _child_expr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class PipelineXSinkLocalState<RecCTESharedState>;
+
 } // namespace doris
\ No newline at end of file
diff --git a/be/src/exec/operator/rec_cte_source_operator.h 
b/be/src/exec/operator/rec_cte_source_operator.h
index 7f12f254922..f7f375151f8 100644
--- a/be/src/exec/operator/rec_cte_source_operator.h
+++ b/be/src/exec/operator/rec_cte_source_operator.h
@@ -324,4 +324,7 @@ private:
     bool _is_used_by_other_rec_cte = false;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class PipelineXLocalState<RecCTESharedState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/repeat_operator.h 
b/be/src/exec/operator/repeat_operator.h
index 43348d2fc5a..52f2c2fe201 100644
--- a/be/src/exec/operator/repeat_operator.h
+++ b/be/src/exec/operator/repeat_operator.h
@@ -90,4 +90,7 @@ private:
     VExprContextSPtrs _expr_ctxs;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class StatefulOperatorX<RepeatLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/result_file_sink_operator.h 
b/be/src/exec/operator/result_file_sink_operator.h
index 6151918df9b..f1dc61dae88 100644
--- a/be/src/exec/operator/result_file_sink_operator.h
+++ b/be/src/exec/operator/result_file_sink_operator.h
@@ -88,4 +88,7 @@ private:
     std::shared_ptr<ResultBlockBufferBase> _sender = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VFileResultWriter, 
ResultFileSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/select_operator.h 
b/be/src/exec/operator/select_operator.h
index 9c4fa8af1bc..f5b10763a39 100644
--- a/be/src/exec/operator/select_operator.h
+++ b/be/src/exec/operator/select_operator.h
@@ -54,4 +54,7 @@ public:
     [[nodiscard]] bool is_source() const override { return false; }
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class StreamingOperatorX<SelectLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/set_probe_sink_operator.h 
b/be/src/exec/operator/set_probe_sink_operator.h
index acf28eb0fd7..e09eac84909 100644
--- a/be/src/exec/operator/set_probe_sink_operator.h
+++ b/be/src/exec/operator/set_probe_sink_operator.h
@@ -133,4 +133,11 @@ private:
     using OperatorBase::_child;
 };
 
+/// Instantiated once in set_probe_sink_operator.cpp; suppresses per-TU 
implicit
+/// instantiation.
+extern template class SetProbeSinkLocalState<true>;
+extern template class SetProbeSinkLocalState<false>;
+extern template class SetProbeSinkOperatorX<true>;
+extern template class SetProbeSinkOperatorX<false>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/set_sink_operator.h 
b/be/src/exec/operator/set_sink_operator.h
index a49e89b7b01..ff8b568c102 100644
--- a/be/src/exec/operator/set_sink_operator.h
+++ b/be/src/exec/operator/set_sink_operator.h
@@ -149,4 +149,10 @@ private:
     const std::vector<TRuntimeFilterDesc> _runtime_filter_descs;
 };
 
+/// Instantiated once in set_sink_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class SetSinkLocalState<true>;
+extern template class SetSinkLocalState<false>;
+extern template class SetSinkOperatorX<true>;
+extern template class SetSinkOperatorX<false>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/set_source_operator.h 
b/be/src/exec/operator/set_source_operator.h
index c502c0cb2e9..d8d73de4cca 100644
--- a/be/src/exec/operator/set_source_operator.h
+++ b/be/src/exec/operator/set_source_operator.h
@@ -103,4 +103,11 @@ private:
     const size_t _child_quantity;
     const bool _is_colocate;
 };
+
+/// Instantiated once in set_source_operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class SetSourceLocalState<true>;
+extern template class SetSourceLocalState<false>;
+extern template class SetSourceOperatorX<true>;
+extern template class SetSourceOperatorX<false>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/spill_iceberg_table_sink_operator.h 
b/be/src/exec/operator/spill_iceberg_table_sink_operator.h
index bd981531896..e05d0c48164 100644
--- a/be/src/exec/operator/spill_iceberg_table_sink_operator.h
+++ b/be/src/exec/operator/spill_iceberg_table_sink_operator.h
@@ -89,4 +89,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VIcebergTableWriter, 
SpillIcebergTableSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/streaming_aggregation_operator.h 
b/be/src/exec/operator/streaming_aggregation_operator.h
index 1c57d0ca33f..48fae130213 100644
--- a/be/src/exec/operator/streaming_aggregation_operator.h
+++ b/be/src/exec/operator/streaming_aggregation_operator.h
@@ -283,4 +283,7 @@ private:
     std::vector<TExpr> _partition_exprs;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class StatefulOperatorX<StreamingAggLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/table_function_operator.h 
b/be/src/exec/operator/table_function_operator.h
index de6e546af1d..de529986c38 100644
--- a/be/src/exec/operator/table_function_operator.h
+++ b/be/src/exec/operator/table_function_operator.h
@@ -182,4 +182,7 @@ private:
     std::vector<int> _child_slot_sizes;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class StatefulOperatorX<TableFunctionLocalState>;
+
 } // namespace doris
diff --git a/be/src/exec/operator/tvf_table_sink_operator.h 
b/be/src/exec/operator/tvf_table_sink_operator.h
index e1a06e675c9..4f1954a2f27 100644
--- a/be/src/exec/operator/tvf_table_sink_operator.h
+++ b/be/src/exec/operator/tvf_table_sink_operator.h
@@ -82,4 +82,7 @@ private:
     ObjectPool* _pool = nullptr;
 };
 
+/// Instantiated once in operator.cpp; suppresses per-TU implicit 
instantiation.
+extern template class AsyncWriterSink<VTVFTableWriter, TVFTableSinkOperatorX>;
+
 } // namespace doris
diff --git a/be/src/exec/partitioner/partitioner.h 
b/be/src/exec/partitioner/partitioner.h
index aa56bf1c80e..98607c36236 100644
--- a/be/src/exec/partitioner/partitioner.h
+++ b/be/src/exec/partitioner/partitioner.h
@@ -191,4 +191,9 @@ private:
     }
 };
 
+/// Instantiated once in partitioner.cpp; suppresses per-TU implicit 
instantiation.
+extern template class Crc32HashPartitioner<ShuffleChannelIds>;
+extern template class Crc32HashPartitioner<SpillPartitionChannelIds>;
+extern template class Crc32HashPartitioner<SpillRePartitionChannelIds>;
+
 } // namespace doris
diff --git a/be/src/exprs/table_function/vjson_each.h 
b/be/src/exprs/table_function/vjson_each.h
index 2a9ddb64599..a779b76aa9d 100644
--- a/be/src/exprs/table_function/vjson_each.h
+++ b/be/src/exprs/table_function/vjson_each.h
@@ -69,4 +69,8 @@ private:
 using VJsonEachTableFn = VJsonEachTableFunction<false>;
 using VJsonEachTextTableFn = VJsonEachTableFunction<true>;
 
+/// Instantiated once in vjson_each.cpp; suppresses per-TU implicit 
instantiation.
+extern template class VJsonEachTableFunction<false>;
+extern template class VJsonEachTableFunction<true>;
+
 } // namespace doris
diff --git a/be/src/format/parquet/vparquet_column_chunk_reader.h 
b/be/src/format/parquet/vparquet_column_chunk_reader.h
index 064d28fc115..a2805fe9379 100644
--- a/be/src/format/parquet/vparquet_column_chunk_reader.h
+++ b/be/src/format/parquet/vparquet_column_chunk_reader.h
@@ -286,4 +286,10 @@ private:
 
 bool has_dict_page(const tparquet::ColumnMetaData& column);
 
+/// Instantiated once in vparquet_column_chunk_reader.cpp; suppresses per-TU 
implicit instantiation.
+extern template class ColumnChunkReader<true, true>;
+extern template class ColumnChunkReader<true, false>;
+extern template class ColumnChunkReader<false, true>;
+extern template class ColumnChunkReader<false, false>;
+
 } // namespace doris
diff --git a/be/src/format/parquet/vparquet_column_reader.h 
b/be/src/format/parquet/vparquet_column_reader.h
index 7217c2b547d..acca51a28c5 100644
--- a/be/src/format/parquet/vparquet_column_reader.h
+++ b/be/src/format/parquet/vparquet_column_reader.h
@@ -546,4 +546,10 @@ public:
     void reset_filter_map_index() override { _filter_map_index = 0; }
 };
 
+/// Instantiated once in vparquet_column_reader.cpp; suppresses per-TU 
implicit instantiation.
+extern template class ScalarColumnReader<true, true>;
+extern template class ScalarColumnReader<true, false>;
+extern template class ScalarColumnReader<false, true>;
+extern template class ScalarColumnReader<false, false>;
+
 }; // namespace doris
diff --git a/be/src/format/parquet/vparquet_page_reader.h 
b/be/src/format/parquet/vparquet_page_reader.h
index 37e3b480bba..785ff304812 100644
--- a/be/src/format/parquet/vparquet_page_reader.h
+++ b/be/src/format/parquet/vparquet_page_reader.h
@@ -258,4 +258,10 @@ std::unique_ptr<PageReader<IN_COLLECTION, OFFSET_INDEX>> 
create_page_reader(
             reader, io_ctx, offset, length, total_rows, metadata, ctx, 
offset_index);
 }
 
+/// Instantiated once in vparquet_page_reader.cpp; suppresses per-TU implicit 
instantiation.
+extern template class PageReader<true, true>;
+extern template class PageReader<true, false>;
+extern template class PageReader<false, true>;
+extern template class PageReader<false, false>;
+
 } // namespace doris
diff --git a/be/src/format_v2/parquet/reader/native/column_chunk_reader.h 
b/be/src/format_v2/parquet/reader/native/column_chunk_reader.h
index a50b7e4bc08..e866e8b1c49 100644
--- a/be/src/format_v2/parquet/reader/native/column_chunk_reader.h
+++ b/be/src/format_v2/parquet/reader/native/column_chunk_reader.h
@@ -472,4 +472,10 @@ private:
 
 bool has_dict_page(const tparquet::ColumnMetaData& column);
 
+/// Instantiated once in column_chunk_reader.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ColumnChunkReader<true, true>;
+extern template class ColumnChunkReader<true, false>;
+extern template class ColumnChunkReader<false, true>;
+extern template class ColumnChunkReader<false, false>;
+
 } // namespace doris::format::parquet::native
diff --git a/be/src/format_v2/parquet/reader/native/column_reader.h 
b/be/src/format_v2/parquet/reader/native/column_reader.h
index b43822cd165..01c6832ac0f 100644
--- a/be/src/format_v2/parquet/reader/native/column_reader.h
+++ b/be/src/format_v2/parquet/reader/native/column_reader.h
@@ -710,4 +710,10 @@ public:
     void reset_filter_map_index() override { _filter_map_index = 0; }
 };
 
+/// Instantiated once in column_reader.cpp; suppresses per-TU implicit 
instantiation.
+extern template class ScalarColumnReader<true, true>;
+extern template class ScalarColumnReader<true, false>;
+extern template class ScalarColumnReader<false, true>;
+extern template class ScalarColumnReader<false, false>;
+
 } // namespace doris::format::parquet::native
diff --git a/be/src/format_v2/parquet/reader/native/page_reader.h 
b/be/src/format_v2/parquet/reader/native/page_reader.h
index da2c066891b..7686f2e5904 100644
--- a/be/src/format_v2/parquet/reader/native/page_reader.h
+++ b/be/src/format_v2/parquet/reader/native/page_reader.h
@@ -300,4 +300,10 @@ std::unique_ptr<PageReader<IN_COLLECTION, OFFSET_INDEX>> 
create_page_reader(
             reader, io_ctx, offset, length, total_rows, metadata, ctx, 
offset_index);
 }
 
+/// Instantiated once in page_reader.cpp; suppresses per-TU implicit 
instantiation.
+extern template class PageReader<true, true>;
+extern template class PageReader<true, false>;
+extern template class PageReader<false, true>;
+extern template class PageReader<false, false>;
+
 } // namespace doris::format::parquet::native
diff --git a/be/src/storage/cache/page_cache.h 
b/be/src/storage/cache/page_cache.h
index 1cc98c5cb49..6f88ff1571d 100644
--- a/be/src/storage/cache/page_cache.h
+++ b/be/src/storage/cache/page_cache.h
@@ -277,4 +277,7 @@ private:
     DISALLOW_COPY_AND_ASSIGN(PageCacheHandle);
 };
 
+/// Instantiated once in page_cache.cpp; suppresses per-TU implicit 
instantiation.
+extern template class 
MemoryTrackedPageWithPagePtr<segment_v2::SegmentFooterPB>;
+
 } // namespace doris
diff --git a/be/src/storage/index/inverted/inverted_index_writer.h 
b/be/src/storage/index/inverted/inverted_index_writer.h
index 3ef7b4d9319..4c78e863497 100644
--- a/be/src/storage/index/inverted/inverted_index_writer.h
+++ b/be/src/storage/index/inverted/inverted_index_writer.h
@@ -29,14 +29,12 @@
 #include "storage/index/inverted/util/reader.h"
 #include "storage/olap_common.h"
 #include "storage/segment/common.h"
+#include "storage/types.h"
 
 namespace doris {
 
 class KeyCoder;
 
-template <FieldType field_type>
-struct CppTypeTraits;
-
 namespace segment_v2 {
 
 using namespace doris::segment_v2::inverted_index;
@@ -104,5 +102,31 @@ private:
     bool _should_analyzer = false;
 };
 
+/// Instantiated once in inverted_index_writer.cpp; suppresses per-TU implicit 
instantiation.
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_CHAR>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_VARCHAR>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_STRING>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_TINYINT>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_SMALLINT>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_INT>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_UNSIGNED_INT>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_BIGINT>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_LARGEINT>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATE>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATETIME>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATEV2>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL32>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL64>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL128I>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL256>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_BOOL>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_IPV4>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_IPV6>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_FLOAT>;
+extern template class 
InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DOUBLE>;
+
 } // namespace segment_v2
 } // namespace doris
\ No newline at end of file
diff --git 
a/be/src/storage/index/inverted/query_v2/boolean_query/occur_boolean_weight.h 
b/be/src/storage/index/inverted/query_v2/boolean_query/occur_boolean_weight.h
index d3157c81473..a0f9a56809c 100644
--- 
a/be/src/storage/index/inverted/query_v2/boolean_query/occur_boolean_weight.h
+++ 
b/be/src/storage/index/inverted/query_v2/boolean_query/occur_boolean_weight.h
@@ -20,6 +20,7 @@
 #include <roaring/roaring.hh>
 
 #include "storage/index/inverted/query_v2/boolean_query/occur.h"
+#include "storage/index/inverted/query_v2/score_combiner.h"
 #include "storage/index/inverted/query_v2/scorer.h"
 #include "storage/index/inverted/query_v2/term_query/term_scorer.h"
 #include "storage/index/inverted/query_v2/wand/block_wand.h"
@@ -140,4 +141,8 @@ void 
OccurBooleanWeight<ScoreCombinerPtrT>::for_each_pruning(const QueryExecutio
             std::move(specialized));
 }
 
+/// Instantiated once in occur_boolean_weight.cpp; suppresses per-TU implicit 
instantiation.
+extern template class OccurBooleanWeight<SumCombinerPtr>;
+extern template class OccurBooleanWeight<DoNothingCombinerPtr>;
+
 } // namespace doris::segment_v2::inverted_index::query_v2
\ No newline at end of file
diff --git a/be/src/storage/index/inverted/query_v2/disjunction_scorer.h 
b/be/src/storage/index/inverted/query_v2/disjunction_scorer.h
index 583c17bf3d6..90dc7de0fb4 100644
--- a/be/src/storage/index/inverted/query_v2/disjunction_scorer.h
+++ b/be/src/storage/index/inverted/query_v2/disjunction_scorer.h
@@ -20,6 +20,7 @@
 #include <queue>
 #include <vector>
 
+#include "storage/index/inverted/query_v2/score_combiner.h"
 #include "storage/index/inverted/query_v2/scorer.h"
 
 namespace doris::segment_v2::inverted_index::query_v2 {
@@ -63,4 +64,8 @@ template <typename ScoreCombinerPtrT>
 ScorerPtr make_disjunction(std::vector<ScorerPtr> scorers, ScoreCombinerPtrT 
score_combiner,
                            size_t minimum_matches_required);
 
+/// Instantiated once in disjunction_scorer.cpp; suppresses per-TU implicit 
instantiation.
+extern template class DisjunctionScorer<SumCombinerPtr>;
+extern template class DisjunctionScorer<DoNothingCombinerPtr>;
+
 } // namespace doris::segment_v2::inverted_index::query_v2
\ No newline at end of file
diff --git a/be/src/storage/index/inverted/query_v2/exclude_scorer.h 
b/be/src/storage/index/inverted/query_v2/exclude_scorer.h
index e7679d60bfd..0a1ed6ac8ac 100644
--- a/be/src/storage/index/inverted/query_v2/exclude_scorer.h
+++ b/be/src/storage/index/inverted/query_v2/exclude_scorer.h
@@ -57,4 +57,7 @@ ScorerPtr make_exclude(ScorerPtr underlying, ScorerPtr 
excluding,
                        roaring::Roaring exclude_null = {},
                        const NullBitmapResolver* resolver = nullptr);
 
+/// Instantiated once in exclude_scorer.cpp; suppresses per-TU implicit 
instantiation.
+extern template class Exclude<ScorerPtr, ScorerPtr>;
+
 } // namespace doris::segment_v2::inverted_index::query_v2
diff --git 
a/be/src/storage/index/inverted/query_v2/phrase_query/phrase_scorer.h 
b/be/src/storage/index/inverted/query_v2/phrase_query/phrase_scorer.h
index b86067bd4b1..072b921f199 100644
--- a/be/src/storage/index/inverted/query_v2/phrase_query/phrase_scorer.h
+++ b/be/src/storage/index/inverted/query_v2/phrase_query/phrase_scorer.h
@@ -113,4 +113,8 @@ inline void 
PhraseScorer<TPostings>::intersection(std::vector<uint32_t>& left,
     left.resize(count);
 }
 
+/// Instantiated once in phrase_scorer.cpp; suppresses per-TU implicit 
instantiation.
+extern template class PhraseScorer<PostingsPtr>;
+extern template class PhraseScorer<SegmentPostingsPtr>;
+
 } // namespace doris::segment_v2::inverted_index::query_v2
\ No newline at end of file
diff --git a/be/src/storage/index/inverted/query_v2/union/simple_union.h 
b/be/src/storage/index/inverted/query_v2/union/simple_union.h
index d06a4b5ac31..dcc9506d181 100644
--- a/be/src/storage/index/inverted/query_v2/union/simple_union.h
+++ b/be/src/storage/index/inverted/query_v2/union/simple_union.h
@@ -62,4 +62,9 @@ auto make_simple_union(std::vector<TDocSet> docsets) {
     return SimpleUnion<TDocSet>::create(std::move(docsets));
 }
 
+/// Instantiated once in simple_union.cpp; suppresses per-TU implicit 
instantiation.
+extern template class SimpleUnion<MockDocSetPtr>;
+extern template class SimpleUnion<PostingsPtr>;
+extern template class SimpleUnion<SegmentPostingsPtr>;
+
 } // namespace doris::segment_v2::inverted_index::query_v2
\ No newline at end of file
diff --git a/be/src/util/frame_of_reference_coding.h 
b/be/src/util/frame_of_reference_coding.h
index f3557bc6985..55d8143f271 100644
--- a/be/src/util/frame_of_reference_coding.h
+++ b/be/src/util/frame_of_reference_coding.h
@@ -210,4 +210,32 @@ private:
     uint32_t _current_decoded_frame = -1;
     std::vector<T> _out_buffer; // store values of decoded frame
 };
+
+template <>
+const uint24_t ForEncoder<uint24_t>::numeric_limits_max();
+
+/// Instantiated once in frame_of_reference_coding.cpp; suppresses per-TU 
implicit instantiation.
+extern template class ForEncoder<int8_t>;
+extern template class ForEncoder<int16_t>;
+extern template class ForEncoder<int32_t>;
+extern template class ForEncoder<int64_t>;
+extern template class ForEncoder<int128_t>;
+extern template class ForEncoder<uint8_t>;
+extern template class ForEncoder<uint16_t>;
+extern template class ForEncoder<uint32_t>;
+extern template class ForEncoder<uint64_t>;
+extern template class ForEncoder<uint24_t>;
+extern template class ForEncoder<uint128_t>;
+extern template class ForDecoder<int8_t>;
+extern template class ForDecoder<int16_t>;
+extern template class ForDecoder<int32_t>;
+extern template class ForDecoder<int64_t>;
+extern template class ForDecoder<int128_t>;
+extern template class ForDecoder<uint8_t>;
+extern template class ForDecoder<uint16_t>;
+extern template class ForDecoder<uint32_t>;
+extern template class ForDecoder<uint64_t>;
+extern template class ForDecoder<uint24_t>;
+extern template class ForDecoder<uint128_t>;
+
 } // namespace doris
diff --git a/be/src/util/json/json_parser.h b/be/src/util/json/json_parser.h
index c4a165e8995..ee91765d44d 100644
--- a/be/src/util/json/json_parser.h
+++ b/be/src/util/json/json_parser.h
@@ -172,4 +172,8 @@ private:
     ParserImpl parser;
 };
 
+class SimdJSONParser;
+/// Instantiated once in json_parser.cpp; suppresses per-TU implicit 
instantiation.
+extern template class JSONDataParser<SimdJSONParser>;
+
 } // namespace doris


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

Reply via email to