]> git.pld-linux.org Git - packages/mysql.git/blame - bug54330.patch
- rel 2; up to percona rel 30.0
[packages/mysql.git] / bug54330.patch
CommitLineData
543222d2
AM
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;
This page took 0.127879 seconds and 4 git commands to generate.