30
31
#include "page0zip.h"
31
32
#include "mtr0log.h"
32
33
#include "log0recv.h"
35
#ifndef UNIV_HOTBACKUP
33
36
#include "rem0cmp.h"
35
static ulint page_rnd = 976722341;
37
38
#ifdef PAGE_CUR_ADAPT
38
39
# ifdef UNIV_SEARCH_PERF_STAT
39
40
static ulint page_cur_short_succ = 0;
40
41
# endif /* UNIV_SEARCH_PERF_STAT */
42
/********************************************************************
43
Tries a search shortcut based on the last insert. */
43
/*******************************************************************//**
44
This is a linear congruential generator PRNG. Returns a pseudo random
45
number between 0 and 2^64-1 inclusive. The formula and the constants
47
X[n+1] = (a * X[n] + c) mod m
49
X[0] = ut_time_us(NULL)
50
a = 1103515245 (3^5 * 5 * 7 * 129749)
51
c = 12345 (3 * 5 * 823)
52
m = 18446744073709551616 (2^64)
54
@return number between 0 and 2^64-1 */
57
page_cur_lcg_prng(void)
58
/*===================*/
60
#define LCG_a 1103515245
62
static ib_uint64_t lcg_current = 0;
63
static ibool initialized = FALSE;
66
lcg_current = (ib_uint64_t) ut_time_us(NULL);
70
/* no need to "% 2^64" explicitly because lcg_current is
71
64 bit and this will be done anyway */
72
lcg_current = LCG_a * lcg_current + LCG_c;
77
/****************************************************************//**
78
Tries a search shortcut based on the last insert.
79
@return TRUE on success */
46
82
page_cur_try_search_shortcut(
47
83
/*=========================*/
48
/* out: TRUE on success */
49
const buf_block_t* block, /* in: index page */
50
const dict_index_t* index, /* in: record descriptor */
51
const dtuple_t* tuple, /* in: data tuple */
84
const buf_block_t* block, /*!< in: index page */
85
const dict_index_t* index, /*!< in: record descriptor */
86
const dtuple_t* tuple, /*!< in: data tuple */
52
87
ulint* iup_matched_fields,
53
/* in/out: already matched
88
/*!< in/out: already matched
54
89
fields in upper limit record */
55
90
ulint* iup_matched_bytes,
56
/* in/out: already matched
91
/*!< in/out: already matched
57
92
bytes in a field not yet
58
93
completely matched */
59
94
ulint* ilow_matched_fields,
60
/* in/out: already matched
95
/*!< in/out: already matched
61
96
fields in lower limit record */
62
97
ulint* ilow_matched_bytes,
63
/* in/out: already matched
98
/*!< in/out: already matched
64
99
bytes in a field not yet
65
100
completely matched */
66
page_cur_t* cursor) /* out: page cursor */
101
page_cur_t* cursor) /*!< out: page cursor */
69
104
const rec_t* next_rec;
156
191
#ifdef PAGE_CUR_LE_OR_EXTENDS
157
/********************************************************************
192
/****************************************************************//**
158
193
Checks if the nth field in a record is a character type field which extends
159
194
the nth field in tuple, i.e., the field is longer or equal in length and has
160
common first characters. */
195
common first characters.
196
@return TRUE if rec field extends tuple field */
163
199
page_cur_rec_field_extends(
164
200
/*=======================*/
165
/* out: TRUE if rec field
166
extends tuple field */
167
const dtuple_t* tuple, /* in: data tuple */
168
const rec_t* rec, /* in: record */
169
const ulint* offsets,/* in: array returned by rec_get_offsets() */
170
ulint n) /* in: compare nth field */
201
const dtuple_t* tuple, /*!< in: data tuple */
202
const rec_t* rec, /*!< in: record */
203
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
204
ulint n) /*!< in: compare nth field */
172
206
const dtype_t* type;
173
207
const dfield_t* dfield;
206
240
#endif /* PAGE_CUR_LE_OR_EXTENDS */
208
/********************************************************************
242
/****************************************************************//**
209
243
Searches the right position for a page cursor. */
212
246
page_cur_search_with_match(
213
247
/*=======================*/
214
const buf_block_t* block, /* in: buffer block */
215
const dict_index_t* index, /* in: record descriptor */
216
const dtuple_t* tuple, /* in: data tuple */
217
ulint mode, /* in: PAGE_CUR_L,
248
const buf_block_t* block, /*!< in: buffer block */
249
const dict_index_t* index, /*!< in: record descriptor */
250
const dtuple_t* tuple, /*!< in: data tuple */
251
ulint mode, /*!< in: PAGE_CUR_L,
218
252
PAGE_CUR_LE, PAGE_CUR_G, or
220
254
ulint* iup_matched_fields,
221
/* in/out: already matched
255
/*!< in/out: already matched
222
256
fields in upper limit record */
223
257
ulint* iup_matched_bytes,
224
/* in/out: already matched
258
/*!< in/out: already matched
225
259
bytes in a field not yet
226
260
completely matched */
227
261
ulint* ilow_matched_fields,
228
/* in/out: already matched
262
/*!< in/out: already matched
229
263
fields in lower limit record */
230
264
ulint* ilow_matched_bytes,
231
/* in/out: already matched
265
/*!< in/out: already matched
232
266
bytes in a field not yet
233
267
completely matched */
234
page_cur_t* cursor) /* out: page cursor */
268
page_cur_t* cursor) /*!< out: page cursor */
506
/***************************************************************
540
/***********************************************************//**
507
541
Positions a page cursor on a randomly chosen user record on a page. If there
508
542
are no user records, sets the cursor on the infimum record. */
511
545
page_cur_open_on_rnd_user_rec(
512
546
/*==========================*/
513
buf_block_t* block, /* in: page */
514
page_cur_t* cursor) /* out: page cursor */
547
buf_block_t* block, /*!< in: page */
548
page_cur_t* cursor) /*!< out: page cursor */
517
551
ulint n_recs = page_get_n_recs(buf_block_get_frame(block));
526
page_rnd += 87584577;
528
rnd = page_rnd % n_recs;
560
rnd = (ulint) (page_cur_lcg_prng() % n_recs);
531
563
page_cur_move_to_next(cursor);
535
/***************************************************************
567
/***********************************************************//**
536
568
Writes the log record of a record insert on a page. */
539
571
page_cur_insert_rec_write_log(
540
572
/*==========================*/
541
rec_t* insert_rec, /* in: inserted physical record */
542
ulint rec_size, /* in: insert_rec size */
543
rec_t* cursor_rec, /* in: record the
573
rec_t* insert_rec, /*!< in: inserted physical record */
574
ulint rec_size, /*!< in: insert_rec size */
575
rec_t* cursor_rec, /*!< in: record the
544
576
cursor is pointing to */
545
dict_index_t* index, /* in: record descriptor */
546
mtr_t* mtr) /* in: mini-transaction handle */
577
dict_index_t* index, /*!< in: record descriptor */
578
mtr_t* mtr) /*!< in: mini-transaction handle */
548
580
ulint cur_rec_size;
549
581
ulint extra_size;
713
745
mlog_catenate_string(mtr, ins_ptr, rec_size);
748
#else /* !UNIV_HOTBACKUP */
749
# define page_cur_insert_rec_write_log(ins_rec,size,cur,index,mtr) ((void) 0)
750
#endif /* !UNIV_HOTBACKUP */
717
/***************************************************************
718
Parses a log record of a record insert on a page. */
752
/***********************************************************//**
753
Parses a log record of a record insert on a page.
754
@return end of log record or NULL */
721
757
page_cur_parse_insert_rec(
722
758
/*======================*/
723
/* out: end of log record or NULL */
724
ibool is_short,/* in: TRUE if short inserts */
725
byte* ptr, /* in: buffer */
726
byte* end_ptr,/* in: buffer end */
727
buf_block_t* block, /* in: page or NULL */
728
dict_index_t* index, /* in: record descriptor */
729
mtr_t* mtr) /* in: mtr or NULL */
759
ibool is_short,/*!< in: TRUE if short inserts */
760
byte* ptr, /*!< in: buffer */
761
byte* end_ptr,/*!< in: buffer end */
762
buf_block_t* block, /*!< in: page or NULL */
763
dict_index_t* index, /*!< in: record descriptor */
764
mtr_t* mtr) /*!< in: mtr or NULL */
731
766
ulint origin_offset;
732
767
ulint end_seg_len;
905
940
return(ptr + end_seg_len);
908
/***************************************************************
943
/***********************************************************//**
909
944
Inserts a record next to page cursor on an uncompressed page.
910
945
Returns pointer to inserted record if succeed, i.e., enough
911
space available, NULL otherwise. The cursor stays at the same position. */
946
space available, NULL otherwise. The cursor stays at the same position.
947
@return pointer to record if succeed, NULL otherwise */
914
950
page_cur_insert_rec_low(
915
951
/*====================*/
916
/* out: pointer to record if succeed, NULL
918
rec_t* current_rec,/* in: pointer to current record after
952
rec_t* current_rec,/*!< in: pointer to current record after
919
953
which the new record is inserted */
920
dict_index_t* index, /* in: record descriptor */
921
const rec_t* rec, /* in: pointer to a physical record */
922
ulint* offsets,/* in/out: rec_get_offsets(rec, index) */
923
mtr_t* mtr) /* in: mini-transaction handle, or NULL */
954
dict_index_t* index, /*!< in: record descriptor */
955
const rec_t* rec, /*!< in: pointer to a physical record */
956
ulint* offsets,/*!< in/out: rec_get_offsets(rec, index) */
957
mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */
925
959
byte* insert_buf;
927
page_t* page; /* the relevant page */
928
rec_t* last_insert; /* cursor position at previous
961
page_t* page; /*!< the relevant page */
962
rec_t* last_insert; /*!< cursor position at previous
930
rec_t* free_rec; /* a free record that was reused,
964
rec_t* free_rec; /*!< a free record that was reused,
932
rec_t* insert_rec; /* inserted record */
933
ulint heap_no; /* heap number of the inserted
966
rec_t* insert_rec; /*!< inserted record */
967
ulint heap_no; /*!< heap number of the inserted
936
970
ut_ad(rec_offs_validate(rec, index, offsets));
1118
1152
return(insert_rec);
1121
/***************************************************************
1122
Compresses or reorganizes a page after an optimistic insert. */
1155
/***********************************************************//**
1156
Compresses or reorganizes a page after an optimistic insert.
1157
@return rec if succeed, NULL otherwise */
1125
1160
page_cur_insert_rec_zip_reorg(
1126
1161
/*==========================*/
1127
/* out: rec if succeed, NULL otherwise */
1128
rec_t** current_rec,/* in/out: pointer to current record after
1162
rec_t** current_rec,/*!< in/out: pointer to current record after
1129
1163
which the new record is inserted */
1130
buf_block_t* block, /* in: buffer block */
1131
dict_index_t* index, /* in: record descriptor */
1132
rec_t* rec, /* in: inserted record */
1133
page_t* page, /* in: uncompressed page */
1134
page_zip_des_t* page_zip,/* in: compressed page */
1135
mtr_t* mtr) /* in: mini-transaction, or NULL */
1164
buf_block_t* block, /*!< in: buffer block */
1165
dict_index_t* index, /*!< in: record descriptor */
1166
rec_t* rec, /*!< in: inserted record */
1167
page_t* page, /*!< in: uncompressed page */
1168
page_zip_des_t* page_zip,/*!< in: compressed page */
1169
mtr_t* mtr) /*!< in: mini-transaction, or NULL */
1171
/***************************************************************
1205
/***********************************************************//**
1172
1206
Inserts a record next to page cursor on a compressed and uncompressed
1173
1207
page. Returns pointer to inserted record if succeed, i.e.,
1174
1208
enough space available, NULL otherwise.
1175
The cursor stays at the same position. */
1209
The cursor stays at the same position.
1210
@return pointer to record if succeed, NULL otherwise */
1178
1213
page_cur_insert_rec_zip(
1179
1214
/*====================*/
1180
/* out: pointer to record if succeed, NULL
1182
rec_t** current_rec,/* in/out: pointer to current record after
1215
rec_t** current_rec,/*!< in/out: pointer to current record after
1183
1216
which the new record is inserted */
1184
buf_block_t* block, /* in: buffer block of *current_rec */
1185
dict_index_t* index, /* in: record descriptor */
1186
const rec_t* rec, /* in: pointer to a physical record */
1187
ulint* offsets,/* in/out: rec_get_offsets(rec, index) */
1188
mtr_t* mtr) /* in: mini-transaction handle, or NULL */
1217
buf_block_t* block, /*!< in: buffer block of *current_rec */
1218
dict_index_t* index, /*!< in: record descriptor */
1219
const rec_t* rec, /*!< in: pointer to a physical record */
1220
ulint* offsets,/*!< in/out: rec_get_offsets(rec, index) */
1221
mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */
1190
1223
byte* insert_buf;
1191
1224
ulint rec_size;
1192
page_t* page; /* the relevant page */
1193
rec_t* last_insert; /* cursor position at previous
1225
page_t* page; /*!< the relevant page */
1226
rec_t* last_insert; /*!< cursor position at previous
1195
rec_t* free_rec; /* a free record that was reused,
1228
rec_t* free_rec; /*!< a free record that was reused,
1197
rec_t* insert_rec; /* inserted record */
1198
ulint heap_no; /* heap number of the inserted
1230
rec_t* insert_rec; /*!< inserted record */
1231
ulint heap_no; /*!< heap number of the inserted
1200
1233
page_zip_des_t* page_zip;
1466
1499
return(insert_rec);
1469
/**************************************************************
1470
Writes a log record of copying a record list end to a new created page. */
1502
#ifndef UNIV_HOTBACKUP
1503
/**********************************************************//**
1504
Writes a log record of copying a record list end to a new created page.
1505
@return 4-byte field where to write the log data length, or NULL if
1506
logging is disabled */
1473
1509
page_copy_rec_list_to_created_page_write_log(
1474
1510
/*=========================================*/
1475
/* out: 4-byte field where to
1476
write the log data length,
1477
or NULL if logging is disabled */
1478
page_t* page, /* in: index page */
1479
dict_index_t* index, /* in: record descriptor */
1480
mtr_t* mtr) /* in: mtr */
1511
page_t* page, /*!< in: index page */
1512
dict_index_t* index, /*!< in: record descriptor */
1513
mtr_t* mtr) /*!< in: mtr */
1494
1527
return(log_ptr);
1529
#endif /* !UNIV_HOTBACKUP */
1497
/**************************************************************
1498
Parses a log record of copying a record list end to a new created page. */
1531
/**********************************************************//**
1532
Parses a log record of copying a record list end to a new created page.
1533
@return end of log record or NULL */
1501
1536
page_parse_copy_rec_list_to_created_page(
1502
1537
/*=====================================*/
1503
/* out: end of log record or NULL */
1504
byte* ptr, /* in: buffer */
1505
byte* end_ptr,/* in: buffer end */
1506
buf_block_t* block, /* in: page or NULL */
1507
dict_index_t* index, /* in: record descriptor */
1508
mtr_t* mtr) /* in: mtr or NULL */
1538
byte* ptr, /*!< in: buffer */
1539
byte* end_ptr,/*!< in: buffer end */
1540
buf_block_t* block, /*!< in: page or NULL */
1541
dict_index_t* index, /*!< in: record descriptor */
1542
mtr_t* mtr) /*!< in: mtr or NULL */
1511
1545
ulint log_data_len;
1550
1584
return(rec_end);
1553
/*****************************************************************
1587
#ifndef UNIV_HOTBACKUP
1588
/*************************************************************//**
1554
1589
Copies records from page to a newly created page, from a given record onward,
1555
1590
including that record. Infimum and supremum records are not copied. */
1558
1593
page_copy_rec_list_end_to_created_page(
1559
1594
/*===================================*/
1560
page_t* new_page, /* in/out: index page to copy to */
1561
rec_t* rec, /* in: first record to copy */
1562
dict_index_t* index, /* in: record descriptor */
1563
mtr_t* mtr) /* in: mtr */
1595
page_t* new_page, /*!< in/out: index page to copy to */
1596
rec_t* rec, /*!< in: first record to copy */
1597
dict_index_t* index, /*!< in: record descriptor */
1598
mtr_t* mtr) /*!< in: mtr */
1565
1600
page_dir_slot_t* slot = 0; /* remove warning */
1566
1601
byte* heap_top;
1723
1758
mtr_set_log_mode(mtr, log_mode);
1726
/***************************************************************
1761
/***********************************************************//**
1727
1762
Writes log record of a record delete on a page. */
1730
1765
page_cur_delete_rec_write_log(
1731
1766
/*==========================*/
1732
rec_t* rec, /* in: record to be deleted */
1733
dict_index_t* index, /* in: record descriptor */
1734
mtr_t* mtr) /* in: mini-transaction handle */
1767
rec_t* rec, /*!< in: record to be deleted */
1768
dict_index_t* index, /*!< in: record descriptor */
1769
mtr_t* mtr) /*!< in: mini-transaction handle */
1754
1789
mlog_close(mtr, log_ptr + 2);
1791
#else /* !UNIV_HOTBACKUP */
1792
# define page_cur_delete_rec_write_log(rec,index,mtr) ((void) 0)
1793
#endif /* !UNIV_HOTBACKUP */
1757
/***************************************************************
1758
Parses log record of a record delete on a page. */
1795
/***********************************************************//**
1796
Parses log record of a record delete on a page.
1797
@return pointer to record end or NULL */
1761
1800
page_cur_parse_delete_rec(
1762
1801
/*======================*/
1763
/* out: pointer to record end or NULL */
1764
byte* ptr, /* in: buffer */
1765
byte* end_ptr,/* in: buffer end */
1766
buf_block_t* block, /* in: page or NULL */
1767
dict_index_t* index, /* in: record descriptor */
1768
mtr_t* mtr) /* in: mtr or NULL */
1802
byte* ptr, /*!< in: buffer */
1803
byte* end_ptr,/*!< in: buffer end */
1804
buf_block_t* block, /*!< in: page or NULL */
1805
dict_index_t* index, /*!< in: record descriptor */
1806
mtr_t* mtr) /*!< in: mtr or NULL */
1771
1809
page_cur_t cursor;
1806
/***************************************************************
1844
/***********************************************************//**
1807
1845
Deletes a record at the page cursor. The cursor is moved to the next
1808
1846
record after the deleted one. */
1811
1849
page_cur_delete_rec(
1812
1850
/*================*/
1813
page_cur_t* cursor, /* in/out: a page cursor */
1814
dict_index_t* index, /* in: record descriptor */
1815
const ulint* offsets,/* in: rec_get_offsets(cursor->rec, index) */
1816
mtr_t* mtr) /* in: mini-transaction handle */
1851
page_cur_t* cursor, /*!< in/out: a page cursor */
1852
dict_index_t* index, /*!< in: record descriptor */
1853
const ulint* offsets,/*!< in: rec_get_offsets(cursor->rec, index) */
1854
mtr_t* mtr) /*!< in: mini-transaction handle */
1818
1856
page_dir_slot_t* cur_dir_slot;
1819
1857
page_dir_slot_t* prev_slot;
1920
1958
ut_a(!page_zip || page_zip_validate(page_zip, page));
1921
1959
#endif /* UNIV_ZIP_DEBUG */
1962
#ifdef UNIV_COMPILE_TEST_FUNCS
1964
/*******************************************************************//**
1965
Print the first n numbers, generated by page_cur_lcg_prng() to make sure
1966
(visually) that it works properly. */
1968
test_page_cur_lcg_prng(
1969
/*===================*/
1970
int n) /*!< in: print first n numbers */
1973
unsigned long long rnd;
1975
for (i = 0; i < n; i++) {
1976
rnd = page_cur_lcg_prng();
1977
printf("%llu\t%%2=%llu %%3=%llu %%5=%llu %%7=%llu %%11=%llu\n",
1987
#endif /* UNIV_COMPILE_TEST_FUNCS */