From c576acaf109615e6c0f3d1e605925c4dc0728774 Mon Sep 17 00:00:00 2001
From: Denis Smirnov <sd@picodata.io>
Date: Thu, 18 Aug 2022 16:48:44 +0700
Subject: [PATCH] perf: remove redundant virtual table clone

---
 Cargo.toml                                    |  2 +-
 src/executor.rs                               |  3 ++-
 .../engine/cartridge/backend/sql/tree.rs      | 23 +++++++++++--------
 src/executor/ir.rs                            | 16 ++++++++-----
 4 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 0170ed12a8..e1576b630d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@ itertools = "0.10"
 pest = "2.0"
 pest_derive = "2.0"
 rand = "0.8"
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0", features = ["derive", "rc"] }
 serde_yaml = "0.8"
 sha2 = "0.10"
 tarantool = { git = "https://git.picodata.io/picodata/picodata/tarantool-module.git", features = ["picodata", "schema"] }
diff --git a/src/executor.rs b/src/executor.rs
index bfc38102e6..db2e3867ac 100644
--- a/src/executor.rs
+++ b/src/executor.rs
@@ -26,6 +26,7 @@
 use ahash::RandomState;
 use std::any::Any;
 use std::collections::{hash_map::Entry, HashMap};
+use std::rc::Rc;
 
 use crate::errors::QueryPlannerError;
 use crate::executor::bucket::Buckets;
@@ -200,7 +201,7 @@ where
         }
 
         if let Some(vtables) = self.exec_plan.get_mut_vtables() {
-            vtables.insert(motion_id, vtable);
+            vtables.insert(motion_id, Rc::new(vtable));
         }
 
         Ok(())
diff --git a/src/executor/engine/cartridge/backend/sql/tree.rs b/src/executor/engine/cartridge/backend/sql/tree.rs
index 142f3ac5ff..4590883c56 100644
--- a/src/executor/engine/cartridge/backend/sql/tree.rs
+++ b/src/executor/engine/cartridge/backend/sql/tree.rs
@@ -1,5 +1,6 @@
 use ahash::RandomState;
 use std::collections::HashMap;
+use std::rc::Rc;
 
 use serde::{Deserialize, Serialize};
 use traversal::DftPost;
@@ -12,7 +13,7 @@ use crate::ir::operator::{Bool, Relational};
 use crate::ir::Node;
 
 /// Payload of the syntax tree node.
-#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
 pub enum SyntaxData {
     /// "as alias_name"
     Alias(String),
@@ -33,11 +34,11 @@ pub enum SyntaxData {
     /// parameter (a wrapper over a plan constants)
     Parameter(usize),
     /// virtual table
-    VTable(Box<VirtualTable>),
+    VTable(Rc<VirtualTable>),
 }
 
 /// A syntax tree node.
-#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
+#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
 pub struct SyntaxNode {
     /// Payload
     pub(crate) data: SyntaxData,
@@ -133,7 +134,7 @@ impl SyntaxNode {
         }
     }
 
-    fn new_vtable(value: Box<VirtualTable>) -> Self {
+    fn new_vtable(value: Rc<VirtualTable>) -> Self {
         SyntaxNode {
             data: SyntaxData::VTable(value),
             left: None,
@@ -143,7 +144,7 @@ impl SyntaxNode {
 }
 
 /// Storage for the syntax nodes.
-#[derive(Serialize, Deserialize, PartialEq, Debug)]
+#[derive(Deserialize, Serialize, PartialEq, Debug)]
 pub struct SyntaxNodes {
     pub(crate) arena: Vec<SyntaxNode>,
     map: HashMap<usize, usize, RandomState>,
@@ -573,7 +574,7 @@ impl<'p> SyntaxPlan<'p> {
                     Ok(self.nodes.push_syntax_node(sn))
                 }
                 Relational::Motion { .. } => {
-                    let vtable = self.plan.get_motion_vtable(id)?.clone();
+                    let vtable = self.plan.get_motion_vtable(id)?;
                     let vtable_alias = vtable.get_alias().map(String::from);
                     let child_id = self.plan.get_motion_child(id)?;
                     let child_rel = self.plan.get_ir_plan().get_relation_node(child_id)?;
@@ -582,7 +583,7 @@ impl<'p> SyntaxPlan<'p> {
                         children = Vec::from([
                             self.nodes.push_syntax_node(SyntaxNode::new_open()),
                             self.nodes
-                                .push_syntax_node(SyntaxNode::new_vtable(Box::new(vtable))),
+                                .push_syntax_node(SyntaxNode::new_vtable(Rc::clone(&vtable))),
                             self.nodes.push_syntax_node(SyntaxNode::new_close()),
                         ]);
 
@@ -592,7 +593,7 @@ impl<'p> SyntaxPlan<'p> {
                     } else {
                         children.push(
                             self.nodes
-                                .push_syntax_node(SyntaxNode::new_vtable(Box::new(vtable))),
+                                .push_syntax_node(SyntaxNode::new_vtable(Rc::clone(&vtable))),
                         );
                     }
 
@@ -660,7 +661,7 @@ impl<'p> SyntaxPlan<'p> {
 
                     if let Some(motion_id) = ir_plan.get_motion_among_rel_nodes(&rel_ids)? {
                         // Replace motion node to virtual table node
-                        let vtable = self.plan.get_motion_vtable(motion_id)?.clone();
+                        let vtable = self.plan.get_motion_vtable(motion_id)?;
                         if vtable.get_alias().is_none() {
                             let sn = SyntaxNode::new_pointer(
                                 id,
@@ -668,7 +669,9 @@ impl<'p> SyntaxPlan<'p> {
                                 vec![
                                     self.nodes.push_syntax_node(SyntaxNode::new_open()),
                                     self.nodes
-                                        .push_syntax_node(SyntaxNode::new_vtable(Box::new(vtable))),
+                                        .push_syntax_node(SyntaxNode::new_vtable(Rc::clone(
+                                            &vtable,
+                                        ))),
                                     self.nodes.push_syntax_node(SyntaxNode::new_close()),
                                 ],
                             );
diff --git a/src/executor/ir.rs b/src/executor/ir.rs
index 6d026a7b7a..cc21dbf7bd 100644
--- a/src/executor/ir.rs
+++ b/src/executor/ir.rs
@@ -1,4 +1,5 @@
 use std::collections::HashMap;
+use std::rc::Rc;
 
 use crate::errors::QueryPlannerError;
 use crate::errors::QueryPlannerError::CustomError;
@@ -10,7 +11,7 @@ use crate::ir::Plan;
 #[derive(Debug, Clone)]
 pub struct ExecutionPlan {
     plan: Plan,
-    vtables: Option<HashMap<usize, VirtualTable>>,
+    vtables: Option<HashMap<usize, Rc<VirtualTable>>>,
 }
 
 impl From<Plan> for ExecutionPlan {
@@ -34,15 +35,15 @@ impl ExecutionPlan {
     }
 
     #[must_use]
-    pub fn get_vtables(&self) -> Option<&HashMap<usize, VirtualTable>> {
+    pub fn get_vtables(&self) -> Option<&HashMap<usize, Rc<VirtualTable>>> {
         self.vtables.as_ref()
     }
 
-    pub fn get_mut_vtables(&mut self) -> Option<&mut HashMap<usize, VirtualTable>> {
+    pub fn get_mut_vtables(&mut self) -> Option<&mut HashMap<usize, Rc<VirtualTable>>> {
         self.vtables.as_mut()
     }
 
-    pub fn set_vtables(&mut self, vtables: HashMap<usize, VirtualTable>) {
+    pub fn set_vtables(&mut self, vtables: HashMap<usize, Rc<VirtualTable>>) {
         self.vtables = Some(vtables);
     }
 
@@ -50,10 +51,13 @@ impl ExecutionPlan {
     ///
     /// # Errors
     /// - Failed to find a virtual table for the motion node.
-    pub fn get_motion_vtable(&self, motion_id: usize) -> Result<&VirtualTable, QueryPlannerError> {
+    pub fn get_motion_vtable(
+        &self,
+        motion_id: usize,
+    ) -> Result<Rc<VirtualTable>, QueryPlannerError> {
         if let Some(vtable) = &self.vtables {
             if let Some(result) = vtable.get(&motion_id) {
-                return Ok(result);
+                return Ok(Rc::clone(result));
             }
         }
 
-- 
GitLab