MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
trx0rseg.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "trx0rseg.h"
27 
28 #ifdef UNIV_NONINL
29 #include "trx0rseg.ic"
30 #endif
31 
32 #include "trx0undo.h"
33 #include "fut0lst.h"
34 #include "srv0srv.h"
35 #include "trx0purge.h"
36 #include "ut0bh.h"
37 #include "srv0mon.h"
38 
39 #ifdef UNIV_PFS_MUTEX
40 /* Key to register rseg_mutex_key with performance schema */
41 UNIV_INTERN mysql_pfs_key_t rseg_mutex_key;
42 #endif /* UNIV_PFS_MUTEX */
43 
44 /****************************************************************/
48 UNIV_INTERN
49 ulint
51 /*===================*/
52  ulint space,
53  ulint zip_size,
55  ulint max_size,
56  ulint rseg_slot_no,
57  mtr_t* mtr)
58 {
59  ulint page_no;
60  trx_rsegf_t* rsegf;
61  trx_sysf_t* sys_header;
62  ulint i;
64 
65  ut_ad(mtr);
66  ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
67  MTR_MEMO_X_LOCK));
68 
69  /* Allocate a new file segment for the rollback segment */
70  block = fseg_create(space, 0, TRX_RSEG + TRX_RSEG_FSEG_HEADER, mtr);
71 
72  if (block == NULL) {
73  /* No space left */
74 
75  return(FIL_NULL);
76  }
77 
78  buf_block_dbg_add_level(block, SYNC_RSEG_HEADER_NEW);
79 
80  page_no = buf_block_get_page_no(block);
81 
82  /* Get the rollback segment file page */
83  rsegf = trx_rsegf_get_new(space, zip_size, page_no, mtr);
84 
85  /* Initialize max size field */
86  mlog_write_ulint(rsegf + TRX_RSEG_MAX_SIZE, max_size,
87  MLOG_4BYTES, mtr);
88 
89  /* Initialize the history list */
90 
91  mlog_write_ulint(rsegf + TRX_RSEG_HISTORY_SIZE, 0, MLOG_4BYTES, mtr);
92  flst_init(rsegf + TRX_RSEG_HISTORY, mtr);
93 
94  /* Reset the undo log slots */
95  for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
96 
97  trx_rsegf_set_nth_undo(rsegf, i, FIL_NULL, mtr);
98  }
99 
100  /* Add the rollback segment info to the free slot in
101  the trx system header */
102 
103  sys_header = trx_sysf_get(mtr);
104 
105  trx_sysf_rseg_set_space(sys_header, rseg_slot_no, space, mtr);
106  trx_sysf_rseg_set_page_no(sys_header, rseg_slot_no, page_no, mtr);
107 
108  return(page_no);
109 }
110 
111 /***********************************************************************/
113 UNIV_INTERN
114 void
116 /*==============*/
117  trx_rseg_t* rseg) /* in, own: instance to free */
118 {
119  trx_undo_t* undo;
120  trx_undo_t* next_undo;
121 
122  mutex_free(&rseg->mutex);
123 
124  /* There can't be any active transactions. */
125  ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0);
126  ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0);
127 
128  for (undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
129  undo != NULL;
130  undo = next_undo) {
131 
132  next_undo = UT_LIST_GET_NEXT(undo_list, undo);
133 
134  UT_LIST_REMOVE(undo_list, rseg->update_undo_cached, undo);
135 
136  MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
137 
138  trx_undo_mem_free(undo);
139  }
140 
141  for (undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
142  undo != NULL;
143  undo = next_undo) {
144 
145  next_undo = UT_LIST_GET_NEXT(undo_list, undo);
146 
147  UT_LIST_REMOVE(undo_list, rseg->insert_undo_cached, undo);
148 
149  MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
150 
151  trx_undo_mem_free(undo);
152  }
153 
154  /* const_cast<trx_rseg_t*>() because this function is
155  like a destructor. */
156 
157  *((trx_rseg_t**) trx_sys->rseg_array + rseg->id) = NULL;
158 
159  mem_free(rseg);
160 }
161 
162 /***************************************************************************
163 Creates and initializes a rollback segment object. The values for the
164 fields are read from the header. The object is inserted to the rseg
165 list of the trx system object and a pointer is inserted in the rseg
166 array in the trx system object.
167 @return own: rollback segment object */
168 static
169 trx_rseg_t*
170 trx_rseg_mem_create(
171 /*================*/
172  ulint id,
173  ulint space,
175  ulint zip_size,
177  ulint page_no,
179  ib_bh_t* ib_bh,
180  mtr_t* mtr)
181 {
182  ulint len;
183  trx_rseg_t* rseg;
184  fil_addr_t node_addr;
185  trx_rsegf_t* rseg_header;
186  trx_ulogf_t* undo_log_hdr;
187  ulint sum_of_undo_sizes;
188 
189  rseg = static_cast<trx_rseg_t*>(mem_zalloc(sizeof(trx_rseg_t)));
190 
191  rseg->id = id;
192  rseg->space = space;
193  rseg->zip_size = zip_size;
194  rseg->page_no = page_no;
195 
196  mutex_create(rseg_mutex_key, &rseg->mutex, SYNC_RSEG);
197 
198  /* const_cast<trx_rseg_t*>() because this function is
199  like a constructor. */
200  *((trx_rseg_t**) trx_sys->rseg_array + rseg->id) = rseg;
201 
202  rseg_header = trx_rsegf_get_new(space, zip_size, page_no, mtr);
203 
204  rseg->max_size = mtr_read_ulint(
205  rseg_header + TRX_RSEG_MAX_SIZE, MLOG_4BYTES, mtr);
206 
207  /* Initialize the undo log lists according to the rseg header */
208 
209  sum_of_undo_sizes = trx_undo_lists_init(rseg);
210 
211  rseg->curr_size = mtr_read_ulint(
212  rseg_header + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, mtr)
213  + 1 + sum_of_undo_sizes;
214 
215  len = flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr);
216 
217  if (len > 0) {
218  rseg_queue_t rseg_queue;
219 
220  trx_sys->rseg_history_len += len;
221 
222  node_addr = trx_purge_get_log_from_hist(
223  flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr));
224 
225  rseg->last_page_no = node_addr.page;
226  rseg->last_offset = node_addr.boffset;
227 
228  undo_log_hdr = trx_undo_page_get(
229  rseg->space, rseg->zip_size, node_addr.page,
230  mtr) + node_addr.boffset;
231 
233  undo_log_hdr + TRX_UNDO_TRX_NO);
234 
236  undo_log_hdr + TRX_UNDO_DEL_MARKS, MLOG_2BYTES, mtr);
237 
238  rseg_queue.rseg = rseg;
239  rseg_queue.trx_no = rseg->last_trx_no;
240 
241  if (rseg->last_page_no != FIL_NULL) {
242  const void* ptr;
243 
244  /* There is no need to cover this operation by the purge
245  mutex because we are still bootstrapping. */
246 
247  ptr = ib_bh_push(ib_bh, &rseg_queue);
248  ut_a(ptr != NULL);
249  }
250  } else {
251  rseg->last_page_no = FIL_NULL;
252  }
253 
254  return(rseg);
255 }
256 
257 /********************************************************************
258 Creates the memory copies for the rollback segments and initializes the
259 rseg array in trx_sys at a database startup. */
260 static
261 void
262 trx_rseg_create_instance(
263 /*=====================*/
264  trx_sysf_t* sys_header,
265  ib_bh_t* ib_bh,
266  mtr_t* mtr)
267 {
268  ulint i;
269 
270  for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
271  ulint page_no;
272 
273  page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
274 
275  if (page_no != FIL_NULL) {
276  ulint space;
277  ulint zip_size;
278  trx_rseg_t* rseg = NULL;
279 
281 
282  space = trx_sysf_rseg_get_space(sys_header, i, mtr);
283 
284  zip_size = space ? fil_space_get_zip_size(space) : 0;
285 
286  rseg = trx_rseg_mem_create(
287  i, space, zip_size, page_no, ib_bh, mtr);
288 
289  ut_a(rseg->id == i);
290  } else {
291  ut_a(trx_sys->rseg_array[i] == NULL);
292  }
293  }
294 }
295 
296 /*********************************************************************
297 Creates a rollback segment.
298 @return pointer to new rollback segment if create successful */
299 UNIV_INTERN
300 trx_rseg_t*
302 /*============*/
303  ulint space)
304 {
305  mtr_t mtr;
306  ulint slot_no;
307  trx_rseg_t* rseg = NULL;
308 
309  mtr_start(&mtr);
310 
311  /* To obey the latching order, acquire the file space
312  x-latch before the trx_sys->mutex. */
313  mtr_x_lock(fil_space_get_latch(space, NULL), &mtr);
314 
315  slot_no = trx_sysf_rseg_find_free(&mtr);
316 
317  if (slot_no != ULINT_UNDEFINED) {
318  ulint id;
319  ulint page_no;
320  ulint zip_size;
321  trx_sysf_t* sys_header;
322 
323  page_no = trx_rseg_header_create(
324  space, 0, ULINT_MAX, slot_no, &mtr);
325 
326  ut_a(page_no != FIL_NULL);
327 
328  sys_header = trx_sysf_get(&mtr);
329 
330  id = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr);
331  ut_a(id == space);
332 
333  zip_size = space ? fil_space_get_zip_size(space) : 0;
334 
335  rseg = trx_rseg_mem_create(
336  slot_no, space, zip_size, page_no,
337  purge_sys->ib_bh, &mtr);
338  }
339 
340  mtr_commit(&mtr);
341 
342  return(rseg);
343 }
344 
345 /*********************************************************************/
348 UNIV_INTERN
349 void
351 /*================*/
352  trx_sysf_t* sys_header, /* in/out: trx system header */
353  ib_bh_t* ib_bh,
354  mtr_t* mtr)
355 {
357 
358  trx_rseg_create_instance(sys_header, ib_bh, mtr);
359 }
360 
361 /********************************************************************
362 Get the number of unique rollback tablespaces in use except space id 0.
363 The last space id will be the sentinel value ULINT_UNDEFINED. The array
364 will be sorted on space id. Note: space_ids should have have space for
365 TRX_SYS_N_RSEGS + 1 elements.
366 @return number of unique rollback tablespaces in use. */
367 UNIV_INTERN
368 ulint
370 /*============================*/
371  ulint* space_ids)
373 {
374  ulint i;
375  mtr_t mtr;
376  trx_sysf_t* sys_header;
377  ulint n_undo_tablespaces = 0;
378  ulint space_ids_aux[TRX_SYS_N_RSEGS + 1];
379 
380  mtr_start(&mtr);
381 
382  sys_header = trx_sysf_get(&mtr);
383 
384  for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
385  ulint page_no;
386  ulint space;
387 
388  page_no = trx_sysf_rseg_get_page_no(sys_header, i, &mtr);
389 
390  if (page_no == FIL_NULL) {
391  continue;
392  }
393 
394  space = trx_sysf_rseg_get_space(sys_header, i, &mtr);
395 
396  if (space != 0) {
397  ulint j;
398  ibool found = FALSE;
399 
400  for (j = 0; j < n_undo_tablespaces; ++j) {
401  if (space_ids[j] == space) {
402  found = TRUE;
403  break;
404  }
405  }
406 
407  if (!found) {
408  ut_a(n_undo_tablespaces <= i);
409  space_ids[n_undo_tablespaces++] = space;
410  }
411  }
412  }
413 
414  mtr_commit(&mtr);
415 
416  ut_a(n_undo_tablespaces <= TRX_SYS_N_RSEGS);
417 
418  space_ids[n_undo_tablespaces] = ULINT_UNDEFINED;
419 
420  if (n_undo_tablespaces > 0) {
421  ut_ulint_sort(space_ids, space_ids_aux, 0, n_undo_tablespaces);
422  }
423 
424  return(n_undo_tablespaces);
425 }