|
9 | 9 | */ |
10 | 10 |
|
11 | 11 | use std::any::TypeId; |
| 12 | +use std::collections::HashMap; |
12 | 13 | use std::sync::Mutex; |
13 | 14 |
|
14 | 15 | use either::Either; |
15 | 16 |
|
16 | 17 | use crate::arc_erase::ArcEraseDyn; |
17 | 18 | use crate::storage::data::DataKey; |
18 | 19 | use crate::storage::data::PagableData; |
| 20 | +use crate::storage::support::SerializerForPaging; |
19 | 21 | use crate::traits::SessionContext; |
20 | 22 |
|
21 | 23 | /// Trait for storage backends that can persist and retrieve paged-out data. |
@@ -68,6 +70,93 @@ pub trait PagableStorage: Send + Sync + 'static { |
68 | 70 | /// Access the session context for storing/retrieving layer-specific state |
69 | 71 | /// during serialization and deserialization. |
70 | 72 | fn session_context(&self) -> &Mutex<SessionContext>; |
| 73 | + |
| 74 | + /// Stores a single content-addressable [`PagableData`] blob and returns its |
| 75 | + /// [`DataKey`]. The key is derived from the data via |
| 76 | + /// [`PagableData::compute_key`]; if the same data is stored twice the second |
| 77 | + /// write is expected to be idempotent (or skipped). |
| 78 | + fn store_data(&self, data: PagableData) -> DataKey; |
| 79 | + |
| 80 | + /// Stores a previously-serialized item (and its transitively reachable arcs) |
| 81 | + /// to storage and returns its content-addressable [`DataKey`]. |
| 82 | + /// |
| 83 | + /// The caller is responsible for the initial serialization: lock |
| 84 | + /// `session_context()`, build a [`SerializerForPaging`], serialize the value, |
| 85 | + /// `.finish()` to obtain `(item_data, item_arcs)`, then pass them in here |
| 86 | + /// along with the still-locked `&mut SessionContext` (this method uses it to |
| 87 | + /// recursively serialize nested arcs). |
| 88 | + /// |
| 89 | + /// `finished` is a cache of arc identity → `DataKey` that the caller may share |
| 90 | + /// across multiple `page_out_item` invocations to avoid re-serializing arcs |
| 91 | + /// that were already paged out earlier in the same batch. |
| 92 | + fn page_out_item( |
| 93 | + &self, |
| 94 | + item_data: Vec<u8>, |
| 95 | + item_arcs: Vec<Box<dyn ArcEraseDyn>>, |
| 96 | + finished: &mut HashMap<usize, DataKey>, |
| 97 | + session_context: &mut SessionContext, |
| 98 | + ) -> DataKey { |
| 99 | + enum Task { |
| 100 | + Start(Box<dyn ArcEraseDyn>), |
| 101 | + Finish((Box<dyn ArcEraseDyn>, Vec<u8>, Vec<Box<dyn ArcEraseDyn>>)), |
| 102 | + } |
| 103 | + |
| 104 | + let mut tasks: Vec<Task> = item_arcs |
| 105 | + .iter() |
| 106 | + .map(|arc| Task::Start(arc.clone_dyn())) |
| 107 | + .collect(); |
| 108 | + |
| 109 | + while let Some(task) = tasks.pop() { |
| 110 | + match task { |
| 111 | + Task::Start(v) => { |
| 112 | + if finished.contains_key(&v.identity()) { |
| 113 | + continue; |
| 114 | + } |
| 115 | + |
| 116 | + let mut serializer = SerializerForPaging::new(session_context); |
| 117 | + v.serialize(&mut serializer).unwrap(); |
| 118 | + let (data, arcs) = serializer.finish(); |
| 119 | + |
| 120 | + let subtasks: Vec<_> = arcs |
| 121 | + .iter() |
| 122 | + .filter(|arc| !finished.contains_key(&arc.identity())) |
| 123 | + .map(|arc| Task::Start(arc.clone_dyn())) |
| 124 | + .collect(); |
| 125 | + |
| 126 | + tasks.push(Task::Finish((v, data, arcs))); |
| 127 | + tasks.extend(subtasks); |
| 128 | + } |
| 129 | + Task::Finish((arc, data, serialized_arcs)) => { |
| 130 | + let arcs: Vec<DataKey> = serialized_arcs |
| 131 | + .iter() |
| 132 | + .map(|arc| { |
| 133 | + *finished |
| 134 | + .get(&arc.identity()) |
| 135 | + .expect("nested arc should have been serialized first") |
| 136 | + }) |
| 137 | + .collect(); |
| 138 | + |
| 139 | + let key = self.store_data(PagableData { data, arcs }); |
| 140 | + finished.insert(arc.identity(), key); |
| 141 | + arc.set_data_key(key); |
| 142 | + } |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + let arcs: Vec<DataKey> = item_arcs |
| 147 | + .iter() |
| 148 | + .map(|arc| { |
| 149 | + *finished |
| 150 | + .get(&arc.identity()) |
| 151 | + .expect("nested arc should have been serialized first") |
| 152 | + }) |
| 153 | + .collect(); |
| 154 | + |
| 155 | + self.store_data(PagableData { |
| 156 | + data: item_data, |
| 157 | + arcs, |
| 158 | + }) |
| 159 | + } |
71 | 160 | } |
72 | 161 |
|
73 | 162 | static_assertions::assert_obj_safe!(PagableStorage); |
0 commit comments