1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/// Graph datastore for MemoRefHeads in our query context.
///
/// New gameplan:
/// Now that we know we only wish to include index (tree structured) data, do we really need refcounts? Probably not
/// Yay! We're a DAG again ( probably. Need to think about B-tree rebalancing scenarios )
/// * Presumably we can return to more traditional toposort
/// * Error on addition of a cycle to the context
///
/// The functions of ContextManager are twofold:
/// 1. Store Subject MemoRefHeads to which an observer `Context` is actually contextualized. This is in turn used
/// by relationship projection logic (Context.get_subject_with_head calls ContextManager.get_head)
/// 2. Provide a (cyclic capable) dependency iterator over the MemoRefHeads present, sufficient for context compression.
/// This is similar to, but not quite the same as a topological sort.
///
/// Crucially: `ContextManager` *must* be able to contain, and iterate cyclic subject relations. The underlying Memo structure is immutable,
/// and thus acyclic, but cyclic `Subject` relations are permissable due to what could be thought of as the "uncommitted" content of the ContextManager.
/// For this reason, we must perform context compression as a single pass over the contained MemoRefHeads, as a cyclic relation could otherwise cause and infinite loop.
/// The internal reference count increment/decrement thus contains cycle breaker functionality.
///
/// The ContextManager has been authored with the idea in mind that it generally should not exceed O(1k) MemoRefHeads.
/// It should be periodically compressed to control expansion, as its entire contents must be serialized for conveyance to neighbors.
///
/// Compression - a key requirement
///
/// Subject heads are applied to the context for any edit for which the consistency model enforcement is applicable.
/// Subject heads shall only removed from the context if:
/// * One or more other resident subject heads reference it
/// * All of the aforementioned subject heads descend it
///
/// Combined with index traversal, this meets our consistency invariant:
/// Projections done on the basis of an index or other relationship traversal shall include all edits whose heads were
/// added to the context previously.
/// Gradually, all edits will be rolled up into the index, which will always have at least one entry in the context (the root index node)
/// This has some crucial requirements:
/// 1. Non-index Subjects may not reference index subjects, or at least these references must not count
/// toward compaction rules
/// 2. Relationship traversals must specify which they require:
/// A. Relative consistency with the record from which they originated
/// B. Absolute consistency with the query context, which likely requires a supplimental index traversal.
/// Index subjects themselves would require only the former of course (with the latter being impossible)
/// For non-index relationship traversals, this is potentially ornerous from a performance perspective)
///
/// Invariant 1: The each state of the context manager must be descendent of its prior state
///
//impl ContextManager {
/// For a given SubjectId, Retrieve a RelationSlotSubjectHead containing all referred subject heads resident in the `ContextManager`
// pub fn compress_subject(&mut self, subject_id: SubjectId) -> Option<RelationSlotSubjectHead> {
// let mut slot_item_ids = Vec::new();
// {
// if let Some(ref mut item) = self.get_item_by_subject( subject_id ) {
// for (slot_id, maybe_rel_item_id) in item.relations.iter().enumerate(){
// if let Some(rel_item_id) = *maybe_rel_item_id {
// slot_item_ids.push((slot_id,rel_item_id));
// }
// }
// }
// }
// if slot_item_ids.len() > 0 {
// let mut rssh = RelationSlotSubjectHead::empty();
// for (slot_id,rel_item_id) in slot_item_ids {
// if let Some(ref mut rel_item) = self.items[rel_item_id] {
// if let Some(ref head) = rel_item.head {
// rssh.insert(slot_id as RelationSlotId, rel_item.subject_id, head.clone());
// }
// }
// }
// Some(rssh)
// }else {
// None
// }
// }
// // starting context: [C <- B <- A, X]
// // Materialize C if needed, then replace C
// // Materialize B to point to C, then replace B and remove C
// // Materialize A to point to B, then replace A and remove B
// // End context [A, X]
// pub fn compress_and_materialize(&self) {
// // TODO: conditionalize this on the basis of the present context size
// let parent_repoints : HashMap<SubjectId,RelationSlotSubjectHead>
// // Iterate the contextualized subject heads in reverse topological order
// for subject_head in {
// self.manage.subject_head_iter()
// } {
// // TODO: implement MemoRefHead.conditionally_materialize such that the materialization threshold is selected dynamically.
// // It shold almost certainly not materialize with a single edit since the last FullyMaterialized memo
// // head.conditionally_materialize( &self.slab );
// if subject_head.from_subject_ids.len() > 0 {
// // OK, somebody is pointing to us, so lets issue an edit for them
// // to point to the new materialized memo for their relevant relations
// for (from_head) in subject_head.referring_heads.iter(){
// let memoref = self.slab.new_memo(
// Some(self.id),
// head.clone(),
// MemoBody::Relation(RelationSlotSubjectHead(memoref_map))
// );
// head.apply_memoref(&memoref, &slab);
// }
// self.repoint_subject_relations(subject_head.subject_id,
// subject_head.head,
// subject_head.from_subject_ids);
// // NOTE: In order to remove a subject head from the context, we must ensure that
// // ALL referencing subject heads in the context get repointed. It's not enough to just do one
// // Now that we know they are pointing to the new materialized MemoRefHead,
// // and that the resident subject struct we have is already updated, we can
// // remove this subject MemoRefHead from the context head, because subsequent
// // index/graph traversals should find this updated parent.
// //
// // When trying to materialize/compress fully (not that we'll want to do this often),
// // this would continue all the way to the root index node, and we should be left
// // with a very small context head
// }
// }
// }
//}
/// Reverse topological iterator over subject heads which are resident in the context manager