@@ -66,9 +66,11 @@ TrxUndoRsegsIterator::TrxUndoRsegsIterator()
66
66
67
67
/* * Sets the next rseg to purge in purge_sys.
68
68
Executed in the purge coordinator thread.
69
- @return whether anything is to be purged */
70
- TRANSACTIONAL_INLINE inline bool TrxUndoRsegsIterator::set_next ()
69
+ @retval false when nothing is to be purged
70
+ @retval true when purge_sys.rseg->latch was locked */
71
+ inline bool TrxUndoRsegsIterator::set_next ()
71
72
{
73
+ ut_ad (!purge_sys.next_stored );
72
74
mysql_mutex_lock (&purge_sys.pq_mutex );
73
75
74
76
/* Only purge consumes events from the priority queue, user
@@ -106,23 +108,10 @@ TRANSACTIONAL_INLINE inline bool TrxUndoRsegsIterator::set_next()
106
108
ut_ad (purge_sys.rseg ->space ->id == TRX_SYS_SPACE
107
109
|| srv_is_undo_tablespace (purge_sys.rseg ->space ->id ));
108
110
109
- trx_id_t last_trx_no;
110
- {
111
- #ifdef SUX_LOCK_GENERIC
112
- purge_sys.rseg ->latch .rd_lock (SRW_LOCK_CALL);
113
- #else
114
- transactional_shared_lock_guard<srw_spin_lock> rg
115
- {purge_sys.rseg ->latch };
116
- #endif
117
- last_trx_no = purge_sys.rseg ->last_trx_no ();
118
-
119
- purge_sys.hdr_offset = purge_sys.rseg ->last_offset ();
120
- purge_sys.hdr_page_no = purge_sys.rseg ->last_page_no ;
121
-
122
- #ifdef SUX_LOCK_GENERIC
123
- purge_sys.rseg ->latch .rd_unlock ();
124
- #endif
125
- }
111
+ purge_sys.rseg ->latch .wr_lock (SRW_LOCK_CALL);
112
+ trx_id_t last_trx_no = purge_sys.rseg ->last_trx_no ();
113
+ purge_sys.hdr_offset = purge_sys.rseg ->last_offset ();
114
+ purge_sys.hdr_page_no = purge_sys.rseg ->last_page_no ;
126
115
127
116
/* Only the purge_coordinator_task will access this object
128
117
purge_sys.rseg_iter, or any of purge_sys.hdr_page_no,
@@ -839,18 +828,17 @@ TRANSACTIONAL_TARGET void trx_purge_truncate_history()
839
828
840
829
/* **********************************************************************/ /* *
841
830
Updates the last not yet purged history log info in rseg when we have purged
842
- a whole undo log. Advances also purge_sys.purge_trx_no past the purged log. */
843
- static void trx_purge_rseg_get_next_history_log (
844
- ulint* n_pages_handled) /* !< in/out: number of UNDO pages
845
- handled */
831
+ a whole undo log. Advances also purge_sys.purge_trx_no past the purged log.
832
+
833
+ @param n_pages_handled number of UNDO pages handled */
834
+ static void trx_purge_rseg_get_next_history_log (ulint *n_pages_handled)
846
835
{
847
836
fil_addr_t prev_log_addr;
848
837
mtr_t mtr;
849
838
850
839
mtr.start ();
851
840
852
- purge_sys.rseg ->latch .wr_lock (SRW_LOCK_CALL);
853
-
841
+ ut_ad (purge_sys.rseg ->latch .is_write_locked ());
854
842
ut_a (purge_sys.rseg ->last_page_no != FIL_NULL);
855
843
856
844
purge_sys.tail .trx_no = purge_sys.rseg ->last_trx_no () + 1 ;
@@ -874,50 +862,44 @@ static void trx_purge_rseg_get_next_history_log(
874
862
else
875
863
prev_log_addr.page = FIL_NULL;
876
864
877
- const bool empty= prev_log_addr.page == FIL_NULL;
878
-
879
- if (empty)
880
- /* No logs left in the history list */
881
- purge_sys.rseg ->last_page_no = FIL_NULL;
882
-
883
- purge_sys.rseg ->latch .wr_unlock ();
884
865
mtr.commit ();
885
866
886
- if (empty)
887
- return ;
888
-
889
- /* Read the previous log header. */
890
- mtr.start ();
891
-
892
- trx_id_t trx_no= 0 ;
893
-
894
- if (const buf_block_t * undo_page=
895
- buf_page_get_gen (page_id_t (purge_sys.rseg ->space ->id , prev_log_addr.page ),
896
- 0 , RW_S_LATCH, nullptr , BUF_GET_POSSIBLY_FREED, &mtr))
867
+ if (prev_log_addr.page == FIL_NULL)
868
+ purge_sys.rseg ->last_page_no = FIL_NULL;
869
+ else
897
870
{
898
- const byte *log_hdr= undo_page->page .frame + prev_log_addr.boffset ;
871
+ /* Read the previous log header. */
872
+ mtr.start ();
899
873
900
- trx_no= mach_read_from_8 (log_hdr + TRX_UNDO_TRX_NO);
901
- ut_ad (mach_read_from_2 (log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1 );
902
- }
874
+ trx_id_t trx_no= 0 ;
875
+ if (const buf_block_t * undo_page=
876
+ buf_page_get_gen (page_id_t (purge_sys.rseg ->space ->id ,
877
+ prev_log_addr.page ),
878
+ 0 , RW_S_LATCH, nullptr , BUF_GET_POSSIBLY_FREED, &mtr))
879
+ {
880
+ const byte *log_hdr= undo_page->page .frame + prev_log_addr.boffset ;
881
+ trx_no= mach_read_from_8 (log_hdr + TRX_UNDO_TRX_NO);
882
+ ut_ad (mach_read_from_2 (log_hdr + TRX_UNDO_NEEDS_PURGE) <= 1 );
883
+ }
903
884
904
- mtr.commit ();
885
+ mtr.commit ();
905
886
906
- if (UNIV_UNLIKELY (!trx_no))
907
- return ;
887
+ if (UNIV_LIKELY (trx_no != 0 ))
888
+ {
889
+ purge_sys.rseg ->last_page_no = prev_log_addr.page ;
890
+ purge_sys.rseg ->set_last_commit (prev_log_addr.boffset , trx_no);
908
891
909
- purge_sys.rseg ->latch .wr_lock (SRW_LOCK_CALL);
910
- purge_sys.rseg ->last_page_no = prev_log_addr.page ;
911
- purge_sys.rseg ->set_last_commit (prev_log_addr.boffset , trx_no);
892
+ /* Purge can also produce events, however these are already
893
+ ordered in the rollback segment and any user generated event
894
+ will be greater than the events that Purge produces. ie. Purge
895
+ can never produce events from an empty rollback segment. */
912
896
913
- /* Purge can also produce events, however these are already ordered
914
- in the rollback segment and any user generated event will be greater
915
- than the events that Purge produces. ie. Purge can never produce
916
- events from an empty rollback segment. */
897
+ mysql_mutex_lock (&purge_sys.pq_mutex );
898
+ purge_sys.purge_queue .push (*purge_sys.rseg );
899
+ mysql_mutex_unlock (&purge_sys.pq_mutex );
900
+ }
901
+ }
917
902
918
- mysql_mutex_lock (&purge_sys.pq_mutex );
919
- purge_sys.purge_queue .push (*purge_sys.rseg );
920
- mysql_mutex_unlock (&purge_sys.pq_mutex );
921
903
purge_sys.rseg ->latch .wr_unlock ();
922
904
}
923
905
@@ -965,16 +947,16 @@ static void trx_purge_read_undo_rec()
965
947
Chooses the next undo log to purge and updates the info in purge_sys. This
966
948
function is used to initialize purge_sys when the next record to purge is
967
949
not known, and also to update the purge system info on the next record when
968
- purge has handled the whole undo log for a transaction. */
969
- TRANSACTIONAL_TARGET static void trx_purge_choose_next_log ()
950
+ purge has handled the whole undo log for a transaction.
951
+ @retval false when nothing is to be purged
952
+ @retval true when purge_sys.rseg->latch was locked */
953
+ static bool trx_purge_choose_next_log ()
970
954
{
971
- ut_ad (!purge_sys.next_stored );
972
-
973
955
if (purge_sys.rseg_iter .set_next ()) {
974
956
trx_purge_read_undo_rec ();
957
+ return true ;
975
958
} else {
976
- /* There is nothing to do yet. */
977
- std::this_thread::yield ();
959
+ return false ;
978
960
}
979
961
}
980
962
@@ -995,9 +977,11 @@ trx_purge_get_next_rec(
995
977
996
978
ut_ad (purge_sys.next_stored );
997
979
ut_ad (purge_sys.tail .trx_no < purge_sys.low_limit_no ());
980
+ ut_ad (purge_sys.rseg ->latch .is_write_locked ());
998
981
999
982
const page_id_t page_id{purge_sys.rseg ->space ->id , purge_sys.page_no };
1000
983
const uint16_t offset = purge_sys.offset ;
984
+ bool locked = true ;
1001
985
1002
986
if (offset == 0 ) {
1003
987
/* It is the dummy undo log record, which means that there is
@@ -1007,19 +991,24 @@ trx_purge_get_next_rec(
1007
991
1008
992
/* Look for the next undo log and record to purge */
1009
993
1010
- trx_purge_choose_next_log ();
994
+ if (trx_purge_choose_next_log ()) {
995
+ purge_sys.rseg ->latch .wr_unlock ();
996
+ }
1011
997
return reinterpret_cast <trx_undo_rec_t *>(-1 );
1012
998
}
1013
999
1014
1000
mtr.start ();
1015
-
1001
+ trx_undo_rec_t *rec_copy = nullptr ;
1016
1002
const buf_block_t * undo_page
1017
1003
= buf_page_get_gen (page_id, 0 , RW_S_LATCH, nullptr ,
1018
1004
BUF_GET_POSSIBLY_FREED, &mtr);
1019
1005
if (UNIV_UNLIKELY (!undo_page)) {
1020
- corrupted:
1006
+ func_exit:
1007
+ if (locked) {
1008
+ purge_sys.rseg ->latch .wr_unlock ();
1009
+ }
1021
1010
mtr.commit ();
1022
- return nullptr ;
1011
+ return rec_copy ;
1023
1012
}
1024
1013
1025
1014
const buf_block_t * rec2_page = undo_page;
@@ -1040,15 +1029,15 @@ trx_purge_get_next_rec(
1040
1029
1041
1030
/* Look for the next undo log and record to purge */
1042
1031
1043
- trx_purge_choose_next_log ();
1032
+ locked = trx_purge_choose_next_log ();
1044
1033
1045
1034
mtr_start (&mtr);
1046
1035
1047
1036
undo_page = buf_page_get_gen (page_id, 0 , RW_S_LATCH,
1048
1037
nullptr , BUF_GET_POSSIBLY_FREED,
1049
1038
&mtr);
1050
1039
if (UNIV_UNLIKELY (!undo_page)) {
1051
- goto corrupted ;
1040
+ goto func_exit ;
1052
1041
}
1053
1042
} else {
1054
1043
purge_sys.offset = page_offset (rec2);
@@ -1061,11 +1050,8 @@ trx_purge_get_next_rec(
1061
1050
}
1062
1051
}
1063
1052
1064
- trx_undo_rec_t * rec_copy = trx_undo_rec_copy (undo_page->page .frame
1065
- + offset, heap);
1066
-
1067
- mtr.commit ();
1068
- return rec_copy;
1053
+ rec_copy = trx_undo_rec_copy (undo_page->page .frame + offset, heap);
1054
+ goto func_exit;
1069
1055
}
1070
1056
1071
1057
/* *******************************************************************/ /* *
@@ -1083,34 +1069,35 @@ trx_purge_fetch_next_rec(
1083
1069
handled */
1084
1070
mem_heap_t * heap) /* !< in: memory heap where copied */
1085
1071
{
1086
- if (!purge_sys.next_stored ) {
1087
- trx_purge_choose_next_log ();
1088
-
1089
- if (! purge_sys.next_stored ) {
1090
- DBUG_PRINT ( " ib_purge " ,
1091
- ( " no logs left in the history list " )) ;
1092
- return nullptr ;
1093
- }
1094
- }
1095
-
1096
- if (purge_sys. tail . trx_no >= purge_sys. low_limit_no ()) {
1097
- return nullptr ;
1098
- }
1099
-
1100
- /* fprintf(stderr, "Thread %lu purging trx %llu undo record %llu\n" ,
1101
- pthread_self(), iter->trx_no, iter->undo_no); */
1102
-
1103
- *roll_ptr = trx_undo_build_roll_ptr (
1104
- /* row_purge_record_func() will later set
1105
- ROLL_PTR_INSERT_FLAG for TRX_UNDO_INSERT_REC */
1106
- false ,
1107
- trx_sys. rseg_id (purge_sys. rseg , true ) ,
1108
- purge_sys.page_no , purge_sys. offset );
1109
-
1110
- /* The following call will advance the stored values of the
1111
- purge iterator. */
1072
+ if (!purge_sys.next_stored )
1073
+ {
1074
+ bool locked= trx_purge_choose_next_log ();
1075
+ ut_ad (locked == purge_sys.next_stored );
1076
+ if (!locked)
1077
+ return nullptr ;
1078
+ if (purge_sys. tail . trx_no >= purge_sys. low_limit_no ())
1079
+ {
1080
+ purge_sys. rseg -> latch . wr_unlock ();
1081
+ return nullptr ;
1082
+ }
1083
+ /* row_purge_record_func() will later set ROLL_PTR_INSERT_FLAG for
1084
+ TRX_UNDO_INSERT_REC */
1085
+ *roll_ptr= trx_undo_build_roll_ptr ( false ,
1086
+ trx_sys. rseg_id (purge_sys. rseg , true ) ,
1087
+ purge_sys. page_no , purge_sys. offset );
1088
+ }
1089
+ else if (purge_sys. tail . trx_no >= purge_sys. low_limit_no ())
1090
+ return nullptr ;
1091
+ else
1092
+ {
1093
+ *roll_ptr= trx_undo_build_roll_ptr ( false ,
1094
+ trx_sys. rseg_id ( purge_sys.rseg , true ),
1095
+ purge_sys. page_no , purge_sys. offset );
1096
+ purge_sys. rseg -> latch . wr_lock (SRW_LOCK_CALL);
1097
+ }
1112
1098
1113
- return trx_purge_get_next_rec (n_pages_handled, heap);
1099
+ /* The following will advance the purge iterator. */
1100
+ return trx_purge_get_next_rec (n_pages_handled, heap);
1114
1101
}
1115
1102
1116
1103
/* * Run a purge batch.
0 commit comments