Skip to content
This repository was archived by the owner on Dec 9, 2025. It is now read-only.

Commit 30a9028

Browse files
committed
finish log->phy optimizer
1 parent 01e0c88 commit 30a9028

4 files changed

Lines changed: 142 additions & 14 deletions

File tree

optd/src/optimizer/merge/helpers.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,65 @@ impl<M: Memo> Optimizer<M> {
146146
let goal_task = self.get_optimize_goal_task_mut(goal_id).unwrap();
147147
goal_task.explore_group_in = principal_task_id;
148148
});
149+
150+
// *NOTE*: No need to consolidate transformations as all missing
151+
// expressions have already been added during the update phase.
152+
});
153+
}
154+
155+
/// Consolidate a goal optimization task into a principal task.
156+
///
157+
/// - Similar to the group exploration consolidation, a merge in the memo may cause
158+
/// several goal optimization tasks to refer to the same underlying goal. This function
159+
/// consolidates all such secondary tasks into a principal one.
160+
///
161+
/// - This involves:
162+
/// - Moving all outgoing optimize goal tasks, incoming optimize goal tasks, and
163+
/// optimize plan tasks from secondary to principal.
164+
/// - Updating each such task's references to point to the principal task.
165+
/// - Deleting the secondary tasks.
166+
///
167+
/// # Arguments
168+
/// * `principal_task_id` - The ID of the task to retain as canonical.
169+
/// * `secondary_task_ids` - All other task IDs to merge into the principal.
170+
pub(super) async fn consolidate_goal_optimize(
171+
&mut self,
172+
principal_task_id: TaskId,
173+
secondary_task_ids: &[TaskId],
174+
) {
175+
secondary_task_ids.iter().for_each(|&task_id| {
176+
let task = self.get_optimize_goal_task_mut(task_id).unwrap();
177+
178+
// Move out the task sets before deletion.
179+
let optimize_out_tasks = std::mem::take(&mut task.optimize_goal_out);
180+
let optimize_in_tasks = std::mem::take(&mut task.optimize_goal_in);
181+
let optimize_plan_tasks = std::mem::take(&mut task.optimize_plan_out);
182+
183+
self.delete_task(task_id);
184+
185+
optimize_out_tasks.into_iter().for_each(|optimize_id| {
186+
let optimize_goal_task = self.get_optimize_goal_task_mut(optimize_id).unwrap();
187+
optimize_goal_task.optimize_goal_in.remove(&task_id);
188+
optimize_goal_task
189+
.optimize_goal_in
190+
.insert(principal_task_id);
191+
});
192+
193+
optimize_in_tasks.into_iter().for_each(|optimize_id| {
194+
let optimize_goal_task = self.get_optimize_goal_task_mut(optimize_id).unwrap();
195+
optimize_goal_task.optimize_goal_out.remove(&task_id);
196+
optimize_goal_task
197+
.optimize_goal_out
198+
.insert(principal_task_id);
199+
});
200+
201+
optimize_plan_tasks.into_iter().for_each(|optimize_id| {
202+
let optimize_plan_task = self.get_optimize_plan_task_mut(optimize_id).unwrap();
203+
optimize_plan_task.optimize_goal_in = Some(principal_task_id);
204+
});
205+
206+
// *NOTE*: No need to consolidate implementations as all missing
207+
// expressions have already been added during the update phase.
149208
});
150209
}
151210

optd/src/optimizer/merge/mod.rs

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
11
use super::Optimizer;
2-
use crate::memo::{Memo, MergeGroupProduct, MergeProducts};
2+
use crate::memo::{Memo, MergeGoalProduct, MergeGroupProduct, MergeProducts};
33

44
mod helpers;
55

66
impl<M: Memo> Optimizer<M> {
77
/// Processes merge results by updating the task graph to reflect merges in the memo.
88
///
9+
/// This function handles both group merges and goal merges by delegating to specialized
10+
/// handlers for each type of merge.
11+
///
12+
/// # Parameters
13+
/// * `result` - The merge result to handle, containing information about merged groups and goals.
14+
///
15+
/// # Returns
16+
/// * `Result<(), OptimizeError>` - Success or an error that occurred during processing.
17+
pub(super) async fn handle_merge_result(
18+
&mut self,
19+
result: MergeProducts,
20+
) -> Result<(), M::MemoError> {
21+
self.handle_group_merges(&result.group_merges).await?;
22+
self.handle_goal_merges(&result.goal_merges).await
23+
}
24+
25+
/// Handles merges of logical groups by updating the task graph.
26+
///
927
/// When groups are merged in the memo, multiple exploration tasks may now refer to
1028
/// the same underlying group. This method handles the task graph updates required
1129
/// by such merges. For each merged group, it:
@@ -28,18 +46,18 @@ impl<M: Memo> Optimizer<M> {
2846
/// with it, containing all logical expressions from the original groups with no duplicates.
2947
///
3048
/// # Parameters
31-
/// * `result` - The merge result to handle, containing information about merged groups.
49+
/// * `group_merges` - A slice of group merge products to handle.
3250
///
3351
/// # Returns
3452
/// * `Result<(), OptimizeError>` - Success or an error that occurred during processing.
35-
pub(super) async fn handle_merge_result(
53+
async fn handle_group_merges(
3654
&mut self,
37-
result: MergeProducts,
55+
group_merges: &[MergeGroupProduct],
3856
) -> Result<(), M::MemoError> {
3957
for MergeGroupProduct {
4058
new_group_id,
4159
merged_groups,
42-
} in result.group_merges
60+
} in group_merges
4361
{
4462
// For each merged group, get all group exploration tasks.
4563
// We don't need to check for the new group ID since it is guaranteed to be new.
@@ -49,7 +67,7 @@ impl<M: Memo> Optimizer<M> {
4967
.collect();
5068

5169
if !group_explore_tasks.is_empty() {
52-
let all_logical_exprs = self.memo.get_all_logical_exprs(new_group_id).await?;
70+
let all_logical_exprs = self.memo.get_all_logical_exprs(*new_group_id).await?;
5371

5472
let (principal_task_id, secondary_task_ids) =
5573
group_explore_tasks.split_first().unwrap();
@@ -70,7 +88,64 @@ impl<M: Memo> Optimizer<M> {
7088

7189
// Step 4: Set the index to point to the new representative task.
7290
self.group_exploration_task_index
73-
.insert(new_group_id, *principal_task_id);
91+
.insert(*new_group_id, *principal_task_id);
92+
}
93+
}
94+
95+
Ok(())
96+
}
97+
98+
/// Handles merges of optimization goals by updating the task graph.
99+
///
100+
/// When goals are merged in the memo, multiple optimization tasks may now refer to
101+
/// the same underlying goal. This method handles the task graph updates required
102+
/// by such merges. For each merged goal, it:
103+
///
104+
/// 1. **Consolidates**: Merges all secondary tasks into a principal task by transferring
105+
/// their dependencies (incoming and outgoing optimization tasks and plan tasks) and
106+
/// updating references, ensuring a clean 1:1 mapping between goals and optimization tasks.
107+
///
108+
/// 2. **Re-indexes**: Updates the goal optimization index to point to the principal task
109+
/// for the new goal ID.
110+
///
111+
/// After processing, each merged goal will have exactly one optimization task associated
112+
/// with it, with all dependencies properly redirected to it.
113+
///
114+
/// # Parameters
115+
/// * `goal_merges` - A slice of goal merge products to handle.
116+
///
117+
/// # Returns
118+
/// * `Result<(), OptimizeError>` - Success or an error that occurred during processing.
119+
async fn handle_goal_merges(
120+
&mut self,
121+
goal_merges: &[MergeGoalProduct],
122+
) -> Result<(), M::MemoError> {
123+
for MergeGoalProduct {
124+
new_goal_id,
125+
merged_goals,
126+
} in goal_merges
127+
{
128+
// For each merged goal, get all goal optimization tasks.
129+
// We don't need to check for the new goal ID since it is guaranteed to be new.
130+
let goal_optimize_tasks: Vec<_> = merged_goals
131+
.iter()
132+
.filter_map(|goal_id| self.goal_optimization_task_index.get(goal_id).copied())
133+
.collect();
134+
135+
if !goal_optimize_tasks.is_empty() {
136+
let (principal_task_id, secondary_task_ids) =
137+
goal_optimize_tasks.split_first().unwrap();
138+
139+
// *NOTE*: Deduplication and updates of implementation tasks have already been
140+
// handled in the `handle_group_merges` method, so we don't need to do it here.
141+
142+
// Step 1: Consolidate all dependent tasks into the new "representative" task.
143+
self.consolidate_goal_optimize(*principal_task_id, secondary_task_ids)
144+
.await;
145+
146+
// Step 2: Set the index to point to the new representative task.
147+
self.goal_optimization_task_index
148+
.insert(*new_goal_id, *principal_task_id);
74149
}
75150
}
76151

optd/src/optimizer/tasks/launch.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -410,11 +410,9 @@ impl<M: Memo> Optimizer<M> {
410410
goal_id,
411411
optimize_plan_out: HashSet::new(),
412412
optimize_goal_out: HashSet::new(), // filled below to avoid infinite recursion
413-
fork_costed_out: HashSet::new(),
414-
optimize_goal_in: HashSet::new(), // filled below to avoid infinite recursion
413+
optimize_goal_in: HashSet::new(), // filled below to avoid infinite recursion
415414
explore_group_in,
416415
implement_expression_in,
417-
cost_expression_in: HashSet::new(), // TODO: design proper costing
418416
};
419417

420418
// Add this task to the exploration task's outgoing edges.

optd/src/optimizer/tasks/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ pub(crate) struct OptimizeGoalTask {
5858
/// `OptimizeGoalTask` parent goals that this task is simultaneously
5959
/// producing for.
6060
pub optimize_goal_out: HashSet<TaskId>,
61-
/// `ForkCostedTask` subscribed to this goal.
62-
pub fork_costed_out: HashSet<TaskId>,
6361

6462
// Input tasks that feed this task.
6563
/// `OptimizeGoalTask` member (children) goals producing for this goal.
@@ -69,8 +67,6 @@ pub(crate) struct OptimizeGoalTask {
6967
pub explore_group_in: TaskId,
7068
/// `ImplementExpressionTask` rules that are implementing logical expressions.
7169
pub implement_expression_in: HashSet<TaskId>,
72-
/// `CostExpressionTask` costing of physical expressions.
73-
pub cost_expression_in: HashSet<TaskId>,
7470
}
7571

7672
/// Task to explore expressions in a logical group.

0 commit comments

Comments
 (0)