@@ -70,7 +70,7 @@ impl super::Store {
70
70
) -> Result < Option < Snapshot > , Error > {
71
71
let index = self . index . load ( ) ;
72
72
if !index. is_initialized ( ) {
73
- return self . consolidate_with_disk_state ( false /*load one new index*/ ) ;
73
+ return self . consolidate_with_disk_state ( true /* needs_init */ , false /*load one new index*/ ) ;
74
74
}
75
75
76
76
if marker. generation != index. generation || marker. state_id != index. state_id ( ) {
@@ -86,7 +86,7 @@ impl super::Store {
86
86
match refresh_mode {
87
87
RefreshMode :: Never => Ok ( None ) ,
88
88
RefreshMode :: AfterAllIndicesLoaded => {
89
- self . consolidate_with_disk_state ( true /*load one new index*/ )
89
+ self . consolidate_with_disk_state ( false /* needs init */ , true /*load one new index*/ )
90
90
}
91
91
}
92
92
}
@@ -166,7 +166,11 @@ impl super::Store {
166
166
167
167
/// refresh and possibly clear out our existing data structures, causing all pack ids to be invalidated.
168
168
/// `load_new_index` is an optimization to at least provide one newly loaded pack after refreshing the slot map.
169
- pub ( crate ) fn consolidate_with_disk_state ( & self , load_new_index : bool ) -> Result < Option < Snapshot > , Error > {
169
+ pub ( crate ) fn consolidate_with_disk_state (
170
+ & self ,
171
+ needs_init : bool ,
172
+ load_new_index : bool ,
173
+ ) -> Result < Option < Snapshot > , Error > {
170
174
let index = self . index . load ( ) ;
171
175
let previous_index_state = Arc :: as_ptr ( & index) as usize ;
172
176
@@ -182,6 +186,15 @@ impl super::Store {
182
186
}
183
187
184
188
let was_uninitialized = !index. is_initialized ( ) ;
189
+
190
+ // We might not be able to detect by pointer if the state changed, as this itself is racy. So we keep track of double-initialization
191
+ // using a flag, which means that if `needs_init` was true we saw the index uninitialized once, but now that we are here it's
192
+ // initialized meaning that somebody was faster and we couldn't detect it by comparisons to the index.
193
+ // If so, make sure we collect the snapshot instead of returning None in case nothing actually changed, which is likely with a
194
+ // race like this.
195
+ if !was_uninitialized && needs_init {
196
+ return Ok ( Some ( self . collect_snapshot ( ) ) ) ;
197
+ }
185
198
self . num_disk_state_consolidation . fetch_add ( 1 , Ordering :: Relaxed ) ;
186
199
187
200
let db_paths: Vec < _ > = std:: iter:: once ( objects_directory. to_owned ( ) )
0 commit comments