jerry-024 commented on code in PR #760:
URL: https://github.com/apache/paimon-rust/pull/760#discussion_r3892666239


##########
crates/integrations/datafusion/src/lateral_vector_search.rs:
##########
@@ -352,9 +450,57 @@ struct LateralVectorSearchExec {
     query_vector_expr: Arc<dyn PhysicalExpr>,
     limit: usize,
     output_schema: ArrowSchemaRef,
+    filter: Option<Predicate>,
+    prepared_filter_cache: Arc<ExecutionPreparedFilterCache>,
     plan_properties: Arc<PlanProperties>,
 }
 
+#[derive(Debug)]
+struct ExecutionPreparedFilterEntry {
+    context: Weak<TaskContext>,
+    prepared_filter: Weak<OnceCell<PreparedVectorSearchFilter>>,
+}
+
+#[derive(Debug, Default)]
+struct ExecutionPreparedFilterCache {
+    // DataFusion passes the same TaskContext Arc to every partition of one
+    // execution. Weak references let those partitions share one prepared 
filter
+    // while ensuring a later execution of the reusable plan starts fresh.
+    entries: Mutex<Vec<ExecutionPreparedFilterEntry>>,
+}
+
+impl ExecutionPreparedFilterCache {
+    fn for_execution(
+        &self,
+        context: &Arc<TaskContext>,
+    ) -> Arc<OnceCell<PreparedVectorSearchFilter>> {
+        let mut entries = self
+            .entries
+            .lock()
+            .unwrap_or_else(std::sync::PoisonError::into_inner);
+        entries.retain(|entry| {
+            entry.context.strong_count() > 0 && 
entry.prepared_filter.strong_count() > 0
+        });
+        for entry in entries.iter() {
+            let Some(entry_context) = entry.context.upgrade() else {
+                continue;
+            };
+            if Arc::ptr_eq(&entry_context, context) {
+                if let Some(prepared_filter) = entry.prepared_filter.upgrade() 
{
+                    return prepared_filter;
+                }
+            }
+        }
+
+        let prepared_filter = Arc::new(OnceCell::new());
+        entries.push(ExecutionPreparedFilterEntry {
+            context: Arc::downgrade(context),
+            prepared_filter: Arc::downgrade(&prepared_filter),
+        });

Review Comment:
   <!-- dlf-review -->
   **[MAJOR]** The execution-scoped prefilter cache only retains a weak 
reference to the prepared filter, so one logical execution can resolve 
different target snapshots across partitions. Once an earlier partition stream 
is exhausted and drops the last strong reference, a later partition using the 
same live `TaskContext` creates a new `OnceCell` and resolves the table 
snapshot again.
   
   Keep the prepared filter strongly owned for the complete execution across 
all partitions, releasing it only when that execution finishes. Please add a 
sequential-partition test that updates the target between partitions.



-- 
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]

Reply via email to