@@ -21,6 +21,7 @@ pub struct SnapshotMap<K, V>
2121{
2222 map : FxHashMap < K , V > ,
2323 undo_log : Vec < UndoLog < K , V > > ,
24+ num_open_snapshots : usize ,
2425}
2526
2627// HACK(eddyb) manual impl avoids `Default` bounds on `K` and `V`.
@@ -31,6 +32,7 @@ impl<K, V> Default for SnapshotMap<K, V>
3132 SnapshotMap {
3233 map : Default :: default ( ) ,
3334 undo_log : Default :: default ( ) ,
35+ num_open_snapshots : 0 ,
3436 }
3537 }
3638}
@@ -40,8 +42,6 @@ pub struct Snapshot {
4042}
4143
4244enum UndoLog < K , V > {
43- OpenSnapshot ,
44- CommittedSnapshot ,
4545 Inserted ( K ) ,
4646 Overwrite ( K , V ) ,
4747 Purged ,
@@ -53,10 +53,11 @@ impl<K, V> SnapshotMap<K, V>
5353 pub fn clear ( & mut self ) {
5454 self . map . clear ( ) ;
5555 self . undo_log . clear ( ) ;
56+ self . num_open_snapshots = 0 ;
5657 }
5758
5859 fn in_snapshot ( & self ) -> bool {
59- ! self . undo_log . is_empty ( )
60+ self . num_open_snapshots > 0
6061 }
6162
6263 pub fn insert ( & mut self , key : K , value : V ) -> bool {
@@ -93,27 +94,27 @@ impl<K, V> SnapshotMap<K, V>
9394 }
9495
9596 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 ;
9899 Snapshot { len }
99100 }
100101
101102 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 ) ;
107105 }
108106
109107 pub fn commit ( & mut self , snapshot : Snapshot ) {
110108 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 ) ;
113114 self . undo_log . clear ( ) ;
114- } else {
115- self . undo_log [ snapshot. len ] = UndoLog :: CommittedSnapshot ;
116115 }
116+
117+ self . num_open_snapshots -= 1 ;
117118 }
118119
119120 pub fn partial_rollback < F > ( & mut self ,
@@ -122,10 +123,8 @@ impl<K, V> SnapshotMap<K, V>
122123 where F : Fn ( & K ) -> bool
123124 {
124125 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 ( ) {
126127 let reverse = match self . undo_log [ i] {
127- UndoLog :: OpenSnapshot => false ,
128- UndoLog :: CommittedSnapshot => false ,
129128 UndoLog :: Purged => false ,
130129 UndoLog :: Inserted ( ref k) => should_revert_key ( k) ,
131130 UndoLog :: Overwrite ( ref k, _) => should_revert_key ( k) ,
@@ -140,27 +139,16 @@ impl<K, V> SnapshotMap<K, V>
140139
141140 pub fn rollback_to ( & mut self , snapshot : Snapshot ) {
142141 self . assert_open_snapshot ( & snapshot) ;
143- while self . undo_log . len ( ) > snapshot. len + 1 {
142+ while self . undo_log . len ( ) > snapshot. len {
144143 let entry = self . undo_log . pop ( ) . unwrap ( ) ;
145144 self . reverse ( entry) ;
146145 }
147146
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 ;
154148 }
155149
156150 fn reverse ( & mut self , entry : UndoLog < K , V > ) {
157151 match entry {
158- UndoLog :: OpenSnapshot => {
159- panic ! ( "cannot rollback an uncommitted snapshot" ) ;
160- }
161-
162- UndoLog :: CommittedSnapshot => { }
163-
164152 UndoLog :: Inserted ( key) => {
165153 self . map . remove ( & key) ;
166154 }
0 commit comments