@@ -699,10 +699,21 @@ namespace db0
699699 dram_changelog_io_pos = m_dram_changelog_io.getStreamPos ();
700700 if (!!m_ext_space) {
701701 assert (m_ext_dram_changelog_io);
702+ m_ext_dram_changelog_io->refresh ();
702703 ext_dram_state_num = m_ext_dram_io->beginApplyChanges (*m_ext_dram_changelog_io);
703704 ext_dram_changelog_io_pos = m_ext_dram_changelog_io->getStreamPos ();
704705 }
705706
707+ if (dram_state_num && m_dram_io.completeApplyChanges (*dram_state_num)) {
708+ // refresh underlying sparse index / diff index after DRAM update
709+ m_sparse_pair.refresh ();
710+ }
711+ if (!!m_ext_space && ext_dram_state_num && m_ext_dram_io->completeApplyChanges (*ext_dram_state_num)) {
712+ m_ext_space.refresh ();
713+ }
714+
715+ // this is the state number to sync-up to
716+ auto max_state_num = m_sparse_pair.getMaxStateNum ();
706717 // send all page-update notifications to the provided handler
707718 if (on_page_updated) {
708719 StateNumType updated_state_num = 0 ;
@@ -711,22 +722,33 @@ namespace db0
711722 auto reader = m_dp_changelog_io.getStreamReader ();
712723 // feed the reader with all available chunks, in case of IOException the stream is getting reverted
713724 // this is to make the operation atomic
714- while (reader.readChangeLogChunk ());
725+ while (auto chunk_ptr = reader.readChangeLogChunk ()) {
726+ if (chunk_ptr->m_state_num == max_state_num) {
727+ // stop at the max known state number
728+ break ;
729+ }
730+ if (chunk_ptr->m_state_num > max_state_num) {
731+ // NOTE: this critical and irrecoverable error indicates corruption of the DP changelog stream
732+ THROWF (db0::InternalException) << " Inconsistent state: DP changelog state number "
733+ << chunk_ptr->m_state_num << " exceeds max known state number " << max_state_num;
734+ }
735+ }
715736
716737 // reset to read all updates again
717738 reader.reset ();
718739 for (;;) {
719740 auto dp_change_log_ptr = reader.readChangeLogChunk ();
720- if (!dp_change_log_ptr) {
741+ if (!dp_change_log_ptr || dp_change_log_ptr->m_state_num > max_state_num) {
742+ // end of the stream or the max known state number reached
721743 break ;
722744 }
723745
724746 assert (dp_change_log_ptr->m_state_num != updated_state_num);
725747 updated_state_num = dp_change_log_ptr->m_state_num ;
726- // Elements are storage page numbers (mutated in that transaction)
727- for (auto storage_page_num : *dp_change_log_ptr) {
728- on_page_updated (storage_page_num , updated_state_num);
729- }
748+ // Elements are logical page numbers (mutated in that transaction)
749+ for (auto page_num : *dp_change_log_ptr) {
750+ on_page_updated (page_num , updated_state_num);
751+ }
730752 }
731753 }
732754
@@ -740,13 +762,6 @@ namespace db0
740762 result = m_file.getLastModifiedTime ();
741763 }
742764
743- if (dram_state_num && m_dram_io.completeApplyChanges (*dram_state_num)) {
744- // refresh underlying sparse index / diff index after DRAM update
745- m_sparse_pair.refresh ();
746- }
747- if (!!m_ext_space && ext_dram_state_num && m_ext_dram_io->completeApplyChanges (*ext_dram_state_num)) {
748- m_ext_space.refresh ();
749- }
750765 m_meta_io.refresh ();
751766 // refresh cycle complete
752767 m_refresh_pending = false ;
@@ -888,7 +903,9 @@ namespace db0
888903
889904 // assure copied streams are consistent
890905 if (dp_header->m_state_num != max_state_num) {
891- THROWF (db0::IOException) << " BDevStorage::copyTo: inconsistent max_state_num in DP changelog" ;
906+ THROWF (db0::IOException)
907+ << " BDevStorage::copyTo: inconsistent max_state_num in DP changelog: "
908+ << (StateNumType)(dp_header->m_state_num ) << " != " << max_state_num;
892909 }
893910 std::uint64_t end_page_num = dp_header->m_end_storage_page_num ;
894911 // NOTE: end_page_num may be relative, need to translate to absolute
0 commit comments