Skip to content

Commit 295c7c6

Browse files
committed
fix: avoid infinite recusion due to cyclic dependency
1 parent c2442a9 commit 295c7c6

File tree

1 file changed

+38
-22
lines changed

1 file changed

+38
-22
lines changed

collab-folder/src/folder.rs

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::borrow::{Borrow, BorrowMut};
2-
use std::collections::HashMap;
2+
use std::collections::{HashMap, HashSet};
33
use std::ops::{Deref, DerefMut};
44
use std::sync::Arc;
55

@@ -406,7 +406,11 @@ impl Folder {
406406
/// * `Vec<View>`: A vector of `View` objects that includes the parent view and all of its child views.
407407
pub fn get_view_recursively(&self, view_id: &str) -> Vec<View> {
408408
let txn = self.collab.transact();
409-
self.body.get_view_recursively_with_txn(&txn, view_id)
409+
let mut views = vec![];
410+
self
411+
.body
412+
.get_view_recursively_with_txn(&txn, view_id, &mut HashSet::default(), &mut views);
413+
views
410414
}
411415
}
412416

@@ -579,36 +583,41 @@ impl FolderBody {
579583
self.meta.get_with_txn(txn, FOLDER_WORKSPACE_ID)
580584
}
581585

582-
/// Recursively retrieves all views associated with the provided `view_id` using a transaction.
586+
/// Recursively retrieves all views associated with the provided `view_id` using a transaction,
587+
/// adding them to the `accumulated_views` vector.
583588
///
584-
/// The function begins by attempting to retrieve the parent view associated with the `view_id`.
585-
/// If the parent view is not found, an empty vector is returned.
589+
/// The function begins by attempting to retrieve the view associated with the `view_id`.
590+
/// If the parent view is not found, the function returns.
586591
/// If the parent view is found, the function proceeds to retrieve all of its child views recursively.
592+
/// The function uses a hash set to keep track of the visited view ids to avoid infinite recursion due
593+
/// to circular dependency.
587594
///
588-
/// The function finally returns a vector containing the parent view and all of its child views.
595+
/// At the end of the recursion, `accumulated_views` will contain the parent view and all of its child views.
589596
/// The views are clones of the original objects.
590597
///
591598
/// # Parameters
592599
///
593600
/// * `txn`: A read transaction object which is used to execute the view retrieval.
594601
/// * `view_id`: The ID of the parent view.
595-
///
596-
/// # Returns
597-
///
598-
/// * `Vec<View>`: A vector of `View` objects that includes the parent view and all of its child views.
599-
pub fn get_view_recursively_with_txn<T: ReadTxn>(&self, txn: &T, view_id: &str) -> Vec<View> {
602+
/// * `visited`: Hash set containing all the traversed view ids.
603+
/// * `accumulated_views`: Vector containing all the views that are accumulated during the traversal.
604+
pub fn get_view_recursively_with_txn<T: ReadTxn>(
605+
&self,
606+
txn: &T,
607+
view_id: &str,
608+
visited: &mut HashSet<String>,
609+
accumulated_views: &mut Vec<View>,
610+
) {
611+
if !visited.insert(view_id.to_string()) {
612+
return;
613+
}
600614
match self.views.get_view_with_txn(txn, view_id) {
601-
None => vec![],
615+
None => (),
602616
Some(parent_view) => {
603-
let mut views = vec![parent_view.as_ref().clone()];
604-
let child_views = parent_view
605-
.children
606-
.items
607-
.iter()
608-
.flat_map(|child| self.get_view_recursively_with_txn(txn, &child.id))
609-
.collect::<Vec<_>>();
610-
views.extend(child_views);
611-
views
617+
accumulated_views.push(parent_view.as_ref().clone());
618+
parent_view.children.items.iter().for_each(|child| {
619+
self.get_view_recursively_with_txn(txn, &child.id, visited, accumulated_views)
620+
})
612621
},
613622
}
614623
}
@@ -643,7 +652,14 @@ impl FolderBody {
643652
.map(|view| view.as_ref().clone())
644653
.collect::<Vec<View>>();
645654
for view in self.views.get_views_belong_to(txn, workspace_id) {
646-
views.extend(self.get_view_recursively_with_txn(txn, &view.id));
655+
let mut all_views_in_workspace = vec![];
656+
self.get_view_recursively_with_txn(
657+
txn,
658+
&view.id,
659+
&mut HashSet::default(),
660+
&mut all_views_in_workspace,
661+
);
662+
views.extend(all_views_in_workspace);
647663
}
648664
views.extend(orphan_views);
649665

0 commit comments

Comments
 (0)