Merge lp:~laurynas-biveinis/percona-server/bug54330 into lp:percona-server/5.5

Proposed by Laurynas Biveinis
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 224
Proposed branch: lp:~laurynas-biveinis/percona-server/bug54330
Merge into: lp:percona-server/5.5
Diff against target: 249 lines (+237/-0)
2 files modified
patches/bug54330.patch (+236/-0)
patches/series (+1/-0)
To merge this branch: bzr merge lp:~laurynas-biveinis/percona-server/bug54330
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+94510@code.launchpad.net

Description of the change

Fix bug 939485 (MySQL bugs 64432, 54330): fast index creation is
broken - the index contains only part of data.

This has been fixed upstream in 5.1 for bug 54330. The fix is
straightforwardly backported from there, revisions 3351.14.149 and
3351.54.1, but adds a testcase.

To post a comment you must log in.
Revision history for this message
Laurynas Biveinis (laurynas-biveinis) wrote :
Revision history for this message
Alexey Kopytov (akopytov) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'patches/bug54330.patch'
--- patches/bug54330.patch 1970-01-01 00:00:00 +0000
+++ patches/bug54330.patch 2012-02-24 09:44:20 +0000
@@ -0,0 +1,236 @@
1--- a/storage/innobase/row/row0merge.c
2+++ b/storage/innobase/row/row0merge.c
3@@ -1607,22 +1607,28 @@
4 const dict_index_t* index, /*!< in: index being created */
5 merge_file_t* file, /*!< in/out: file containing
6 index entries */
7- ulint* half, /*!< in/out: half the file */
8 row_merge_block_t* block, /*!< in/out: 3 buffers */
9 int* tmpfd, /*!< in/out: temporary file handle */
10- struct TABLE* table) /*!< in/out: MySQL table, for
11+ struct TABLE* table, /*!< in/out: MySQL table, for
12 reporting erroneous key value
13 if applicable */
14+ ulint* num_run,/*!< in/out: Number of runs remain
15+ to be merged */
16+ ulint* run_offset) /*!< in/out: Array contains the
17+ first offset number for each merge
18+ run */
19 {
20 ulint foffs0; /*!< first input offset */
21 ulint foffs1; /*!< second input offset */
22 ulint error; /*!< error code */
23 merge_file_t of; /*!< output file */
24- const ulint ihalf = *half;
25+ const ulint ihalf = run_offset[*num_run / 2];
26 /*!< half the input file */
27- ulint ohalf; /*!< half the output file */
28+ ulint n_run = 0;
29+ /*!< num of runs generated from this merge */
30
31 UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
32+
33 ut_ad(ihalf < file->offset);
34
35 of.fd = *tmpfd;
36@@ -1638,17 +1644,20 @@
37 #endif /* POSIX_FADV_SEQUENTIAL */
38
39 /* Merge blocks to the output file. */
40- ohalf = 0;
41 foffs0 = 0;
42 foffs1 = ihalf;
43
44+ UNIV_MEM_INVALID(run_offset, *num_run * sizeof *run_offset);
45+
46 for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) {
47- ulint ahalf; /*!< arithmetic half the input file */
48
49 if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
50 return(DB_INTERRUPTED);
51 }
52
53+ /* Remember the offset number for this run */
54+ run_offset[n_run++] = of.offset;
55+
56 error = row_merge_blocks(index, file, block,
57 &foffs0, &foffs1, &of, table);
58
59@@ -1656,21 +1665,6 @@
60 return(error);
61 }
62
63- /* Record the offset of the output file when
64- approximately half the output has been generated. In
65- this way, the next invocation of row_merge() will
66- spend most of the time in this loop. The initial
67- estimate is ohalf==0. */
68- ahalf = file->offset / 2;
69- ut_ad(ohalf <= of.offset);
70-
71- /* Improve the estimate until reaching half the input
72- file size, or we can not get any closer to it. All
73- comparands should be non-negative when !(ohalf < ahalf)
74- because ohalf <= of.offset. */
75- if (ohalf < ahalf || of.offset - ahalf < ohalf - ahalf) {
76- ohalf = of.offset;
77- }
78 }
79
80 /* Copy the last blocks, if there are any. */
81@@ -1680,6 +1674,9 @@
82 return(DB_INTERRUPTED);
83 }
84
85+ /* Remember the offset number for this run */
86+ run_offset[n_run++] = of.offset;
87+
88 if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) {
89 return(DB_CORRUPTION);
90 }
91@@ -1692,6 +1689,9 @@
92 return(DB_INTERRUPTED);
93 }
94
95+ /* Remember the offset number for this run */
96+ run_offset[n_run++] = of.offset;
97+
98 if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) {
99 return(DB_CORRUPTION);
100 }
101@@ -1703,10 +1703,23 @@
102 return(DB_CORRUPTION);
103 }
104
105+ ut_ad(n_run <= *num_run);
106+
107+ *num_run = n_run;
108+
109+ /* Each run can contain one or more offsets. As merge goes on,
110+ the number of runs (to merge) will reduce until we have one
111+ single run. So the number of runs will always be smaller than
112+ the number of offsets in file */
113+ ut_ad((*num_run) <= file->offset);
114+
115+ /* The number of offsets in output file is always equal or
116+ smaller than input file */
117+ ut_ad(of.offset <= file->offset);
118+
119 /* Swap file descriptors for the next pass. */
120 *tmpfd = file->fd;
121 *file = of;
122- *half = ohalf;
123
124 UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]);
125
126@@ -1731,27 +1744,44 @@
127 if applicable */
128 {
129 ulint half = file->offset / 2;
130+ ulint num_runs;
131+ ulint* run_offset;
132+ ulint error = DB_SUCCESS;
133+
134+ /* Record the number of merge runs we need to perform */
135+ num_runs = file->offset;
136+
137+ /* If num_runs are less than 1, nothing to merge */
138+ if (num_runs <= 1) {
139+ return(error);
140+ }
141+
142+ /* "run_offset" records each run's first offset number */
143+ run_offset = (ulint*) mem_alloc(file->offset * sizeof(ulint));
144+
145+ /* This tells row_merge() where to start for the first round
146+ of merge. */
147+ run_offset[half] = half;
148
149 /* The file should always contain at least one byte (the end
150 of file marker). Thus, it must be at least one block. */
151 ut_ad(file->offset > 0);
152
153+ /* Merge the runs until we have one big run */
154 do {
155- ulint error;
156+ error = row_merge(trx, index, file, block, tmpfd,
157+ table, &num_runs, run_offset);
158
159- error = row_merge(trx, index, file, &half,
160- block, tmpfd, table);
161+ UNIV_MEM_ASSERT_RW(run_offset, num_runs * sizeof *run_offset);
162
163 if (error != DB_SUCCESS) {
164- return(error);
165+ break;
166 }
167+ } while (num_runs > 1);
168
169- /* half > 0 should hold except when the file consists
170- of one block. No need to merge further then. */
171- ut_ad(half > 0 || file->offset == 1);
172- } while (half < file->offset && half > 0);
173+ mem_free(run_offset);
174
175- return(DB_SUCCESS);
176+ return(error);
177 }
178
179 /*************************************************************//**
180--- /dev/null
181+++ b/mysql-test/suite/innodb/r/bug54330.result
182@@ -0,0 +1,13 @@
183+DROP TABLE IF EXISTS t1;
184+CREATE TABLE t1 (
185+id BIGINT(20) AUTO_INCREMENT PRIMARY KEY,
186+bar BIGINT(20)
187+) ENGINE=InnoDB;
188+SELECT COUNT(*) FROM t1;
189+COUNT(*)
190+517672
191+ALTER TABLE t1 ADD INDEX baz (bar);
192+SELECT COUNT(*) FROM t1 FORCE INDEX (baz);
193+COUNT(*)
194+517672
195+DROP TABLE t1;
196--- /dev/null
197+++ b/mysql-test/suite/innodb/t/bug54330.test
198@@ -0,0 +1,38 @@
199+# Testcase for MySQL bug #54330 - broken fast index creation
200+
201+--disable_warnings
202+DROP TABLE IF EXISTS t1;
203+--enable_warnings
204+
205+CREATE TABLE t1 (
206+ id BIGINT(20) AUTO_INCREMENT PRIMARY KEY,
207+ bar BIGINT(20)
208+) ENGINE=InnoDB;
209+
210+--disable_query_log
211+SET @old_autocommit=@@AUTOCOMMIT;
212+SET AUTOCOMMIT=0;
213+let $1= 515641;
214+while ($1)
215+{
216+ eval INSERT INTO t1 (bar) VALUES (NULL);
217+ dec $1;
218+}
219+let $1= 2031;
220+while ($1)
221+{
222+ eval INSERT INTO t1 (bar) VALUES ($1);
223+ dec $1;
224+}
225+COMMIT;
226+SET AUTOCOMMIT=@old_autocommit;
227+--enable_query_log
228+
229+SELECT COUNT(*) FROM t1;
230+
231+ALTER TABLE t1 ADD INDEX baz (bar);
232+
233+# With the bug present this will differ from the SELECT above!
234+SELECT COUNT(*) FROM t1 FORCE INDEX (baz);
235+
236+DROP TABLE t1;
0237
=== modified file 'patches/series'
--- patches/series 2012-01-19 08:42:23 +0000
+++ patches/series 2012-02-24 09:44:20 +0000
@@ -63,3 +63,4 @@
63group_commit.patch63group_commit.patch
64warning_fixes.patch64warning_fixes.patch
65bug917246.patch65bug917246.patch
66bug54330.patch

Subscribers

People subscribed via source and target branches