@@ -21,6 +21,7 @@ pub struct SnapshotMap<K, V>
21
21
{
22
22
map : FxHashMap < K , V > ,
23
23
undo_log : Vec < UndoLog < K , V > > ,
24
+ num_open_snapshots : usize ,
24
25
}
25
26
26
27
// HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`.
@@ -31,6 +32,7 @@ impl<K, V> Default for SnapshotMap<K, V>
31
32
SnapshotMap {
32
33
map : Default :: default ( ) ,
33
34
undo_log : Default :: default ( ) ,
35
+ num_open_snapshots : 0 ,
34
36
}
35
37
}
36
38
}
@@ -40,8 +42,6 @@ pub struct Snapshot {
40
42
}
41
43
42
44
enum UndoLog < K , V > {
43
- OpenSnapshot ,
44
- CommittedSnapshot ,
45
45
Inserted ( K ) ,
46
46
Overwrite ( K , V ) ,
47
47
Purged ,
@@ -53,10 +53,11 @@ impl<K, V> SnapshotMap<K, V>
53
53
pub fn clear ( & mut self ) {
54
54
self . map . clear ( ) ;
55
55
self . undo_log . clear ( ) ;
56
+ self . num_open_snapshots = 0 ;
56
57
}
57
58
58
59
fn in_snapshot ( & self ) -> bool {
59
- ! self . undo_log . is_empty ( )
60
+ self . num_open_snapshots > 0
60
61
}
61
62
62
63
pub fn insert ( & mut self , key : K , value : V ) -> bool {
@@ -93,27 +94,27 @@ impl<K, V> SnapshotMap<K, V>
93
94
}
94
95
95
96
pub fn snapshot ( & mut self ) -> Snapshot {
96
- self . undo_log . push ( UndoLog :: OpenSnapshot ) ;
97
- let len = self . undo_log . len ( ) - 1 ;
97
+ let len = self . undo_log . len ( ) ;
98
+ self . num_open_snapshots += 1 ;
98
99
Snapshot { len }
99
100
}
100
101
101
102
fn assert_open_snapshot ( & self , snapshot : & Snapshot ) {
102
- assert ! ( snapshot. len < self . undo_log. len( ) ) ;
103
- assert ! ( match self . undo_log[ snapshot. len] {
104
- UndoLog :: OpenSnapshot => true ,
105
- _ => false ,
106
- } ) ;
103
+ assert ! ( self . undo_log. len( ) >= snapshot. len) ;
104
+ assert ! ( self . num_open_snapshots > 0 ) ;
107
105
}
108
106
109
107
pub fn commit ( & mut self , snapshot : Snapshot ) {
110
108
self . assert_open_snapshot ( & snapshot) ;
111
- if snapshot. len == 0 {
112
- // The root snapshot.
109
+ if self . num_open_snapshots == 1 {
110
+ // The root snapshot. It's safe to clear the undo log because
111
+ // there's no snapshot further out that we might need to roll back
112
+ // to.
113
+ assert ! ( snapshot. len == 0 ) ;
113
114
self . undo_log . clear ( ) ;
114
- } else {
115
- self . undo_log [ snapshot. len ] = UndoLog :: CommittedSnapshot ;
116
115
}
116
+
117
+ self . num_open_snapshots -= 1 ;
117
118
}
118
119
119
120
pub fn partial_rollback < F > ( & mut self ,
@@ -122,10 +123,8 @@ impl<K, V> SnapshotMap<K, V>
122
123
where F : Fn ( & K ) -> bool
123
124
{
124
125
self . assert_open_snapshot ( snapshot) ;
125
- for i in ( snapshot. len + 1 .. self . undo_log . len ( ) ) . rev ( ) {
126
+ for i in ( snapshot. len .. self . undo_log . len ( ) ) . rev ( ) {
126
127
let reverse = match self . undo_log [ i] {
127
- UndoLog :: OpenSnapshot => false ,
128
- UndoLog :: CommittedSnapshot => false ,
129
128
UndoLog :: Purged => false ,
130
129
UndoLog :: Inserted ( ref k) => should_revert_key ( k) ,
131
130
UndoLog :: Overwrite ( ref k, _) => should_revert_key ( k) ,
@@ -140,27 +139,16 @@ impl<K, V> SnapshotMap<K, V>
140
139
141
140
pub fn rollback_to ( & mut self , snapshot : Snapshot ) {
142
141
self . assert_open_snapshot ( & snapshot) ;
143
- while self . undo_log . len ( ) > snapshot. len + 1 {
142
+ while self . undo_log . len ( ) > snapshot. len {
144
143
let entry = self . undo_log . pop ( ) . unwrap ( ) ;
145
144
self . reverse ( entry) ;
146
145
}
147
146
148
- let v = self . undo_log . pop ( ) . unwrap ( ) ;
149
- assert ! ( match v {
150
- UndoLog :: OpenSnapshot => true ,
151
- _ => false ,
152
- } ) ;
153
- assert ! ( self . undo_log. len( ) == snapshot. len) ;
147
+ self . num_open_snapshots -= 1 ;
154
148
}
155
149
156
150
fn reverse ( & mut self , entry : UndoLog < K , V > ) {
157
151
match entry {
158
- UndoLog :: OpenSnapshot => {
159
- panic ! ( "cannot rollback an uncommitted snapshot" ) ;
160
- }
161
-
162
- UndoLog :: CommittedSnapshot => { }
163
-
164
152
UndoLog :: Inserted ( key) => {
165
153
self . map . remove ( & key) ;
166
154
}
0 commit comments