be/src/exprs/aggregate/aggregate_function_java_udaf.h
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #pragma once |
19 | | |
20 | | #include <jni.h> |
21 | | #include <unistd.h> |
22 | | |
23 | | #include <cstdint> |
24 | | #include <memory> |
25 | | |
26 | | #include "absl/strings/substitute.h" |
27 | | #include "common/cast_set.h" |
28 | | #include "common/compiler_util.h" |
29 | | #include "common/exception.h" |
30 | | #include "common/logging.h" |
31 | | #include "common/status.h" |
32 | | #include "core/column/column_array.h" |
33 | | #include "core/column/column_map.h" |
34 | | #include "core/column/column_string.h" |
35 | | #include "core/field.h" |
36 | | #include "core/string_ref.h" |
37 | | #include "core/types.h" |
38 | | #include "exprs/aggregate/aggregate_function.h" |
39 | | #include "format/jni/jni_data_bridge.h" |
40 | | #include "runtime/user_function_cache.h" |
41 | | #include "util/jni-util.h" |
42 | | #include "util/jni_plugin_registry.h" |
43 | | |
44 | | namespace doris { |
45 | | |
46 | | const char* UDAF_EXECUTOR_CLOSE_SIGNATURE = "()V"; |
47 | | const char* UDAF_EXECUTOR_DESTROY_SIGNATURE = "()V"; |
48 | | const char* UDAF_EXECUTOR_ADD_SIGNATURE = "(ZIIJILjava/util/Map;)V"; |
49 | | const char* UDAF_EXECUTOR_SERIALIZE_SIGNATURE = "(J)[B"; |
50 | | const char* UDAF_EXECUTOR_MERGE_SIGNATURE = "(J[B)V"; |
51 | | const char* UDAF_EXECUTOR_GET_SIGNATURE = "(JLjava/util/Map;)J"; |
52 | | const char* UDAF_EXECUTOR_RESET_SIGNATURE = "(J)V"; |
53 | | // Calling Java method about those signature means: "(argument-types)return-type" |
54 | | // https://www.iitk.ac.in/esc101/05Aug/tutorial/native1.1/implementing/method.html |
55 | | |
56 | | struct AggregateJavaUdafData { |
57 | | public: |
58 | 0 | AggregateJavaUdafData() = default; |
59 | 0 | AggregateJavaUdafData(int64_t num_args) { cast_set(argument_size, num_args); } |
60 | | |
61 | 0 | ~AggregateJavaUdafData() = default; |
62 | | |
63 | 0 | Status close_and_delete_object() { |
64 | 0 | if (!can_call(executor_close_id) || executor_closed) { |
65 | 0 | return Status::OK(); |
66 | 0 | } |
67 | 0 | JNIEnv* env = nullptr; |
68 | |
|
69 | 0 | RETURN_IF_ERROR(Jni::Env::Get(&env)); |
70 | | |
71 | | // Raised before the call, not after: UdafExecutor.close() drops its state map, so a |
72 | | // close that threw halfway is still a close as far as everything below is concerned. |
73 | 0 | executor_closed = true; |
74 | 0 | auto st = executor_obj.call_nonvirtual_void_method(env, executor_cl, executor_close_id) |
75 | 0 | .call(); |
76 | 0 | if (!st.ok()) { |
77 | 0 | LOG(WARNING) << "Failed to close JAVA UDAF: " << st.to_string(); |
78 | 0 | return st; |
79 | 0 | } |
80 | 0 | return Status::OK(); |
81 | 0 | } |
82 | | |
83 | 0 | Status init_udaf(const TFunction& fn, const std::string& local_location) { |
84 | 0 | JNIEnv* env = nullptr; |
85 | 0 | RETURN_NOT_OK_STATUS_WITH_WARN(Jni::Env::Get(&env), "Java-Udaf init_udaf function"); |
86 | |
|
87 | 0 | TJavaUdfExecutorCtorParams ctor_params; |
88 | 0 | ctor_params.__set_fn(fn); |
89 | 0 | if (!fn.hdfs_location.empty() && !fn.checksum.empty()) { |
90 | 0 | ctor_params.__set_location(local_location); |
91 | 0 | } |
92 | |
|
93 | 0 | Jni::LocalArray ctor_params_bytes; |
94 | 0 | RETURN_IF_ERROR(Jni::Util::SerializeThriftMsg(env, &ctor_params, &ctor_params_bytes)); |
95 | 0 | RETURN_IF_ERROR(Jni::PluginRegistry::create_udf_executor( |
96 | 0 | env, Jni::plugin::JAVA_UDF_AGGREGATE, ctor_params_bytes, &executor_obj, |
97 | 0 | &executor_cl)); |
98 | | // From here the Java executor is alive, so a failure below has to close it: the |
99 | | // caller's cleanup path cannot, since it is exactly the method ids resolved here that |
100 | | // it would need to do so. |
101 | 0 | if (Status status = register_func_id(env); !status.ok()) { |
102 | 0 | LOG(WARNING) << "Java-Udaf register_func_id function failed: " << status.to_string(); |
103 | | // Logged, not discarded: this is the failure that says the Java executor object was |
104 | | // leaked, and it is the only place it can be seen. register_func_id's own failure is |
105 | | // the one returned, since that is what the caller asked for. |
106 | 0 | WARN_IF_ERROR(close_and_delete_object(), |
107 | 0 | "failed to close the Java UDAF executor after register_func_id failed"); |
108 | 0 | return status; |
109 | 0 | } |
110 | 0 | return Status::OK(); |
111 | 0 | } |
112 | | |
113 | | Status add(int64_t places_address, bool is_single_place, const IColumn** columns, |
114 | | int64_t row_num_start, int64_t row_num_end, const DataTypes& argument_types, |
115 | 0 | int64_t place_offset) { |
116 | 0 | JNIEnv* env = nullptr; |
117 | 0 | RETURN_NOT_OK_STATUS_WITH_WARN(Jni::Env::Get(&env), "Java-Udaf add function"); |
118 | |
|
119 | 0 | Block input_block; |
120 | 0 | for (size_t i = 0; i < argument_size; ++i) { |
121 | 0 | input_block.insert(ColumnWithTypeAndName(columns[i]->get_ptr(), argument_types[i], |
122 | 0 | std::to_string(i))); |
123 | 0 | } |
124 | 0 | std::unique_ptr<long[]> input_table; |
125 | 0 | RETURN_IF_ERROR(JniDataBridge::to_java_table(&input_block, input_table)); |
126 | 0 | auto input_table_schema = JniDataBridge::parse_table_schema(&input_block); |
127 | 0 | std::map<String, String> input_params = { |
128 | 0 | {"meta_address", std::to_string((long)input_table.get())}, |
129 | 0 | {"required_fields", input_table_schema.first}, |
130 | 0 | {"columns_types", input_table_schema.second}}; |
131 | |
|
132 | 0 | Jni::LocalObject input_map; |
133 | 0 | RETURN_IF_ERROR(Jni::Util::convert_to_java_map(env, input_params, &input_map)); |
134 | | // invoke add batch |
135 | | // Keep consistent with the function signature of executor_add_batch_id. |
136 | | |
137 | 0 | return executor_obj.call_void_method(env, executor_add_batch_id) |
138 | 0 | .with_arg((jboolean)is_single_place) |
139 | 0 | .with_arg(cast_set<jint>(row_num_start)) |
140 | 0 | .with_arg(cast_set<jint>(row_num_end)) |
141 | 0 | .with_arg(cast_set<jlong>(places_address)) |
142 | 0 | .with_arg(cast_set<jint>(place_offset)) |
143 | 0 | .with_arg(input_map) |
144 | 0 | .call(); |
145 | 0 | } |
146 | | |
147 | 0 | Status merge(const AggregateJavaUdafData& rhs, int64_t place) { |
148 | 0 | JNIEnv* env = nullptr; |
149 | 0 | RETURN_NOT_OK_STATUS_WITH_WARN(Jni::Env::Get(&env), "Java-Udaf merge function"); |
150 | 0 | serialize_data = rhs.serialize_data; |
151 | 0 | Jni::LocalArray byte_arr; |
152 | 0 | RETURN_IF_ERROR(Jni::Util::WriteBufferToByteArray(env, (jbyte*)serialize_data.data(), |
153 | 0 | cast_set<jsize>(serialize_data.length()), |
154 | 0 | &byte_arr)); |
155 | | |
156 | 0 | return executor_obj.call_nonvirtual_void_method(env, executor_cl, executor_merge_id) |
157 | 0 | .with_arg((jlong)place) |
158 | 0 | .with_arg(byte_arr) |
159 | 0 | .call(); |
160 | 0 | } |
161 | | |
162 | 0 | Status write(BufferWritable& buf, int64_t place) { |
163 | 0 | JNIEnv* env = nullptr; |
164 | 0 | RETURN_NOT_OK_STATUS_WITH_WARN(Jni::Env::Get(&env), "Java-Udaf write function"); |
165 | | // TODO: Here get a byte[] from FE serialize, and then allocate the same length bytes to |
166 | | // save it in BE, Because i'm not sure there is a way to use the byte[] not allocate again. |
167 | 0 | Jni::LocalArray arr; |
168 | 0 | RETURN_IF_ERROR( |
169 | 0 | executor_obj.call_nonvirtual_object_method(env, executor_cl, executor_serialize_id) |
170 | 0 | .with_arg((jlong)place) |
171 | 0 | .call(&arr)); |
172 | | |
173 | 0 | jsize len = 0; |
174 | 0 | RETURN_IF_ERROR(arr.get_length(env, &len)); |
175 | 0 | serialize_data.resize(len); |
176 | 0 | RETURN_IF_ERROR(arr.get_byte_elements(env, 0, len, |
177 | 0 | reinterpret_cast<jbyte*>(serialize_data.data()))); |
178 | 0 | buf.write_binary(serialize_data); |
179 | 0 | return Status::OK(); |
180 | 0 | } |
181 | | |
182 | 0 | Status reset(int64_t place) { |
183 | 0 | JNIEnv* env = nullptr; |
184 | 0 | RETURN_NOT_OK_STATUS_WITH_WARN(Jni::Env::Get(&env), "Java-Udaf reset function"); |
185 | 0 | return executor_obj.call_nonvirtual_void_method(env, executor_cl, executor_reset_id) |
186 | 0 | .with_arg(cast_set<jlong>(place)) |
187 | 0 | .call(); |
188 | 0 | } |
189 | | |
190 | 0 | void read(BufferReadable& buf) { buf.read_binary(serialize_data); } |
191 | | |
192 | 0 | Status destroy() { |
193 | | // Also once the executor has been closed: UdafExecutor.close() sets its state map to |
194 | | // null and destroy() walks that map. AggregateJavaUdaf::create() calls this right after |
195 | | // a failed init_udaf(), which closes - so without this the tail of the id resolution |
196 | | // (a failure on the last id, with close and destroy both bound already) would run |
197 | | // destroy() on a closed executor and swallow the NPE that comes back. |
198 | 0 | if (!can_call(executor_destroy_id) || executor_closed) { |
199 | 0 | return Status::OK(); |
200 | 0 | } |
201 | 0 | JNIEnv* env = nullptr; |
202 | 0 | RETURN_NOT_OK_STATUS_WITH_WARN(Jni::Env::Get(&env), "Java-Udaf destroy function"); |
203 | 0 | return executor_obj.call_nonvirtual_void_method(env, executor_cl, executor_destroy_id) |
204 | 0 | .call(); |
205 | 0 | } |
206 | | |
207 | 0 | Status get(IColumn& to, const DataTypePtr& result_type, int64_t place) const { |
208 | 0 | JNIEnv* env = nullptr; |
209 | 0 | RETURN_NOT_OK_STATUS_WITH_WARN(Jni::Env::Get(&env), "Java-Udaf get value function"); |
210 | |
|
211 | 0 | Block output_block; |
212 | 0 | output_block.insert( |
213 | 0 | ColumnWithTypeAndName(result_type->create_column(), result_type, "_result_")); |
214 | 0 | auto output_table_schema = JniDataBridge::parse_table_schema(&output_block); |
215 | 0 | std::string output_nullable = result_type->is_nullable() ? "true" : "false"; |
216 | 0 | std::map<String, String> output_params = {{"is_nullable", output_nullable}, |
217 | 0 | {"required_fields", output_table_schema.first}, |
218 | 0 | {"columns_types", output_table_schema.second}}; |
219 | |
|
220 | 0 | Jni::LocalObject output_map; |
221 | 0 | RETURN_IF_ERROR(Jni::Util::convert_to_java_map(env, output_params, &output_map)); |
222 | 0 | long output_address; |
223 | |
|
224 | 0 | RETURN_IF_ERROR(executor_obj.call_long_method(env, executor_get_value_id) |
225 | 0 | .with_arg(cast_set<jlong>(place)) |
226 | 0 | .with_arg(output_map) |
227 | 0 | .call(&output_address)); |
228 | | |
229 | 0 | RETURN_IF_ERROR(JniDataBridge::fill_block(&output_block, {0}, output_address)); |
230 | 0 | const auto& result_column = output_block.get_by_position(0).column; |
231 | 0 | DORIS_CHECK(result_column->size() == 1); |
232 | 0 | to.insert_from(*result_column, 0); |
233 | 0 | return Status::OK(); |
234 | 0 | } |
235 | | |
236 | | private: |
237 | | /** |
238 | | * Whether a JNI call through this method id can be made at all. |
239 | | * |
240 | | * The clean-up path is reached with nothing bound: init_udaf() creates the executor before it |
241 | | * resolves any method id, and AggregateJavaUdaf::create() calls destroy() when init_udaf() |
242 | | * fails - through a null receiver, a null class and a null method id if the Java factory was |
243 | | * what threw. That is undefined behaviour rather than an error, because the two DCHECKs in |
244 | | * the JNI wrappers that would catch it are compiled out of a release build. The scalar and |
245 | | * UDTF paths guard the same window with JniContext::open_successes. |
246 | | */ |
247 | 0 | bool can_call(const Jni::MethodId& method_id) const { |
248 | 0 | return !executor_obj.uninitialized() && !executor_cl.uninitialized() && |
249 | 0 | !method_id.uninitialized(); |
250 | 0 | } |
251 | | |
252 | | // Whether close() has already been called on the Java executor. Nothing that touches its |
253 | | // state may run afterwards. |
254 | | bool executor_closed = false; |
255 | | |
256 | 0 | Status register_func_id(JNIEnv* env) { |
257 | | // close first, and deliberately: the executor object already exists by the time this |
258 | | // runs, so every resolution below is a failure that has to close it - and |
259 | | // close_and_delete_object() is itself gated on can_call(executor_close_id). Resolving |
260 | | // any other id before this one leaves a window where the executor is alive and there |
261 | | // is no way left to close it. |
262 | 0 | RETURN_IF_ERROR(executor_cl.get_method(env, "close", UDAF_EXECUTOR_CLOSE_SIGNATURE, |
263 | 0 | &executor_close_id)); |
264 | 0 | RETURN_IF_ERROR(executor_cl.get_method(env, "reset", UDAF_EXECUTOR_RESET_SIGNATURE, |
265 | 0 | &executor_reset_id)); |
266 | 0 | RETURN_IF_ERROR(executor_cl.get_method(env, "merge", UDAF_EXECUTOR_MERGE_SIGNATURE, |
267 | 0 | &executor_merge_id)); |
268 | 0 | RETURN_IF_ERROR(executor_cl.get_method(env, "serialize", UDAF_EXECUTOR_SERIALIZE_SIGNATURE, |
269 | 0 | &executor_serialize_id)); |
270 | 0 | RETURN_IF_ERROR(executor_cl.get_method(env, "getValue", UDAF_EXECUTOR_GET_SIGNATURE, |
271 | 0 | &executor_get_value_id)); |
272 | 0 | RETURN_IF_ERROR(executor_cl.get_method(env, "destroy", UDAF_EXECUTOR_DESTROY_SIGNATURE, |
273 | 0 | &executor_destroy_id)); |
274 | 0 | RETURN_IF_ERROR(executor_cl.get_method(env, "addBatch", UDAF_EXECUTOR_ADD_SIGNATURE, |
275 | 0 | &executor_add_batch_id)); |
276 | | |
277 | 0 | return Status::OK(); |
278 | 0 | } |
279 | | |
280 | | private: |
281 | | // TODO: too many variables are hold, it's causing a lot of memory waste |
282 | | // it's time to refactor it. |
283 | | Jni::GlobalClass executor_cl; |
284 | | Jni::GlobalObject executor_obj; |
285 | | |
286 | | Jni::MethodId executor_add_batch_id; |
287 | | Jni::MethodId executor_merge_id; |
288 | | Jni::MethodId executor_serialize_id; |
289 | | Jni::MethodId executor_get_value_id; |
290 | | Jni::MethodId executor_reset_id; |
291 | | Jni::MethodId executor_close_id; |
292 | | Jni::MethodId executor_destroy_id; |
293 | | int argument_size = 0; |
294 | | std::string serialize_data; |
295 | | }; |
296 | | |
297 | | class AggregateJavaUdaf final |
298 | | : public IAggregateFunctionDataHelper<AggregateJavaUdafData, AggregateJavaUdaf>, |
299 | | VarargsExpression, |
300 | | NullableAggregateFunction { |
301 | | public: |
302 | | ENABLE_FACTORY_CREATOR(AggregateJavaUdaf); |
303 | | AggregateJavaUdaf(const TFunction& fn, const DataTypes& argument_types_, |
304 | | const DataTypePtr& return_type) |
305 | 0 | : IAggregateFunctionDataHelper(argument_types_), |
306 | 0 | _fn(fn), |
307 | 0 | _return_type(return_type), |
308 | 0 | _first_created(true), |
309 | 0 | _exec_place(nullptr) {} |
310 | 0 | ~AggregateJavaUdaf() override = default; |
311 | | |
312 | | static AggregateFunctionPtr create(const TFunction& fn, const DataTypes& argument_types_, |
313 | 0 | const DataTypePtr& return_type) { |
314 | 0 | return std::make_shared<AggregateJavaUdaf>(fn, argument_types_, return_type); |
315 | 0 | } |
316 | | //Note: The condition is added because maybe the BE can't find java-udaf impl jar |
317 | | //So need to check as soon as possible, before call Data function |
318 | 0 | Status check_udaf(const TFunction& fn) { |
319 | 0 | auto function_cache = UserFunctionCache::instance(); |
320 | | // get jar path if both file path location and checksum are null |
321 | 0 | if (!fn.hdfs_location.empty() && !fn.checksum.empty()) { |
322 | 0 | return function_cache->get_jarpath(fn.id, fn.hdfs_location, fn.checksum, |
323 | 0 | &_local_location); |
324 | 0 | } else { |
325 | 0 | return Status::OK(); |
326 | 0 | } |
327 | 0 | } |
328 | | |
329 | 0 | void create(AggregateDataPtr __restrict place) const override { |
330 | 0 | new (place) Data(argument_types.size()); |
331 | 0 | if (_first_created) { |
332 | 0 | Status status = this->data(place).init_udaf(_fn, _local_location); |
333 | 0 | _first_created = false; |
334 | 0 | _exec_place = place; |
335 | 0 | if (UNLIKELY(!status.ok())) { |
336 | 0 | static_cast<void>(this->data(place).destroy()); |
337 | 0 | this->data(place).~Data(); |
338 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, status.to_string()); |
339 | 0 | } |
340 | 0 | } |
341 | 0 | } |
342 | | |
343 | | // To avoid multiple times JNI call, Here will destroy all data at once |
344 | 0 | void destroy(AggregateDataPtr __restrict place) const noexcept override { |
345 | 0 | if (place == _exec_place) { |
346 | 0 | Status status = Status::OK(); |
347 | 0 | status = this->data(_exec_place).destroy(); |
348 | 0 | status = this->data(_exec_place).close_and_delete_object(); |
349 | 0 | _first_created = true; |
350 | 0 | if (UNLIKELY(!status.ok())) { |
351 | 0 | LOG(WARNING) << "Failed to destroy function: " << status.to_string(); |
352 | 0 | } |
353 | 0 | } |
354 | 0 | this->data(place).~Data(); |
355 | 0 | } |
356 | | |
357 | 0 | String get_name() const override { return _fn.name.function_name; } |
358 | | |
359 | 0 | DataTypePtr get_return_type() const override { return _return_type; } |
360 | | |
361 | | void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num, |
362 | 0 | Arena&) const override { |
363 | 0 | int64_t places_address = reinterpret_cast<int64_t>(place); |
364 | 0 | Status st = this->data(_exec_place) |
365 | 0 | .add(places_address, true, columns, row_num, row_num + 1, |
366 | 0 | argument_types, 0); |
367 | 0 | if (UNLIKELY(!st.ok())) { |
368 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
369 | 0 | } |
370 | 0 | } |
371 | | |
372 | | void add_batch(size_t batch_size, AggregateDataPtr* places, size_t place_offset, |
373 | 0 | const IColumn** columns, Arena&, bool /*agg_many*/) const override { |
374 | 0 | int64_t places_address = reinterpret_cast<int64_t>(places); |
375 | 0 | Status st = this->data(_exec_place) |
376 | 0 | .add(places_address, false, columns, 0, batch_size, argument_types, |
377 | 0 | place_offset); |
378 | 0 | if (UNLIKELY(!st.ok())) { |
379 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | | void add_batch_single_place(size_t batch_size, AggregateDataPtr place, const IColumn** columns, |
384 | 0 | Arena&) const override { |
385 | 0 | int64_t places_address = reinterpret_cast<int64_t>(place); |
386 | 0 | Status st = this->data(_exec_place) |
387 | 0 | .add(places_address, true, columns, 0, batch_size, argument_types, 0); |
388 | 0 | if (UNLIKELY(!st.ok())) { |
389 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
390 | 0 | } |
391 | 0 | } |
392 | | |
393 | | void add_range_single_place(int64_t partition_start, int64_t partition_end, int64_t frame_start, |
394 | | int64_t frame_end, AggregateDataPtr place, const IColumn** columns, |
395 | | Arena&, UInt8* current_window_empty, |
396 | 0 | UInt8* current_window_has_inited) const override { |
397 | 0 | frame_start = std::max<int64_t>(frame_start, partition_start); |
398 | 0 | frame_end = std::min<int64_t>(frame_end, partition_end); |
399 | 0 | int64_t places_address = reinterpret_cast<int64_t>(place); |
400 | 0 | Status st = this->data(_exec_place) |
401 | 0 | .add(places_address, true, columns, frame_start, frame_end, |
402 | 0 | argument_types, 0); |
403 | 0 | if (frame_start >= frame_end) { |
404 | 0 | if (!*current_window_has_inited) { |
405 | 0 | *current_window_empty = true; |
406 | 0 | } |
407 | 0 | } else { |
408 | 0 | *current_window_empty = false; |
409 | 0 | *current_window_has_inited = true; |
410 | 0 | } |
411 | 0 | if (UNLIKELY(!st.ok())) { |
412 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | 0 | void reset(AggregateDataPtr place) const override { |
417 | 0 | Status st = this->data(_exec_place).reset(reinterpret_cast<int64_t>(place)); |
418 | 0 | if (UNLIKELY(!st.ok())) { |
419 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
420 | 0 | } |
421 | 0 | } |
422 | | |
423 | | void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs, |
424 | 0 | Arena&) const override { |
425 | 0 | Status st = |
426 | 0 | this->data(_exec_place).merge(this->data(rhs), reinterpret_cast<int64_t>(place)); |
427 | 0 | if (UNLIKELY(!st.ok())) { |
428 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
429 | 0 | } |
430 | 0 | } |
431 | | |
432 | 0 | void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override { |
433 | 0 | Status st = this->data(_exec_place).write(buf, reinterpret_cast<int64_t>(place)); |
434 | 0 | if (UNLIKELY(!st.ok())) { |
435 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
436 | 0 | } |
437 | 0 | } |
438 | | |
439 | | // during merge-finalized phase, for deserialize and merge firstly, |
440 | | // will call create --- deserialize --- merge --- destory for each rows , |
441 | | // so need doing new (place), to create Data and read to buf, then call merge , |
442 | | // and during destory about deserialize, because haven't done init_udaf, |
443 | | // so it's can't call ~Data, only to change _destory_deserialize flag. |
444 | | void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf, |
445 | 0 | Arena&) const override { |
446 | 0 | this->data(place).read(buf); |
447 | 0 | } |
448 | | |
449 | 0 | void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override { |
450 | 0 | Status st = this->data(_exec_place).get(to, _return_type, reinterpret_cast<int64_t>(place)); |
451 | 0 | if (UNLIKELY(!st.ok())) { |
452 | 0 | throw doris::Exception(ErrorCode::INTERNAL_ERROR, st.to_string()); |
453 | 0 | } |
454 | 0 | } |
455 | | |
456 | | private: |
457 | | TFunction _fn; |
458 | | DataTypePtr _return_type; |
459 | | mutable bool _first_created; |
460 | | mutable AggregateDataPtr _exec_place; |
461 | | std::string _local_location; |
462 | | }; |
463 | | |
464 | | } // namespace doris |