Unify Btrfs send parent finding algorithm for snbk #1080
+566
−125
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The pull request implements the tree-based Btrfs send parent finding mechanism previously mentioned in #1072.
The new implementation unifies the algorithm used for determining send parents in both snapshot transferring and restoring.
If the PR is accepted, technically, there will be no algorithmic difference between snapshot transfer and restoration.
This will help unify the underlying code for snapshot transferring and restoring, and I would like to contribute it in a follow-up PR.
This is a relatively large change. Please let me know if anything needs adjustment or clarification.
Details about this PR
New Proposed
TreeViewModuleTypes
TreeView:Constructs a reusable tree from a list of
ProxyNodeobjects and provides the following features:TreeView::ProxyNodeBase class for tree nodes.
It provides metadata about Btrfs subvolumes on the sender side and determines whether a node is valid to be used as a send parent.
TreeView::VirtualNodeInternal class representing Btrfs subvolumes that are not managed by Snapper (i.e., no corresponding
TheBigThingexists for a UUID). Virtual nodes are always considered invalid as send parents.TreeView::SearchResultWraps a search result, including the selected parent node and its walking distance.
TreeView::ParentTypeEnumeration describing how a parent node is associated:
DIRECT_PARENT: a direct Btrfs parent UUID relationship existsIMPLICIT_PARENT: the parent is manually assigned without an explicit Btrfs relationshipTechnical Details
TreeViewstores nodes using shared pointers, and each node holds an iterator to its associatedTheBigThing.The node validity is retrieved dynamically, making the tree reusable across multiple searches.
A virtual root node without an actual UUID is created to connect all discovered subtrees, ensuring that no nodes remain orphaned. This is a special usage of
TreeView::VirtualNode.Breadth-first search strategy is used to find the nearest valid node as the send parent.
Parent nodes are prioritized over siblings. Among siblings, nodes with higher snapshot numbers (i.e., more recent snapshots) are preferred.
Even if the starting node itself is a valid send parent, it is explicitly prohibited from being selected as its own send parent.
Some basic documentation and comments have been added to the code.
Please let me know if the documentation is insufficient. I will refine it accordingly.
Demo
The following demo was made from an openSUSE Tumbleweed virtual machine.
Snapshots:
Backups:
The constructed tree:
graph LR 0x39736570[0x39736570 - virtual] 0x39736570 -.-> 0x397455d0 0x397455d0[0x397455d0 - virtual] 0x397455d0 --> 104 104[104] 0x397455d0 --> 100 100[100] 0x397455d0 --> 94 94[94] 0x397455d0 --> 93 93[93 - valid] 0x39736570 -.-> 1 1[1] 1 --> 80 80[80] 80 --> 105 105[105] 105 --> 110 110[110] 110 --> 112 112[112] 112 --> 149 149[149] 149 --> 180 180[180] 149 --> 179 179[179] 149 --> 178 178[178] 149 --> 177 177[177] 149 --> 176 176[176] 149 --> 175 175[175] 149 --> 174 174[174] 149 --> 173 173[173] 149 --> 172 172[172] 149 --> 171 171[171] 149 --> 170 170[170] 149 --> 166 166[166] 149 --> 158 158[158] 149 --> 157 157[157] 149 --> 156 156[156] 149 --> 155 155[155 - valid] 149 --> 154 154[154] 112 --> 132 132[132 - valid] 112 --> 124 124[124] 112 --> 123 123[123] 112 --> 122 122[122] 112 --> 121 121[121] 112 --> 118 118[118] 112 --> 113 113[113] 1 --> 70 70[70] 1 --> 46 46[46] 1 --> 23 23[23] 1 --> 18 18[18] 1 --> 17 17[17] 1 --> 12 12[12] 1 --> 11 11[11] 1 --> 10 10[10] 1 --> 9 9[9] 1 --> 2 2[2 - valid]Resolved send parents for each snapshot:
Improvements
After re-transferring snapshots from the source to the target using the new algorithm, disk usage is significantly reduced for the selected snapshots:

Changes to
TheBigThingsmoduleThe following types were added:
TheBigThings::BaseNodeanonymous::BaseNodeBase class for tree nodes.
It provides a constructor interface using an iterator to
TheBigThing, and determines node validity(i.e., whether the snapshot exists on both sender and receiver sides).
TheBigThings::SourceNodeanonymous::SourceNodeUsed when transferring snapshots from the source to the target.
TheBigThings::TargetNodeanonymous::TargetNodeUsed when restoring snapshots from the target to the source.
Two member variables were added:
source_tree:TreeViewwithTheBigThings::SourceNodeanonymous::SourceNode.Used to find the Btrfs send parent when transferring snapshots.
target_tree:TreeViewwithTheBigThings::TargetNodeanonymous::TargetNode.Used to find the Btrfs send parent when restoring snapshots.
The following functions were replaced by
TreeView::find_nearest_valid_node:TheBigThings::find_send_parentTheBigThings::find_restore_parent