@@ -70,7 +70,7 @@ impl super::Store {
7070 ) -> Result < Option < Snapshot > , Error > {
7171 let index = self . index . load ( ) ;
7272 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*/ ) ;
7474 }
7575
7676 if marker. generation != index. generation || marker. state_id != index. state_id ( ) {
@@ -86,7 +86,7 @@ impl super::Store {
8686 match refresh_mode {
8787 RefreshMode :: Never => Ok ( None ) ,
8888 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*/ )
9090 }
9191 }
9292 }
@@ -166,7 +166,11 @@ impl super::Store {
166166
167167 /// refresh and possibly clear out our existing data structures, causing all pack ids to be invalidated.
168168 /// `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 > {
170174 let index = self . index . load ( ) ;
171175 let previous_index_state = Arc :: as_ptr ( & index) as usize ;
172176
@@ -182,6 +186,15 @@ impl super::Store {
182186 }
183187
184188 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+ }
185198 self . num_disk_state_consolidation . fetch_add ( 1 , Ordering :: Relaxed ) ;
186199
187200 let db_paths: Vec < _ > = std:: iter:: once ( objects_directory. to_owned ( ) )
0 commit comments