Skip to main content

dag/
vertex_options.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8use std::collections::HashSet;
9
10use serde::Deserialize;
11
12use crate::Group;
13use crate::Vertex;
14
15/// A list of [`Vertex`]s (usually heads) with options attached to each vertex.
16#[derive(Default, Debug, Clone, Deserialize)]
17#[serde(transparent)]
18pub struct VertexListWithOptions {
19    list: Vec<(Vertex, VertexOptions)>,
20}
21
22/// Options attached to a vertex. Usually the vertex is a head. The head and its
23/// ancestors are going to be inserted to the graph. The options controls some
24/// details about the insertion.
25#[derive(Debug, Clone, Deserialize)]
26#[non_exhaustive]
27pub struct VertexOptions {
28    /// How many ids to reserve for this vertex. Suppose this vertex has id `n`,
29    /// then `n+1..=n+reserve_size` can only be used when inserting this vertex
30    /// and its ancestors in the same batch.
31    ///
32    /// Note: if any id `j` in the `n+1..=n+reserve_size` range were already
33    /// taken, then the reserve range becomes `n+1..j` instead. This avoids
34    /// fragmentation.
35    #[serde(default = "Default::default")]
36    pub reserve_size: u32,
37
38    /// The desired [`Group`] for this vertex. Note a vertex's group can be
39    /// moved down (ex. `NON_MASTER` to `MASTER`) but not moved up
40    /// (ex. `MASTER` to `NON_MASTER`).
41    /// - If the vertex does not exist, it will be inserted into the
42    ///   `desired_group`.
43    /// - If the vertex is already in a lower group than `desired_group`,
44    ///   the vertex will stay in that lower group unchanged.
45    /// - If the vertex is in a higher group than `desired_group`,
46    ///   the implementation (ex. `add_heads_and_flush`) might move the vertex
47    ///   (and its ancestors) to a lower group, or error out.
48    #[serde(default = "default_desired_group")]
49    pub desired_group: Group,
50}
51
52const fn default_desired_group() -> Group {
53    Group::NON_MASTER
54}
55
56impl Default for VertexOptions {
57    fn default() -> Self {
58        Self {
59            reserve_size: 0,
60            desired_group: default_desired_group(),
61        }
62    }
63}
64
65impl<'a> From<&'a [Vertex]> for VertexListWithOptions {
66    fn from(list: &'a [Vertex]) -> Self {
67        // Just use default options.
68        Self {
69            list: list
70                .iter()
71                .map(|v| (v.clone(), VertexOptions::default()))
72                .collect(),
73        }
74    }
75}
76
77impl From<Vec<Vertex>> for VertexListWithOptions {
78    fn from(list: Vec<Vertex>) -> Self {
79        // Just use default options.
80        Self {
81            list: list
82                .into_iter()
83                .map(|v| (v, VertexOptions::default()))
84                .collect(),
85        }
86    }
87}
88
89impl From<Vec<(Vertex, VertexOptions)>> for VertexListWithOptions {
90    fn from(list: Vec<(Vertex, VertexOptions)>) -> Self {
91        Self { list }
92    }
93}
94
95impl VertexListWithOptions {
96    /// Get the vertexes and their options.
97    pub fn vertex_options(&self) -> Vec<(Vertex, VertexOptions)> {
98        self.list.clone()
99    }
100
101    /// Get the vertexes.
102    pub fn vertexes(&self) -> Vec<Vertex> {
103        self.list.iter().map(|i| i.0.clone()).collect()
104    }
105
106    /// Sort the heads. Lower desired group first.
107    pub fn sort_by_group(mut self) -> Self {
108        self.list.sort_by_key(|(_v, opts)| opts.desired_group.0);
109        self
110    }
111
112    /// Get the vertexes, filter by the `desired_group` option.
113    pub fn vertexes_by_group(&self, group: Group) -> Vec<Vertex> {
114        self.list
115            .iter()
116            .filter_map(|(v, o)| {
117                if o.desired_group == group {
118                    Some(v.clone())
119                } else {
120                    None
121                }
122            })
123            .collect()
124    }
125
126    /// Test if this list is empty.
127    pub fn is_empty(&self) -> bool {
128        self.list.is_empty()
129    }
130
131    /// Add a new item to the list.
132    pub fn push(&mut self, head_opts: (Vertex, VertexOptions)) {
133        self.list.push(head_opts);
134    }
135
136    /// Set the `desired_group` option for all vertexes.
137    pub fn with_desired_group(mut self, group: Group) -> Self {
138        for (_v, opts) in self.list.iter_mut() {
139            opts.desired_group = group;
140        }
141        self
142    }
143
144    /// Chain another list. Vertexes that are already in this list are skipped.
145    pub fn chain(mut self, other: impl Into<Self>) -> Self {
146        let other = other.into();
147        let existed: HashSet<_> = self.vertexes().into_iter().collect();
148        for (v, o) in other.list {
149            if !existed.contains(&v) {
150                self.list.push((v, o))
151            }
152        }
153        self
154    }
155
156    /// Length of the `VertexListWithOptions`.
157    pub fn len(&self) -> usize {
158        self.list.len()
159    }
160
161    /// Minimal `desired_group` from all heads. `None` for empty heads list.
162    pub fn min_desired_group(&self) -> Option<Group> {
163        self.list.iter().map(|v| v.1.desired_group).min()
164    }
165
166    /// Maximum `desired_group` from all heads. `None` for empty heads list.
167    pub fn max_desired_group(&self) -> Option<Group> {
168        self.list.iter().map(|v| v.1.desired_group).max()
169    }
170}