Skip to main content

dag/idmap/
mem_idmap.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::BTreeMap;
9use std::sync::atomic;
10use std::sync::atomic::AtomicU64;
11
12use super::IdMapWrite;
13use crate::errors::NotFoundError;
14use crate::id::Group;
15use crate::id::Id;
16use crate::id::Vertex;
17use crate::ops::IdConvert;
18use crate::ops::Persist;
19use crate::ops::PrefixLookup;
20use crate::Result;
21use crate::VerLink;
22
23/// Bi-directional mapping between an integer id and a name (`[u8]`).
24///
25/// Private. Stored in memory.
26pub struct MemIdMap {
27    core: CoreMemIdMap,
28    map_id: String,
29    map_version: VerLink,
30}
31
32/// Subset of the `MemIdMap` interface that does not have "map_version".
33/// or "version" concept.
34#[derive(Default, Clone)]
35pub(crate) struct CoreMemIdMap {
36    id2name: BTreeMap<Id, Vertex>,
37    name2id: BTreeMap<Vertex, Id>,
38}
39
40impl MemIdMap {
41    /// Create an empty [`MemIdMap`].
42    pub fn new() -> Self {
43        Self {
44            core: Default::default(),
45            map_id: format!("mem:{}", next_id()),
46            map_version: VerLink::new(),
47        }
48    }
49}
50
51impl Clone for MemIdMap {
52    fn clone(&self) -> Self {
53        Self {
54            core: self.core.clone(),
55            map_id: self.map_id.clone(),
56            map_version: self.map_version.clone(),
57        }
58    }
59}
60
61impl CoreMemIdMap {
62    pub fn lookup_vertex_id(&self, name: &Vertex) -> Option<Id> {
63        self.name2id.get(name).copied()
64    }
65
66    pub fn lookup_vertex_name(&self, id: Id) -> Option<&Vertex> {
67        self.id2name.get(&id)
68    }
69
70    pub fn lookup_vertexes_by_hex_prefix(
71        &self,
72        hex_prefix: &[u8],
73        limit: usize,
74    ) -> Result<Vec<Vertex>> {
75        let start = Vertex::from_hex(hex_prefix)?;
76        let mut result = Vec::new();
77        for (vertex, id) in self.name2id.range(start..) {
78            if result.len() >= limit {
79                break;
80            }
81            if id.is_virtual() && hex_prefix.len() != vertex.as_ref().len() * 2 {
82                // Virtual group requires full match.
83                continue;
84            }
85            if !vertex.to_hex().as_bytes().starts_with(hex_prefix) {
86                break;
87            }
88            result.push(vertex.clone());
89        }
90        Ok(result)
91    }
92
93    pub fn lookup_range(&self, low: Id, high: Id) -> impl Iterator<Item = (&Id, &Vertex)> {
94        self.id2name.range(low..=high)
95    }
96
97    pub fn has_vertex_name(&self, name: &Vertex) -> bool {
98        self.name2id.contains_key(name)
99    }
100
101    pub fn has_vertex_id(&self, id: Id) -> bool {
102        self.id2name.contains_key(&id)
103    }
104
105    pub fn insert_vertex_id_name(&mut self, id: Id, vertex_name: Vertex) {
106        self.name2id.insert(vertex_name.clone(), id);
107        self.id2name.insert(id, vertex_name);
108    }
109
110    pub fn remove_range(&mut self, low: Id, high: Id) -> Result<Vec<Vertex>> {
111        let to_remove: Vec<(Id, Vertex)> = self
112            .id2name
113            .range(low..=high)
114            .map(|(i, n)| (*i, n.clone()))
115            .collect();
116        for (id, name) in &to_remove {
117            self.id2name.remove(id);
118            self.name2id.remove(name);
119        }
120        Ok(to_remove.into_iter().map(|(_, v)| v).collect())
121    }
122}
123
124#[async_trait::async_trait]
125impl IdConvert for MemIdMap {
126    async fn vertex_id(&self, name: Vertex) -> Result<Id> {
127        self.core
128            .lookup_vertex_id(&name)
129            .ok_or_else(|| name.not_found_error())
130    }
131    async fn vertex_id_with_max_group(
132        &self,
133        name: &Vertex,
134        max_group: Group,
135    ) -> Result<Option<Id>> {
136        let optional_id = self.core.name2id.get(name).and_then(|id| {
137            if id.group() <= max_group {
138                Some(*id)
139            } else {
140                None
141            }
142        });
143        Ok(optional_id)
144    }
145    async fn vertex_name(&self, id: Id) -> Result<Vertex> {
146        self.core
147            .lookup_vertex_name(id)
148            .cloned()
149            .ok_or_else(|| id.not_found_error())
150    }
151    async fn contains_vertex_name(&self, name: &Vertex) -> Result<bool> {
152        Ok(self.core.has_vertex_name(name))
153    }
154
155    async fn contains_vertex_id_locally(&self, ids: &[Id]) -> Result<Vec<bool>> {
156        Ok(ids
157            .iter()
158            .copied()
159            .map(|id| self.core.has_vertex_id(id))
160            .collect())
161    }
162    async fn contains_vertex_name_locally(&self, names: &[Vertex]) -> Result<Vec<bool>> {
163        Ok(names
164            .iter()
165            .map(|name| self.core.has_vertex_name(name))
166            .collect())
167    }
168
169    fn map_id(&self) -> &str {
170        &self.map_id
171    }
172
173    fn map_version(&self) -> &VerLink {
174        &self.map_version
175    }
176}
177
178// TODO: Reconsider re-assign master cases. Currently they are ignored.
179#[async_trait::async_trait]
180impl IdMapWrite for MemIdMap {
181    async fn insert(&mut self, id: Id, name: &[u8]) -> Result<()> {
182        let vertex_name = Vertex::copy_from(name);
183        self.core.insert_vertex_id_name(id, vertex_name);
184        self.map_version.bump();
185        Ok(())
186    }
187    async fn remove_range(&mut self, low: Id, high: Id) -> Result<Vec<Vertex>> {
188        if !(low.is_virtual() && high.is_virtual()) {
189            self.map_version = VerLink::new();
190        }
191        self.core.remove_range(low, high)
192    }
193}
194
195impl Persist for MemIdMap {
196    type Lock = ();
197
198    fn lock(&mut self) -> Result<Self::Lock> {
199        Ok(())
200    }
201
202    fn reload(&mut self, _lock: &Self::Lock) -> Result<()> {
203        Ok(())
204    }
205
206    fn persist(&mut self, _lock: &Self::Lock) -> Result<()> {
207        Ok(())
208    }
209}
210
211#[async_trait::async_trait]
212impl PrefixLookup for MemIdMap {
213    async fn vertexes_by_hex_prefix(&self, hex_prefix: &[u8], limit: usize) -> Result<Vec<Vertex>> {
214        self.core.lookup_vertexes_by_hex_prefix(hex_prefix, limit)
215    }
216}
217
218fn next_id() -> u64 {
219    static ID: AtomicU64 = AtomicU64::new(0);
220    ID.fetch_add(1, atomic::Ordering::AcqRel)
221}