sov_first_read_last_write_cache/
access.rs

1use thiserror::Error;
2
3use crate::CacheValue;
4
5#[derive(Error, Debug, PartialEq, Eq)]
6pub enum MergeError {
7    #[error("consecutive reads are inconsistent: left read: {left:?}, right read: {right:?}")]
8    ReadThenRead {
9        left: Option<CacheValue>,
10        right: Option<CacheValue>,
11    },
12    #[error("the read: {read:?} is in inconsistent with the previous write: {write:?}")]
13    WriteThenRead {
14        write: Option<CacheValue>,
15        read: Option<CacheValue>,
16    },
17}
18
19/// `Access` represents a sequence of events on a particular value.
20/// For example, a transaction might read a value, then take some action which causes it to be updated
21/// The rules for defining causality are as follows:
22/// 1. If a read is preceded by another read, check that the two reads match and discard one.
23/// 2. If a read is preceded by a write, check that the value read matches the value written. Discard the read.
24/// 3. Otherwise, retain the read.
25/// 4. A write is retained unless it is followed by another write.
26#[derive(PartialEq, Eq, Debug, Clone)]
27pub(crate) enum Access {
28    Read(Option<CacheValue>),
29    ReadThenWrite {
30        original: Option<CacheValue>,
31        modified: Option<CacheValue>,
32    },
33    Write(Option<CacheValue>),
34}
35
36impl Access {
37    pub(crate) fn last_value(&self) -> &Option<CacheValue> {
38        match self {
39            Access::Read(value) => value,
40            Access::ReadThenWrite { modified, .. } => modified,
41            Access::Write(value) => value,
42        }
43    }
44
45    pub(crate) fn write_value(&mut self, new_value: Option<CacheValue>) {
46        match self {
47            // If we've already read this slot, turn it into a readThenWrite access
48            Access::Read(original) => {
49                // If we're resetting the key to its original value, we can just discard the write history
50                if original == &new_value {
51                    return;
52                }
53                // Otherwise, keep track of the original value and the new value
54                *self = Access::ReadThenWrite {
55                    original: original.take(),
56
57                    modified: new_value,
58                };
59            }
60            // For ReadThenWrite override the modified value with a new value
61            Access::ReadThenWrite { original, modified } => {
62                // If we're resetting the key to its original value, we can just discard the write history
63                if original == &new_value {
64                    *self = Access::Read(new_value)
65                } else {
66                    *modified = new_value
67                }
68            }
69            // For Write override the original value with a new value
70            // We can do this unconditionally, since overwriting a value with itself is a no-op
71            Access::Write(value) => *value = new_value,
72        }
73    }
74
75    pub(crate) fn merge(&mut self, rhs: Self) -> Result<(), MergeError> {
76        // Pattern matching on (`self`, rhs) is a bit cleaner, but would move the `self` inside the tuple.
77        // We need the `self` later on for *self = Access.. therefore the nested solution.
78        match self {
79            Access::Read(left_read) => match rhs {
80                Access::Read(right_read) => {
81                    if left_read != &right_read {
82                        Err(MergeError::ReadThenRead {
83                            left: left_read.clone(),
84                            right: right_read,
85                        })
86                    } else {
87                        Ok(())
88                    }
89                }
90                Access::ReadThenWrite {
91                    original: right_original,
92                    modified: right_modified,
93                } => {
94                    if left_read != &right_original {
95                        Err(MergeError::ReadThenRead {
96                            left: left_read.clone(),
97                            right: right_original,
98                        })
99                    } else {
100                        *self = Access::ReadThenWrite {
101                            original: right_original,
102                            modified: right_modified,
103                        };
104
105                        Ok(())
106                    }
107                }
108                Access::Write(right_write) => {
109                    *self = Access::ReadThenWrite {
110                        original: left_read.take(),
111                        modified: right_write,
112                    };
113                    Ok(())
114                }
115            },
116            Access::ReadThenWrite {
117                original: left_original,
118                modified: left_modified,
119            } => match rhs {
120                Access::Read(right_read) => {
121                    if left_modified != &right_read {
122                        Err(MergeError::WriteThenRead {
123                            write: left_modified.clone(),
124                            read: right_read,
125                        })
126                    } else {
127                        Ok(())
128                    }
129                }
130                Access::ReadThenWrite {
131                    original: right_original,
132                    modified: right_modified,
133                } => {
134                    if left_modified != &right_original {
135                        Err(MergeError::WriteThenRead {
136                            write: left_modified.clone(),
137                            read: right_original,
138                        })
139                    } else {
140                        *self = Access::ReadThenWrite {
141                            original: left_original.take(),
142                            modified: right_modified,
143                        };
144                        Ok(())
145                    }
146                }
147                Access::Write(right_write) => {
148                    *self = Access::ReadThenWrite {
149                        original: left_original.take(),
150                        modified: right_write,
151                    };
152                    Ok(())
153                }
154            },
155            Access::Write(left_write) => match rhs {
156                Access::Read(right_read) => {
157                    if left_write != &right_read {
158                        Err(MergeError::WriteThenRead {
159                            write: left_write.clone(),
160                            read: right_read,
161                        })
162                    } else {
163                        Ok(())
164                    }
165                }
166                Access::ReadThenWrite {
167                    original: right_original,
168                    modified: right_modified,
169                } => {
170                    if left_write != &right_original {
171                        Err(MergeError::WriteThenRead {
172                            write: left_write.clone(),
173                            read: right_original,
174                        })
175                    } else {
176                        *self = Access::Write(right_modified);
177                        Ok(())
178                    }
179                }
180                Access::Write(right_write) => {
181                    *self = Access::Write(right_write);
182                    Ok(())
183                }
184            },
185        }
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192    use crate::utils::test_util::create_value;
193
194    #[test]
195    fn test_access_read_write() {
196        let original_value = create_value(1);
197        let mut access = Access::Read(original_value.clone());
198
199        // Check: Read => ReadThenWrite transition
200        {
201            let new_value = create_value(2);
202            access.write_value(new_value.clone());
203
204            assert_eq!(access.last_value(), &new_value);
205            assert_eq!(
206                access,
207                Access::ReadThenWrite {
208                    original: original_value.clone(),
209                    modified: new_value
210                }
211            );
212        }
213
214        // Check: ReadThenWrite => ReadThenWrite transition
215        {
216            let new_value = create_value(3);
217            access.write_value(new_value.clone());
218
219            assert_eq!(access.last_value(), &new_value);
220            assert_eq!(
221                access,
222                Access::ReadThenWrite {
223                    original: original_value,
224                    modified: new_value
225                }
226            );
227        }
228    }
229
230    #[test]
231    fn test_access_write() {
232        let original_value = create_value(1);
233        let mut access = Access::Write(original_value.clone());
234
235        // Check: Write => Write transition
236        {
237            assert_eq!(access.last_value(), &original_value);
238            let new_value = create_value(3);
239            access.write_value(new_value.clone());
240            assert_eq!(access.last_value(), &new_value);
241            assert_eq!(access, Access::Write(new_value));
242        }
243    }
244
245    #[test]
246    fn test_access_merge() {
247        let first_read = 1;
248        let mut value = create_value(first_read);
249        let mut left = Access::Read(value.clone());
250
251        let last_write = 10;
252        for i in 2..last_write + 1 {
253            left.merge(Access::Read(value.clone())).unwrap();
254
255            value = create_value(i);
256            left.merge(Access::Write(value.clone())).unwrap();
257        }
258
259        assert_eq!(
260            left,
261            Access::ReadThenWrite {
262                original: create_value(first_read),
263                modified: create_value(last_write)
264            }
265        )
266    }
267
268    #[test]
269    fn test_err_merge_left_read_neq_right_read() {
270        let first_read = 1;
271        let value = create_value(first_read);
272        let left = &mut Access::Read(value.clone());
273
274        let second_read = 2;
275        let value2 = create_value(second_read);
276
277        assert_eq!(
278            left.merge(Access::Read(value2.clone())),
279            Err(MergeError::ReadThenRead {
280                left: value,
281                right: value2,
282            })
283        );
284    }
285
286    #[test]
287    fn test_err_merge_left_read_neq_right_orig() {
288        let first_read = 1;
289        let value = create_value(first_read);
290        let left = &mut Access::Read(value.clone());
291
292        let second_read = 2;
293        let value2 = create_value(second_read);
294        let right = Access::ReadThenWrite {
295            original: value2.clone(),
296            modified: value.clone(),
297        };
298
299        assert_eq!(
300            left.merge(right),
301            Err(MergeError::ReadThenRead {
302                left: value,
303                right: value2,
304            })
305        );
306    }
307
308    #[test]
309    fn test_err_merge_left_mod_neq_right_read() {
310        let first_read = 1;
311        let value = create_value(first_read);
312
313        let second_read = 2;
314        let value2 = create_value(second_read);
315
316        let left = &mut Access::ReadThenWrite {
317            original: value2.clone(),
318            modified: value.clone(),
319        };
320
321        let right = Access::Read(value2.clone());
322
323        assert_eq!(
324            left.merge(right),
325            Err(MergeError::WriteThenRead {
326                write: value,
327                read: value2,
328            })
329        )
330    }
331
332    #[test]
333    fn test_err_merge_left_mod_neq_right_orig() {
334        let first_read = 1;
335        let value = create_value(first_read);
336
337        let second_read = 2;
338        let value2 = create_value(second_read);
339
340        let left = &mut Access::ReadThenWrite {
341            original: value.clone(),
342            modified: value2.clone(),
343        };
344
345        let right = Access::ReadThenWrite {
346            original: value.clone(),
347            modified: value2.clone(),
348        };
349
350        assert_eq!(
351            left.merge(right),
352            Err(MergeError::WriteThenRead {
353                write: value2,
354                read: value,
355            })
356        )
357    }
358
359    #[test]
360    fn test_err_merge_left_right_neq_right_orig() {
361        let first_read = 1;
362        let value = create_value(first_read);
363
364        let second_read = 2;
365        let value2 = create_value(second_read);
366
367        let left = &mut Access::Write(value.clone());
368        let right = Access::ReadThenWrite {
369            original: value2.clone(),
370            modified: value.clone(),
371        };
372
373        assert_eq!(
374            left.merge(right),
375            Err(MergeError::WriteThenRead {
376                write: value,
377                read: value2,
378            })
379        )
380    }
381}