]> git.pld-linux.org Git - packages/mysql.git/blob - bug54330.patch
- up to 5.5.28
[packages/mysql.git] / bug54330.patch
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.117476 seconds and 3 git commands to generate.