]>
Commit | Line | Data |
---|---|---|
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; |