Merge lp:~stewart/drizzle/7.1-innodb-from-mysql-5.5.10 into lp:drizzle/7.1

Proposed by Stewart Smith
Status: Merged
Merged at revision: 2550
Proposed branch: lp:~stewart/drizzle/7.1-innodb-from-mysql-5.5.10
Merge into: lp:drizzle/7.1
Prerequisite: lp:~stewart/drizzle/7.1-innodb-1.1.5
Diff against target: 2942 lines (+915/-561)
40 files modified
plugin/innobase/btr/btr0btr.cc (+1/-1)
plugin/innobase/btr/btr0cur.cc (+239/-84)
plugin/innobase/btr/btr0sea.cc (+1/-1)
plugin/innobase/buf/buf0buddy.cc (+1/-1)
plugin/innobase/buf/buf0buf.cc (+26/-26)
plugin/innobase/buf/buf0lru.cc (+7/-39)
plugin/innobase/dict/dict0dict.cc (+10/-0)
plugin/innobase/dict/dict0load.cc (+1/-1)
plugin/innobase/fsp/fsp0fsp.cc (+4/-4)
plugin/innobase/handler/ha_innodb.cc (+110/-7)
plugin/innobase/ibuf/ibuf0ibuf.cc (+5/-22)
plugin/innobase/include/btr0cur.h (+41/-6)
plugin/innobase/include/buf0buf.h (+7/-7)
plugin/innobase/include/buf0lru.h (+4/-8)
plugin/innobase/include/dict0mem.h (+6/-0)
plugin/innobase/include/dict0types.h (+0/-5)
plugin/innobase/include/rem0cmp.h (+4/-0)
plugin/innobase/include/rem0cmp.ic (+1/-1)
plugin/innobase/include/row0upd.h (+18/-8)
plugin/innobase/include/srv0srv.h (+18/-0)
plugin/innobase/include/sync0rw.h (+2/-1)
plugin/innobase/include/trx0rseg.h (+1/-3)
plugin/innobase/include/trx0trx.h (+2/-2)
plugin/innobase/include/univ.i (+4/-3)
plugin/innobase/mem/mem0mem.cc (+1/-1)
plugin/innobase/page/page0zip.cc (+1/-1)
plugin/innobase/rem/rem0cmp.cc (+11/-3)
plugin/innobase/row/row0ins.cc (+1/-1)
plugin/innobase/row/row0merge.cc (+47/-23)
plugin/innobase/row/row0purge.cc (+31/-47)
plugin/innobase/row/row0umod.cc (+17/-30)
plugin/innobase/row/row0upd.cc (+31/-16)
plugin/innobase/row/row0vers.cc (+7/-3)
plugin/innobase/srv/srv0srv.cc (+6/-1)
plugin/innobase/srv/srv0start.cc (+8/-5)
plugin/innobase/sync/sync0arr.cc (+2/-2)
plugin/innobase/sync/sync0rw.cc (+10/-9)
plugin/innobase/sync/sync0sync.cc (+216/-173)
plugin/innobase/trx/trx0roll.cc (+2/-2)
plugin/innobase/trx/trx0trx.cc (+11/-14)
To merge this branch: bzr merge lp:~stewart/drizzle/7.1-innodb-from-mysql-5.5.10
Reviewer Review Type Date Requested Status
Drizzle Trunk Pending
Review via email: mp+106811@code.launchpad.net

Description of the change

To post a comment you must log in.
Revision history for this message
Henrik Ingo (hingo) wrote :

Why 5.5.10? It's like a year old. Why not latest and greatest? 5.5.24?

2552. By Stewart Smith

fix compiler warning on some compilers:
plugin/innobase/srv/srv0srv.cc: In function 'ulint srv_thread_has_reserved_slot(srv_thread_type)':
plugin/innobase/srv/srv0srv.cc:1075: error: comparison between signed and unsigned integer expressions [-Wsign-compare]

Revision history for this message
Stewart Smith (stewart) wrote :

On Tue, 22 May 2012 19:56:26 -0000, Henrik Ingo <email address hidden> wrote:
> Why 5.5.10? It's like a year old. Why not latest and greatest? 5.5.24?

It's coming in stages. There's a suitably large jump where it's better
to do incremental improvements rather than jump all the way in one go.

--
Stewart Smith

Revision history for this message
Brian Aker (brianaker) wrote :

https://jenkins.drizzle.org/view/Build/job/drizzle-build-ubuntu-debug/1834/console

Failure is happening when running with the server compiled as debug.

From master.err:

CURRENT_TEST: query_log.check_query_log_attribute
Can't open shared library '/home/jenkins/workspace/drizzle-build-ubuntu-debug/plugin/.libs/libquery_log_plugin.so' (errno: 0 /home/jenkins/workspace/drizzle-build-ubuntu-debug/plugin/.libs/libquery_log_plugin.so: undefined symbol: _ZNK5boost9gregorian10greg_month14as_long_stringEv)
Couldn't load plugin library named 'query_log'.

Aborting:"Failed to initialize plugins". Abort was called from drizzled/drizzled.cc:1409 in init_variables_after_daemonizing()
Note: Forcing kill of process 16390

Revision history for this message
Stewart Smith (stewart) wrote :

On Thu, 24 May 2012 22:58:18 -0000, Brian Aker <email address hidden> wrote:
> Failure is happening when running with the server compiled as debug.
>
> >From master.err:
>
>
> CURRENT_TEST: query_log.check_query_log_attribute
> Can't open shared library '/home/jenkins/workspace/drizzle-build-ubuntu-debug/plugin/.libs/libquery_log_plugin.so' (errno: 0 /home/jenkins/workspace/drizzle-build-ubuntu-debug/plugin/.libs/libquery_log_plugin.so: undefined symbol: _ZNK5boost9gregorian10greg_month14as_long_stringEv)
> Couldn't load plugin library named 'query_log'.
>
> Aborting:"Failed to initialize plugins". Abort was called from drizzled/drizzled.cc:1409 in init_variables_after_daemonizing()
> Note: Forcing kill of process 16390

huh... I have nothing to do with boost in my patch.... perhaps this is
with linking of the query_log plugin itself? My guess is that there's a
library missing.

--
Stewart Smith

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugin/innobase/btr/btr0btr.cc'
2--- plugin/innobase/btr/btr0btr.cc 2012-05-23 00:15:24 +0000
3+++ plugin/innobase/btr/btr0btr.cc 2012-05-23 00:15:24 +0000
4@@ -980,7 +980,7 @@
5 log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
6
7 #ifndef UNIV_HOTBACKUP
8- temp_block = buf_block_alloc(buf_pool, 0);
9+ temp_block = buf_block_alloc(buf_pool);
10 #else /* !UNIV_HOTBACKUP */
11 ut_ad(block == back_block1);
12 temp_block = back_block2;
13
14=== modified file 'plugin/innobase/btr/btr0cur.cc'
15--- plugin/innobase/btr/btr0cur.cc 2012-05-23 00:15:24 +0000
16+++ plugin/innobase/btr/btr0cur.cc 2012-05-23 00:15:24 +0000
17@@ -111,6 +111,18 @@
18 /*--------------------------------------*/
19 #define BTR_BLOB_HDR_SIZE 8 /*!< Size of a BLOB
20 part header, in bytes */
21+
22+/** Estimated table level stats from sampled value.
23+@param value sampled stats
24+@param index index being sampled
25+@param sample number of sampled rows
26+@param ext_size external stored data size
27+@param not_empty table not empty
28+@return estimated table wide stats from sampled value */
29+#define BTR_TABLE_STATS_FROM_SAMPLE(value, index, sample, ext_size, not_empty)\
30+ (((value) * (ib_int64_t) index->stat_n_leaf_pages \
31+ + (sample) - 1 + (ext_size) + (not_empty)) / ((sample) + (ext_size)))
32+
33 /* @} */
34 #endif /* !UNIV_HOTBACKUP */
35
36@@ -185,7 +197,7 @@
37 ulint
38 btr_rec_get_externally_stored_len(
39 /*==============================*/
40- rec_t* rec, /*!< in: record */
41+ const rec_t* rec, /*!< in: record */
42 const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
43 #endif /* !UNIV_HOTBACKUP */
44
45@@ -1874,8 +1886,8 @@
46 NOT call it if index is secondary */
47
48 if (!dict_index_is_clust(index)
49- || row_upd_changes_ord_field_binary(NULL, NULL,
50- index, update)) {
51+ || row_upd_changes_ord_field_binary(index, update, thr,
52+ NULL, NULL)) {
53
54 /* Remove possible hash index pointer to this record */
55 btr_search_update_hash_on_delete(cursor);
56@@ -3479,9 +3491,53 @@
57 }
58
59 /*******************************************************************//**
60+Record the number of non_null key values in a given index for
61+each n-column prefix of the index where n < dict_index_get_n_unique(index).
62+The estimates are eventually stored in the array:
63+index->stat_n_non_null_key_vals. */
64+static
65+void
66+btr_record_not_null_field_in_rec(
67+/*=============================*/
68+ rec_t* rec, /*!< in: physical record */
69+ ulint n_unique, /*!< in: dict_index_get_n_unique(index),
70+ number of columns uniquely determine
71+ an index entry */
72+ const ulint* offsets, /*!< in: rec_get_offsets(rec, index),
73+ its size could be for all fields or
74+ that of "n_unique" */
75+ ib_int64_t* n_not_null) /*!< in/out: array to record number of
76+ not null rows for n-column prefix */
77+{
78+ ulint i;
79+
80+ ut_ad(rec_offs_n_fields(offsets) >= n_unique);
81+
82+ if (n_not_null == NULL) {
83+ return;
84+ }
85+
86+ for (i = 0; i < n_unique; i++) {
87+ ulint rec_len;
88+
89+ rec_get_nth_field(rec, offsets, i, &rec_len);
90+
91+ if (rec_len != UNIV_SQL_NULL) {
92+ n_not_null[i]++;
93+ } else {
94+ /* Break if we hit the first NULL value */
95+ break;
96+ }
97+ }
98+}
99+
100+/*******************************************************************//**
101 Estimates the number of different key values in a given index, for
102 each n-column prefix of the index where n <= dict_index_get_n_unique(index).
103-The estimates are stored in the array index->stat_n_diff_key_vals. */
104+The estimates are stored in the array index->stat_n_diff_key_vals.
105+If innodb_stats_method is "nulls_ignored", we also record the number of
106+non-null values for each prefix and store the estimates in
107+array index->stat_n_non_null_key_vals. */
108 UNIV_INTERN
109 void
110 btr_estimate_number_of_different_key_vals(
111@@ -3495,6 +3551,8 @@
112 ulint matched_fields;
113 ulint matched_bytes;
114 ib_int64_t* n_diff;
115+ ib_int64_t* n_not_null;
116+ ibool stats_null_not_equal;
117 ullint n_sample_pages; /* number of pages to sample */
118 ulint not_empty_flag = 0;
119 ulint total_external_size = 0;
120@@ -3503,16 +3561,43 @@
121 ullint add_on;
122 mtr_t mtr;
123 mem_heap_t* heap = NULL;
124- ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
125- ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
126- ulint* offsets_rec = offsets_rec_;
127- ulint* offsets_next_rec= offsets_next_rec_;
128- rec_offs_init(offsets_rec_);
129- rec_offs_init(offsets_next_rec_);
130+ ulint* offsets_rec = NULL;
131+ ulint* offsets_next_rec = NULL;
132
133 n_cols = dict_index_get_n_unique(index);
134
135- n_diff = (ib_int64_t *)mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
136+ heap = mem_heap_create((sizeof *n_diff + sizeof *n_not_null)
137+ * (n_cols + 1)
138+ + dict_index_get_n_fields(index)
139+ * (sizeof *offsets_rec
140+ + sizeof *offsets_next_rec));
141+
142+ n_diff = static_cast<ib_int64_t *>(mem_heap_zalloc(heap, (n_cols + 1) * sizeof(ib_int64_t)));
143+
144+ n_not_null = NULL;
145+
146+ /* Check srv_innodb_stats_method setting, and decide whether we
147+ need to record non-null value and also decide if NULL is
148+ considered equal (by setting stats_null_not_equal value) */
149+ switch (srv_innodb_stats_method) {
150+ case SRV_STATS_NULLS_IGNORED:
151+ n_not_null = static_cast<ib_int64_t *>(mem_heap_zalloc(heap, (n_cols + 1)
152+ * sizeof *n_not_null));
153+ /* fall through */
154+
155+ case SRV_STATS_NULLS_UNEQUAL:
156+ /* for both SRV_STATS_NULLS_IGNORED and SRV_STATS_NULLS_UNEQUAL
157+ case, we will treat NULLs as unequal value */
158+ stats_null_not_equal = TRUE;
159+ break;
160+
161+ case SRV_STATS_NULLS_EQUAL:
162+ stats_null_not_equal = FALSE;
163+ break;
164+
165+ default:
166+ ut_error;
167+ }
168
169 /* It makes no sense to test more pages than are contained
170 in the index, thus we lower the number if it is too high */
171@@ -3529,7 +3614,6 @@
172 /* We sample some pages in the index to get an estimate */
173
174 for (i = 0; i < n_sample_pages; i++) {
175- rec_t* supremum;
176 mtr_start(&mtr);
177
178 btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
179@@ -3542,18 +3626,25 @@
180
181 page = btr_cur_get_page(&cursor);
182
183- supremum = page_get_supremum_rec(page);
184 rec = page_rec_get_next(page_get_infimum_rec(page));
185
186- if (rec != supremum) {
187+ if (!page_rec_is_supremum(rec)) {
188 not_empty_flag = 1;
189 offsets_rec = rec_get_offsets(rec, index, offsets_rec,
190 ULINT_UNDEFINED, &heap);
191+
192+ if (n_not_null) {
193+ btr_record_not_null_field_in_rec(
194+ rec, n_cols, offsets_rec, n_not_null);
195+ }
196 }
197
198- while (rec != supremum) {
199+ while (!page_rec_is_supremum(rec)) {
200 rec_t* next_rec = page_rec_get_next(rec);
201- if (next_rec == supremum) {
202+ if (page_rec_is_supremum(next_rec)) {
203+ total_external_size +=
204+ btr_rec_get_externally_stored_len(
205+ rec, offsets_rec);
206 break;
207 }
208
209@@ -3561,11 +3652,13 @@
210 matched_bytes = 0;
211 offsets_next_rec = rec_get_offsets(next_rec, index,
212 offsets_next_rec,
213- n_cols, &heap);
214+ ULINT_UNDEFINED,
215+ &heap);
216
217 cmp_rec_rec_with_match(rec, next_rec,
218 offsets_rec, offsets_next_rec,
219- index, &matched_fields,
220+ index, stats_null_not_equal,
221+ &matched_fields,
222 &matched_bytes);
223
224 for (j = matched_fields + 1; j <= n_cols; j++) {
225@@ -3575,6 +3668,12 @@
226 n_diff[j]++;
227 }
228
229+ if (n_not_null) {
230+ btr_record_not_null_field_in_rec(
231+ next_rec, n_cols, offsets_next_rec,
232+ n_not_null);
233+ }
234+
235 total_external_size
236 += btr_rec_get_externally_stored_len(
237 rec, offsets_rec);
238@@ -3609,10 +3708,6 @@
239 }
240 }
241
242- offsets_rec = rec_get_offsets(rec, index, offsets_rec,
243- ULINT_UNDEFINED, &heap);
244- total_external_size += btr_rec_get_externally_stored_len(
245- rec, offsets_rec);
246 mtr_commit(&mtr);
247 }
248
249@@ -3626,13 +3721,9 @@
250
251 for (j = 0; j <= n_cols; j++) {
252 index->stat_n_diff_key_vals[j]
253- = ((n_diff[j]
254- * (ib_int64_t)index->stat_n_leaf_pages
255- + n_sample_pages - 1
256- + total_external_size
257- + not_empty_flag)
258- / (n_sample_pages
259- + total_external_size));
260+ = BTR_TABLE_STATS_FROM_SAMPLE(
261+ n_diff[j], index, n_sample_pages,
262+ total_external_size, not_empty_flag);
263
264 /* If the tree is small, smaller than
265 10 * n_sample_pages + total_external_size, then
266@@ -3651,45 +3742,81 @@
267 }
268
269 index->stat_n_diff_key_vals[j] += add_on;
270- }
271-
272- mem_free(n_diff);
273- if (UNIV_LIKELY_NULL(heap)) {
274- mem_heap_free(heap);
275- }
276+
277+ /* Update the stat_n_non_null_key_vals[] with our
278+ sampled result. stat_n_non_null_key_vals[] is created
279+ and initialized to zero in dict_index_add_to_cache(),
280+ along with stat_n_diff_key_vals[] array */
281+ if (n_not_null != NULL && (j < n_cols)) {
282+ index->stat_n_non_null_key_vals[j] =
283+ BTR_TABLE_STATS_FROM_SAMPLE(
284+ n_not_null[j], index, n_sample_pages,
285+ total_external_size, not_empty_flag);
286+ }
287+ }
288+
289+ mem_heap_free(heap);
290 }
291
292 /*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
293
294 /***********************************************************//**
295+Gets the offset of the pointer to the externally stored part of a field.
296+@return offset of the pointer to the externally stored part */
297+static
298+ulint
299+btr_rec_get_field_ref_offs(
300+/*=======================*/
301+ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
302+ ulint n) /*!< in: index of the external field */
303+{
304+ ulint field_ref_offs;
305+ ulint local_len;
306+
307+ ut_a(rec_offs_nth_extern(offsets, n));
308+ field_ref_offs = rec_get_nth_field_offs(offsets, n, &local_len);
309+ ut_a(local_len != UNIV_SQL_NULL);
310+ ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
311+
312+ return(field_ref_offs + local_len - BTR_EXTERN_FIELD_REF_SIZE);
313+}
314+
315+/** Gets a pointer to the externally stored part of a field.
316+@param rec record
317+@param offsets rec_get_offsets(rec)
318+@param n index of the externally stored field
319+@return pointer to the externally stored part */
320+#define btr_rec_get_field_ref(rec, offsets, n) \
321+ ((rec) + btr_rec_get_field_ref_offs(offsets, n))
322+
323+/***********************************************************//**
324 Gets the externally stored size of a record, in units of a database page.
325 @return externally stored part, in units of a database page */
326 static
327 ulint
328 btr_rec_get_externally_stored_len(
329 /*==============================*/
330- rec_t* rec, /*!< in: record */
331+ const rec_t* rec, /*!< in: record */
332 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
333 {
334 ulint n_fields;
335- byte* data;
336- ulint local_len;
337- ulint extern_len;
338 ulint total_extern_len = 0;
339 ulint i;
340
341 ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
342+
343+ if (!rec_offs_any_extern(offsets)) {
344+ return(0);
345+ }
346+
347 n_fields = rec_offs_n_fields(offsets);
348
349 for (i = 0; i < n_fields; i++) {
350 if (rec_offs_nth_extern(offsets, i)) {
351
352- data = rec_get_nth_field(rec, offsets, i, &local_len);
353-
354- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
355-
356- extern_len = mach_read_from_4(data + local_len
357- + BTR_EXTERN_LEN + 4);
358+ ulint extern_len = mach_read_from_4(
359+ btr_rec_get_field_ref(rec, offsets, i)
360+ + BTR_EXTERN_LEN + 4);
361
362 total_extern_len += ut_calc_align(extern_len,
363 UNIV_PAGE_SIZE);
364@@ -3719,7 +3846,7 @@
365 ulint byte_val;
366
367 data = rec_get_nth_field(rec, offsets, i, &local_len);
368-
369+ ut_ad(rec_offs_nth_extern(offsets, i));
370 ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
371
372 local_len -= BTR_EXTERN_FIELD_REF_SIZE;
373@@ -3729,6 +3856,9 @@
374 if (val) {
375 byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG);
376 } else {
377+#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
378+ ut_a(!(byte_val & BTR_EXTERN_OWNER_FLAG));
379+#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
380 byte_val = byte_val | BTR_EXTERN_OWNER_FLAG;
381 }
382
383@@ -3946,13 +4076,12 @@
384 && buf_block_get_space(block) == space
385 && buf_block_get_page_no(block) == page_no) {
386
387- if (buf_LRU_free_block(&block->page, all, NULL)
388- != BUF_LRU_FREED
389+ if (buf_LRU_free_block(&block->page, all) != BUF_LRU_FREED
390 && all && block->page.zip.data) {
391 /* Attempt to deallocate the uncompressed page
392 if the whole block cannot be deallocted. */
393
394- buf_LRU_free_block(&block->page, FALSE, NULL);
395+ buf_LRU_free_block(&block->page, FALSE);
396 }
397 }
398
399@@ -3968,8 +4097,8 @@
400 @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
401 UNIV_INTERN
402 ulint
403-btr_store_big_rec_extern_fields(
404-/*============================*/
405+btr_store_big_rec_extern_fields_func(
406+/*=================================*/
407 dict_index_t* index, /*!< in: index of rec; the index tree
408 MUST be X-latched */
409 buf_block_t* rec_block, /*!< in/out: block containing rec */
410@@ -3978,11 +4107,16 @@
411 the "external storage" flags in offsets
412 will not correspond to rec when
413 this function returns */
414- big_rec_t* big_rec_vec, /*!< in: vector containing fields
415+#ifdef UNIV_DEBUG
416+ mtr_t* local_mtr, /*!< in: mtr containing the
417+ latch to rec and to the tree */
418+#endif /* UNIV_DEBUG */
419+#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
420+ ibool update_in_place,/*! in: TRUE if the record is updated
421+ in place (not delete+insert) */
422+#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
423+ const big_rec_t*big_rec_vec) /*!< in: vector containing fields
424 to be stored externally */
425- mtr_t* /*local_mtr __attribute__((unused))*/) /*!< in: mtr
426- containing the latch to rec and to the
427- tree */
428 {
429 ulint rec_page_no;
430 byte* field_ref;
431@@ -4000,6 +4134,7 @@
432 z_stream c_stream;
433
434 ut_ad(rec_offs_validate(rec, index, offsets));
435+ ut_ad(rec_offs_any_extern(offsets));
436 ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
437 MTR_MEMO_X_LOCK));
438 ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
439@@ -4031,21 +4166,37 @@
440 ut_a(err == Z_OK);
441 }
442
443+#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
444+ /* All pointers to externally stored columns in the record
445+ must either be zero or they must be pointers to inherited
446+ columns, owned by this record or an earlier record version. */
447+ for (i = 0; i < rec_offs_n_fields(offsets); i++) {
448+ if (!rec_offs_nth_extern(offsets, i)) {
449+ continue;
450+ }
451+ field_ref = btr_rec_get_field_ref(rec, offsets, i);
452+
453+ ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
454+ /* Either this must be an update in place,
455+ or the BLOB must be inherited, or the BLOB pointer
456+ must be zero (will be written in this function). */
457+ ut_a(update_in_place
458+ || (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
459+ || !memcmp(field_ref, field_ref_zero,
460+ BTR_EXTERN_FIELD_REF_SIZE));
461+ }
462+#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
463 /* We have to create a file segment to the tablespace
464 for each field and put the pointer to the field in rec */
465
466 for (i = 0; i < big_rec_vec->n_fields; i++) {
467- ut_ad(rec_offs_nth_extern(offsets,
468- big_rec_vec->fields[i].field_no));
469- {
470- ulint local_len;
471- field_ref = rec_get_nth_field(
472- rec, offsets, big_rec_vec->fields[i].field_no,
473- &local_len);
474- ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
475- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
476- field_ref += local_len;
477- }
478+ field_ref = btr_rec_get_field_ref(
479+ rec, offsets, big_rec_vec->fields[i].field_no);
480+#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
481+ /* A zero BLOB pointer should have been initially inserted. */
482+ ut_a(!memcmp(field_ref, field_ref_zero,
483+ BTR_EXTERN_FIELD_REF_SIZE));
484+#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
485 extern_len = big_rec_vec->fields[i].len;
486 UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data,
487 extern_len);
488@@ -4327,6 +4478,23 @@
489 mem_heap_free(heap);
490 }
491
492+#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
493+ /* All pointers to externally stored columns in the record
494+ must be valid. */
495+ for (i = 0; i < rec_offs_n_fields(offsets); i++) {
496+ if (!rec_offs_nth_extern(offsets, i)) {
497+ continue;
498+ }
499+
500+ field_ref = btr_rec_get_field_ref(rec, offsets, i);
501+
502+ /* The pointer must not be zero. */
503+ ut_a(0 != memcmp(field_ref, field_ref_zero,
504+ BTR_EXTERN_FIELD_REF_SIZE));
505+ /* The column must not be disowned by this record. */
506+ ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
507+ }
508+#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
509 return(DB_SUCCESS);
510 }
511
512@@ -4349,6 +4517,7 @@
513 if (UNIV_UNLIKELY(type != FIL_PAGE_TYPE_BLOB)) {
514 ulint flags = fil_space_get_flags(space_id);
515
516+#ifndef UNIV_DEBUG /* Improve debug test coverage */
517 if (UNIV_LIKELY
518 ((flags & DICT_TF_FORMAT_MASK) == DICT_TF_FORMAT_51)) {
519 /* Old versions of InnoDB did not initialize
520@@ -4357,6 +4526,7 @@
521 a BLOB page that is in Antelope format.*/
522 return;
523 }
524+#endif /* !UNIV_DEBUG */
525
526 ut_print_timestamp(stderr);
527 fprintf(stderr,
528@@ -4406,23 +4576,13 @@
529 ulint page_no;
530 ulint next_page_no;
531 mtr_t mtr;
532-#ifdef UNIV_DEBUG
533+
534 ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
535 MTR_MEMO_X_LOCK));
536 ut_ad(mtr_memo_contains_page(local_mtr, field_ref,
537 MTR_MEMO_PAGE_X_FIX));
538 ut_ad(!rec || rec_offs_validate(rec, index, offsets));
539-
540- if (rec) {
541- ulint local_len;
542- const byte* f = rec_get_nth_field(rec, offsets,
543- i, &local_len);
544- ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
545- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
546- f += local_len;
547- ut_ad(f == field_ref);
548- }
549-#endif /* UNIV_DEBUG */
550+ ut_ad(!rec || field_ref == btr_rec_get_field_ref(rec, offsets, i));
551
552 if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
553 BTR_EXTERN_FIELD_REF_SIZE))) {
554@@ -4587,13 +4747,8 @@
555
556 for (i = 0; i < n_fields; i++) {
557 if (rec_offs_nth_extern(offsets, i)) {
558- ulint len;
559- byte* data
560- = rec_get_nth_field(rec, offsets, i, &len);
561- ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
562-
563 btr_free_externally_stored_field(
564- index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
565+ index, btr_rec_get_field_ref(rec, offsets, i),
566 rec, offsets, page_zip, i, rb_ctx, mtr);
567 }
568 }
569
570=== modified file 'plugin/innobase/btr/btr0sea.cc'
571--- plugin/innobase/btr/btr0sea.cc 2010-12-27 18:39:11 +0000
572+++ plugin/innobase/btr/btr0sea.cc 2012-05-23 00:15:24 +0000
573@@ -146,7 +146,7 @@
574 be enough free space in the hash table. */
575
576 if (heap->free_block == NULL) {
577- buf_block_t* block = buf_block_alloc(NULL, 0);
578+ buf_block_t* block = buf_block_alloc(NULL);
579
580 rw_lock_x_lock(&btr_search_latch);
581
582
583=== modified file 'plugin/innobase/buf/buf0buddy.cc'
584--- plugin/innobase/buf/buf0buddy.cc 2010-12-24 00:04:05 +0000
585+++ plugin/innobase/buf/buf0buddy.cc 2012-05-23 00:15:24 +0000
586@@ -327,7 +327,7 @@
587
588 /* Try replacing an uncompressed page in the buffer pool. */
589 buf_pool_mutex_exit(buf_pool);
590- block = buf_LRU_get_free_block(buf_pool, 0);
591+ block = buf_LRU_get_free_block(buf_pool);
592 *lru = TRUE;
593 buf_pool_mutex_enter(buf_pool);
594
595
596=== modified file 'plugin/innobase/buf/buf0buf.cc'
597--- plugin/innobase/buf/buf0buf.cc 2012-05-23 00:15:24 +0000
598+++ plugin/innobase/buf/buf0buf.cc 2012-05-23 00:15:24 +0000
599@@ -419,9 +419,9 @@
600 buf_block_t*
601 buf_block_alloc(
602 /*============*/
603- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
604- ulint zip_size) /*!< in: compressed page size in bytes,
605- or 0 if uncompressed tablespace */
606+ buf_pool_t* buf_pool) /*!< in/out: buffer pool instance,
607+ or NULL for round-robin selection
608+ of the buffer pool */
609 {
610 buf_block_t* block;
611 ulint index;
612@@ -434,7 +434,7 @@
613 buf_pool = buf_pool_from_array(index);
614 }
615
616- block = buf_LRU_get_free_block(buf_pool, zip_size);
617+ block = buf_LRU_get_free_block(buf_pool);
618
619 buf_block_set_state(block, BUF_BLOCK_MEMORY);
620
621@@ -862,9 +862,9 @@
622
623 block->modify_clock = 0;
624
625-#ifdef UNIV_DEBUG_FILE_ACCESSES
626+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
627 block->page.file_page_was_freed = FALSE;
628-#endif /* UNIV_DEBUG_FILE_ACCESSES */
629+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
630
631 block->check_index_page_at_flush = FALSE;
632 block->index = NULL;
633@@ -1622,7 +1622,7 @@
634
635 buf_LRU_make_block_old(&block->page);
636 dirty++;
637- } else if (buf_LRU_free_block(&block->page, TRUE, NULL)
638+ } else if (buf_LRU_free_block(&block->page, TRUE)
639 != BUF_LRU_FREED) {
640 nonfree++;
641 }
642@@ -2228,7 +2228,7 @@
643 return(is_hashed);
644 }
645
646-#ifdef UNIV_DEBUG_FILE_ACCESSES
647+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
648 /********************************************************************//**
649 Sets file_page_was_freed TRUE if the page is found in the buffer pool.
650 This function should be called when we free a file page and want the
651@@ -2251,6 +2251,8 @@
652
653 if (bpage) {
654 ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
655+ /* bpage->file_page_was_freed can already hold
656+ when this code is invoked from dict_drop_index_tree() */
657 bpage->file_page_was_freed = TRUE;
658 }
659
660@@ -2288,7 +2290,7 @@
661
662 return(bpage);
663 }
664-#endif /* UNIV_DEBUG_FILE_ACCESSES */
665+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
666
667 /********************************************************************//**
668 Get read access to a compressed page (usually of type
669@@ -2365,8 +2367,7 @@
670 mutex_enter(block_mutex);
671
672 /* Discard the uncompressed page frame if possible. */
673- if (buf_LRU_free_block(bpage, FALSE, NULL)
674- == BUF_LRU_FREED) {
675+ if (buf_LRU_free_block(bpage, FALSE) == BUF_LRU_FREED) {
676
677 mutex_exit(block_mutex);
678 goto lookup;
679@@ -2390,7 +2391,7 @@
680
681 buf_page_set_accessed_make_young(bpage, access_time);
682
683-#ifdef UNIV_DEBUG_FILE_ACCESSES
684+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
685 ut_a(!bpage->file_page_was_freed);
686 #endif
687
688@@ -2882,7 +2883,7 @@
689 buf_pool_mutex_exit(buf_pool);
690 mutex_exit(&buf_pool->zip_mutex);
691
692- block = buf_LRU_get_free_block(buf_pool, 0);
693+ block = buf_LRU_get_free_block(buf_pool);
694 ut_a(block);
695
696 buf_pool_mutex_enter(buf_pool);
697@@ -3012,8 +3013,7 @@
698 /* Try to evict the block from the buffer pool, to use the
699 insert buffer (change buffer) as much as possible. */
700
701- if (buf_LRU_free_block(&block->page, TRUE, NULL)
702- == BUF_LRU_FREED) {
703+ if (buf_LRU_free_block(&block->page, TRUE) == BUF_LRU_FREED) {
704 mutex_exit(&block->mutex);
705 if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
706 /* Set the watch, as it would have
707@@ -3059,7 +3059,7 @@
708
709 buf_page_set_accessed_make_young(&block->page, access_time);
710
711-#ifdef UNIV_DEBUG_FILE_ACCESSES
712+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
713 ut_a(!block->page.file_page_was_freed);
714 #endif
715
716@@ -3218,7 +3218,7 @@
717 ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
718 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
719
720-#ifdef UNIV_DEBUG_FILE_ACCESSES
721+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
722 ut_a(block->page.file_page_was_freed == FALSE);
723 #endif
724 if (UNIV_UNLIKELY(!access_time)) {
725@@ -3330,7 +3330,7 @@
726 ut_a(block->page.buf_fix_count > 0);
727 ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
728 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
729-#ifdef UNIV_DEBUG_FILE_ACCESSES
730+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
731 ut_a(block->page.file_page_was_freed == FALSE);
732 #endif
733
734@@ -3416,9 +3416,9 @@
735 ut_a(block->page.buf_fix_count > 0);
736 ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
737 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
738-#ifdef UNIV_DEBUG_FILE_ACCESSES
739+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
740 ut_a(block->page.file_page_was_freed == FALSE);
741-#endif /* UNIV_DEBUG_FILE_ACCESSES */
742+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
743 buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
744
745 buf_pool->stat.n_page_gets++;
746@@ -3447,9 +3447,9 @@
747 bpage->newest_modification = 0;
748 bpage->oldest_modification = 0;
749 HASH_INVALIDATE(bpage, hash);
750-#ifdef UNIV_DEBUG_FILE_ACCESSES
751+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
752 bpage->file_page_was_freed = FALSE;
753-#endif /* UNIV_DEBUG_FILE_ACCESSES */
754+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
755 }
756
757 /********************************************************************//**
758@@ -3587,7 +3587,7 @@
759 && UNIV_LIKELY(!recv_recovery_is_on())) {
760 block = NULL;
761 } else {
762- block = buf_LRU_get_free_block(buf_pool, 0);
763+ block = buf_LRU_get_free_block(buf_pool);
764 ut_ad(block);
765 ut_ad(buf_pool_from_block(block) == buf_pool);
766 }
767@@ -3793,7 +3793,7 @@
768 ut_ad(mtr->state == MTR_ACTIVE);
769 ut_ad(space || !zip_size);
770
771- free_block = buf_LRU_get_free_block(buf_pool, 0);
772+ free_block = buf_LRU_get_free_block(buf_pool);
773
774 fold = buf_page_address_fold(space, offset);
775
776@@ -3808,9 +3808,9 @@
777 #ifdef UNIV_IBUF_COUNT_DEBUG
778 ut_a(ibuf_count_get(space, offset) == 0);
779 #endif
780-#ifdef UNIV_DEBUG_FILE_ACCESSES
781+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
782 block->page.file_page_was_freed = FALSE;
783-#endif /* UNIV_DEBUG_FILE_ACCESSES */
784+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
785
786 /* Page can be found in buf_pool */
787 buf_pool_mutex_exit(buf_pool);
788
789=== modified file 'plugin/innobase/buf/buf0lru.cc'
790--- plugin/innobase/buf/buf0lru.cc 2012-05-23 00:15:24 +0000
791+++ plugin/innobase/buf/buf0lru.cc 2012-05-23 00:15:24 +0000
792@@ -604,7 +604,7 @@
793 ut_ad(block->page.in_LRU_list);
794
795 mutex_enter(&block->mutex);
796- freed = buf_LRU_free_block(&block->page, FALSE, NULL);
797+ freed = buf_LRU_free_block(&block->page, FALSE);
798 mutex_exit(&block->mutex);
799
800 switch (freed) {
801@@ -667,7 +667,7 @@
802
803 mutex_enter(block_mutex);
804 accessed = buf_page_is_accessed(bpage);
805- freed = buf_LRU_free_block(bpage, TRUE, NULL);
806+ freed = buf_LRU_free_block(bpage, TRUE);
807 mutex_exit(block_mutex);
808
809 switch (freed) {
810@@ -859,9 +859,7 @@
811 buf_block_t*
812 buf_LRU_get_free_block(
813 /*===================*/
814- buf_pool_t* buf_pool, /*!< in: buffer pool instance */
815- ulint zip_size) /*!< in: compressed page size in bytes,
816- or 0 if uncompressed tablespace */
817+ buf_pool_t* buf_pool) /*!< in/out: buffer pool instance */
818 {
819 buf_block_t* block = NULL;
820 ibool freed;
821@@ -937,31 +935,11 @@
822
823 /* If there is a block in the free list, take it */
824 block = buf_LRU_get_free_only(buf_pool);
825+ buf_pool_mutex_exit(buf_pool);
826+
827 if (block) {
828-
829 ut_ad(buf_pool_from_block(block) == buf_pool);
830-
831-#ifdef UNIV_DEBUG
832- block->page.zip.m_start =
833-#endif /* UNIV_DEBUG */
834- block->page.zip.m_end =
835- block->page.zip.m_nonempty =
836- block->page.zip.n_blobs = 0;
837-
838- if (UNIV_UNLIKELY(zip_size)) {
839- ibool lru;
840- page_zip_set_size(&block->page.zip, zip_size);
841-
842- block->page.zip.data = static_cast<unsigned char *>(buf_buddy_alloc(
843- buf_pool, zip_size, &lru));
844-
845- UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
846- } else {
847- page_zip_set_size(&block->page.zip, 0);
848- block->page.zip.data = NULL;
849- }
850-
851- buf_pool_mutex_exit(buf_pool);
852+ memset(&block->page.zip, 0, sizeof block->page.zip);
853
854 if (started_monitor) {
855 srv_print_innodb_monitor = mon_value_was;
856@@ -973,8 +951,6 @@
857 /* If no block was in the free list, search from the end of the LRU
858 list and try to free a block there */
859
860- buf_pool_mutex_exit(buf_pool);
861-
862 freed = buf_LRU_search_and_free_block(buf_pool, n_iterations);
863
864 if (freed > 0) {
865@@ -1457,12 +1433,8 @@
866 buf_LRU_free_block(
867 /*===============*/
868 buf_page_t* bpage, /*!< in: block to be freed */
869- ibool zip, /*!< in: TRUE if should remove also the
870+ ibool zip) /*!< in: TRUE if should remove also the
871 compressed page of an uncompressed page */
872- ibool* buf_pool_mutex_released)
873- /*!< in: pointer to a variable that will
874- be assigned TRUE if buf_pool_mutex
875- was temporarily released, or NULL */
876 {
877 buf_page_t* b = NULL;
878 buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
879@@ -1639,10 +1611,6 @@
880 b->io_fix = BUF_IO_READ;
881 }
882
883- if (buf_pool_mutex_released) {
884- *buf_pool_mutex_released = TRUE;
885- }
886-
887 buf_pool_mutex_exit(buf_pool);
888 mutex_exit(block_mutex);
889
890
891=== modified file 'plugin/innobase/dict/dict0dict.cc'
892--- plugin/innobase/dict/dict0dict.cc 2012-05-23 00:15:24 +0000
893+++ plugin/innobase/dict/dict0dict.cc 2012-05-23 00:15:24 +0000
894@@ -1691,6 +1691,12 @@
895 new_index->heap,
896 (1 + dict_index_get_n_unique(new_index))
897 * sizeof(ib_int64_t)));
898+
899+ new_index->stat_n_non_null_key_vals = static_cast<ib_int64_t *>(mem_heap_zalloc(
900+ new_index->heap,
901+ (1 + dict_index_get_n_unique(new_index))
902+ * sizeof(*new_index->stat_n_non_null_key_vals)));
903+
904 /* Give some sensible values to stat_n_... in case we do
905 not calculate statistics quickly enough */
906
907@@ -4323,6 +4329,10 @@
908 for (i = dict_index_get_n_unique(index); i; ) {
909 index->stat_n_diff_key_vals[i--] = 1;
910 }
911+
912+ memset(index->stat_n_non_null_key_vals, 0,
913+ (1 + dict_index_get_n_unique(index))
914+ * sizeof(*index->stat_n_non_null_key_vals));
915 }
916
917 index = dict_table_get_next_index(index);
918
919=== modified file 'plugin/innobase/dict/dict0load.cc'
920--- plugin/innobase/dict/dict0load.cc 2012-05-23 00:15:24 +0000
921+++ plugin/innobase/dict/dict0load.cc 2012-05-23 00:15:24 +0000
922@@ -1630,7 +1630,7 @@
923 "InnoDB: in InnoDB data dictionary"
924 " has unknown type %lx.\n",
925 (ulong) flags);
926- return(NULL);
927+ return("incorrect flags in SYS_TABLES");
928 }
929 } else {
930 flags = 0;
931
932=== modified file 'plugin/innobase/fsp/fsp0fsp.cc'
933--- plugin/innobase/fsp/fsp0fsp.cc 2012-05-23 00:15:24 +0000
934+++ plugin/innobase/fsp/fsp0fsp.cc 2012-05-23 00:15:24 +0000
935@@ -3424,9 +3424,9 @@
936
937 fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
938
939-#ifdef UNIV_DEBUG_FILE_ACCESSES
940+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
941 buf_page_set_file_page_was_freed(space, page);
942-#endif
943+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
944 }
945
946 /**********************************************************************//**
947@@ -3492,13 +3492,13 @@
948
949 fsp_free_extent(space, zip_size, page, mtr);
950
951-#ifdef UNIV_DEBUG_FILE_ACCESSES
952+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
953 for (i = 0; i < FSP_EXTENT_SIZE; i++) {
954
955 buf_page_set_file_page_was_freed(space,
956 first_page_in_extent + i);
957 }
958-#endif
959+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
960 }
961
962 /**********************************************************************//**
963
964=== modified file 'plugin/innobase/handler/ha_innodb.cc'
965--- plugin/innobase/handler/ha_innodb.cc 2012-05-23 00:15:24 +0000
966+++ plugin/innobase/handler/ha_innodb.cc 2012-05-23 00:15:24 +0000
967@@ -292,6 +292,18 @@
968
969 static char* internal_innobase_data_file_path = NULL;
970
971+/** Possible values for system variable "innodb_stats_method". The values
972+are defined the same as its corresponding MyISAM system variable
973+"myisam_stats_method"(see "myisam_stats_method_names"), for better usability */
974+static const char* innodb_stats_method_names[] = {
975+ "nulls_equal",
976+ "nulls_unequal",
977+ "nulls_ignored",
978+ NULL
979+};
980+
981+static string innodb_stats_method;
982+
983 /* The following counter is used to convey information to InnoDB
984 about server activity: in selects it is not sensible to call
985 srv_active_wake_master_thread after each fetch or search, we only do
986@@ -2014,6 +2026,36 @@
987 return(1);
988 }
989
990+static
991+int
992+innodb_stats_method_validate(
993+/*=============================*/
994+ Session* , /*!< in: thread handle */
995+ set_var *var)
996+{
997+ const char *stats_method_input = var->value->str_value.ptr();
998+
999+ if (stats_method_input == NULL)
1000+ return 1;
1001+
1002+ ulint use;
1003+
1004+ for (use = 0;
1005+ use < UT_ARR_SIZE(innodb_stats_method_names);
1006+ ++use) {
1007+ if (!innobase_strcasecmp(stats_method_input,
1008+ innodb_stats_method_names[use]))
1009+ {
1010+ srv_innodb_stats_method= use;
1011+ innodb_stats_method= innodb_stats_method_names[use];
1012+ return 0;
1013+ }
1014+ }
1015+
1016+ return 1;
1017+}
1018+
1019+
1020 /*************************************************************//**
1021 Check if it is a valid value of innodb_change_buffering. This function is
1022 registered as a callback with MySQL.
1023@@ -2577,6 +2619,9 @@
1024 context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("max_purge_lag", innodb_max_purge_lag));
1025 context.registerVariable(new sys_var_constrained_value_readonly<uint64_t>("stats_sample_pages", innodb_stats_sample_pages));
1026 context.registerVariable(new sys_var_bool_ptr("adaptive_hash_index", &btr_search_enabled, innodb_adaptive_hash_index_update));
1027+ context.registerVariable(new sys_var_std_string("stats_method",
1028+ innodb_stats_method,
1029+ innodb_stats_method_validate));
1030
1031 context.registerVariable(new sys_var_constrained_value<uint32_t>("commit_concurrency",
1032 innobase_commit_concurrency,
1033@@ -7247,6 +7292,65 @@
1034
1035 return(0);
1036 }
1037+
1038+/*********************************************************************//**
1039+Calculate Record Per Key value. Need to exclude the NULL value if
1040+innodb_stats_method is set to "nulls_ignored"
1041+@return estimated record per key value */
1042+static
1043+ha_rows
1044+innodb_rec_per_key(
1045+/*===============*/
1046+ dict_index_t* index, /*!< in: dict_index_t structure */
1047+ ulint i, /*!< in: the column we are
1048+ calculating rec per key */
1049+ ha_rows records) /*!< in: estimated total records */
1050+{
1051+ ha_rows rec_per_key;
1052+
1053+ ut_ad(i < dict_index_get_n_unique(index));
1054+
1055+ /* Note the stat_n_diff_key_vals[] stores the diff value with
1056+ n-prefix indexing, so it is always stat_n_diff_key_vals[i + 1] */
1057+ if (index->stat_n_diff_key_vals[i + 1] == 0) {
1058+
1059+ rec_per_key = records;
1060+ } else if (srv_innodb_stats_method == SRV_STATS_NULLS_IGNORED) {
1061+ ib_int64_t num_null;
1062+
1063+ /* Number of rows with NULL value in this
1064+ field */
1065+ num_null = records - index->stat_n_non_null_key_vals[i];
1066+
1067+ /* In theory, index->stat_n_non_null_key_vals[i]
1068+ should always be less than the number of records.
1069+ Since this is statistics value, the value could
1070+ have slight discrepancy. But we will make sure
1071+ the number of null values is not a negative number. */
1072+ num_null = (num_null < 0) ? 0 : num_null;
1073+
1074+ /* If the number of NULL values is the same as or
1075+ large than that of the distinct values, we could
1076+ consider that the table consists mostly of NULL value.
1077+ Set rec_per_key to 1. */
1078+ if (index->stat_n_diff_key_vals[i + 1] <= num_null) {
1079+ rec_per_key = 1;
1080+ } else {
1081+ /* Need to exclude rows with NULL values from
1082+ rec_per_key calculation */
1083+ rec_per_key = (ha_rows)(
1084+ (records - num_null)
1085+ / (index->stat_n_diff_key_vals[i + 1]
1086+ - num_null));
1087+ }
1088+ } else {
1089+ rec_per_key = (ha_rows)
1090+ (records / index->stat_n_diff_key_vals[i + 1]);
1091+ }
1092+
1093+ return(rec_per_key);
1094+}
1095+
1096 /*********************************************************************//**
1097 Returns statistics information of the table to the MySQL interpreter,
1098 in various fields of the handle object. */
1099@@ -7468,13 +7572,7 @@
1100 break;
1101 }
1102
1103- if (index->stat_n_diff_key_vals[j + 1] == 0) {
1104-
1105- rec_per_key = stats.records;
1106- } else {
1107- rec_per_key = (ha_rows)(stats.records /
1108- index->stat_n_diff_key_vals[j + 1]);
1109- }
1110+ rec_per_key = innodb_rec_per_key(index, j, stats.records);
1111
1112 /* Since MySQL seems to favor table scans
1113 too much over index searches, we pretend
1114@@ -9467,6 +9565,11 @@
1115 _("ove blocks to the 'new' end of the buffer pool if the first access"
1116 " was at least this many milliseconds ago."
1117 " The timeout is disabled if 0 (the default)."));
1118+ context("stats-method",
1119+ po::value<string>(&innodb_stats_method),
1120+ "Specifies how InnoDB index statistics collection code should "
1121+ "treat NULLs. Possible values are NULLS_EQUAL (default), "
1122+ "NULLS_UNEQUAL and NULLS_IGNORED");
1123 }
1124
1125
1126
1127=== modified file 'plugin/innobase/ibuf/ibuf0ibuf.cc'
1128--- plugin/innobase/ibuf/ibuf0ibuf.cc 2012-05-23 00:15:24 +0000
1129+++ plugin/innobase/ibuf/ibuf0ibuf.cc 2012-05-23 00:15:24 +0000
1130@@ -2282,9 +2282,9 @@
1131 fseg_free_page(header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
1132 IBUF_SPACE_ID, page_no, &mtr);
1133
1134-#ifdef UNIV_DEBUG_FILE_ACCESSES
1135+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1136 buf_page_reset_file_page_was_freed(IBUF_SPACE_ID, page_no);
1137-#endif
1138+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
1139
1140 ibuf_enter();
1141
1142@@ -2328,9 +2328,9 @@
1143 ibuf_bitmap_page_set_bits(
1144 bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, FALSE, &mtr);
1145
1146-#ifdef UNIV_DEBUG_FILE_ACCESSES
1147+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1148 buf_page_set_file_page_was_freed(IBUF_SPACE_ID, page_no);
1149-#endif
1150+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
1151 mtr_commit(&mtr);
1152
1153 ibuf_exit();
1154@@ -2591,23 +2591,6 @@
1155
1156 if (UNIV_UNLIKELY(ibuf->empty)
1157 && UNIV_LIKELY(!srv_shutdown_state)) {
1158-ibuf_is_empty:
1159-
1160-#if 0 /* TODO */
1161- if (srv_shutdown_state) {
1162- /* If the insert buffer becomes empty during
1163- shutdown, note it in the system tablespace. */
1164-
1165- trx_sys_set_ibuf_format(TRX_SYS_IBUF_EMPTY);
1166- }
1167-
1168- /* TO DO: call trx_sys_set_ibuf_format() at startup
1169- and whenever ibuf_use is changed to allow buffered
1170- delete-marking or deleting. Never downgrade the
1171- stamped format except when the insert buffer becomes
1172- empty. */
1173-#endif
1174-
1175 return(0);
1176 }
1177
1178@@ -2637,7 +2620,7 @@
1179 mtr_commit(&mtr);
1180 btr_pcur_close(&pcur);
1181
1182- goto ibuf_is_empty;
1183+ return(0);
1184 }
1185
1186 sum_sizes = ibuf_get_merge_page_nos(TRUE, btr_pcur_get_rec(&pcur),
1187
1188=== modified file 'plugin/innobase/include/btr0cur.h'
1189--- plugin/innobase/include/btr0cur.h 2012-05-23 00:15:24 +0000
1190+++ plugin/innobase/include/btr0cur.h 2012-05-23 00:15:24 +0000
1191@@ -467,7 +467,10 @@
1192 /*******************************************************************//**
1193 Estimates the number of different key values in a given index, for
1194 each n-column prefix of the index where n <= dict_index_get_n_unique(index).
1195-The estimates are stored in the array index->stat_n_diff_key_vals. */
1196+The estimates are stored in the array index->stat_n_diff_key_vals.
1197+If innodb_stats_method is nulls_ignored, we also record the number of
1198+non-null values for each prefix and stored the estimates in
1199+array index->stat_n_non_null_key_vals. */
1200 UNIV_INTERN
1201 void
1202 btr_estimate_number_of_different_key_vals(
1203@@ -498,8 +501,8 @@
1204 @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
1205 UNIV_INTERN
1206 ulint
1207-btr_store_big_rec_extern_fields(
1208-/*============================*/
1209+btr_store_big_rec_extern_fields_func(
1210+/*=================================*/
1211 dict_index_t* index, /*!< in: index of rec; the index tree
1212 MUST be X-latched */
1213 buf_block_t* rec_block, /*!< in/out: block containing rec */
1214@@ -508,10 +511,42 @@
1215 the "external storage" flags in offsets
1216 will not correspond to rec when
1217 this function returns */
1218- big_rec_t* big_rec_vec, /*!< in: vector containing fields
1219+#ifdef UNIV_DEBUG
1220+ mtr_t* local_mtr, /*!< in: mtr containing the
1221+ latch to rec and to the tree */
1222+#endif /* UNIV_DEBUG */
1223+#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
1224+ ibool update_in_place,/*! in: TRUE if the record is updated
1225+ in place (not delete+insert) */
1226+#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
1227+ const big_rec_t*big_rec_vec) /*!< in: vector containing fields
1228 to be stored externally */
1229- mtr_t* local_mtr); /*!< in: mtr containing the latch to
1230- rec and to the tree */
1231+ __attribute__((nonnull));
1232+
1233+/** Stores the fields in big_rec_vec to the tablespace and puts pointers to
1234+them in rec. The extern flags in rec will have to be set beforehand.
1235+The fields are stored on pages allocated from leaf node
1236+file segment of the index tree.
1237+@param index in: clustered index; MUST be X-latched by mtr
1238+@param b in/out: block containing rec; MUST be X-latched by mtr
1239+@param rec in/out: clustered index record
1240+@param offsets in: rec_get_offsets(rec, index);
1241+ the "external storage" flags in offsets will not be adjusted
1242+@param mtr in: mini-transaction that holds x-latch on index and b
1243+@param upd in: TRUE if the record is updated in place (not delete+insert)
1244+@param big in: vector containing fields to be stored externally
1245+@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
1246+#ifdef UNIV_DEBUG
1247+# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
1248+ btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big)
1249+#elif defined UNIV_BLOB_LIGHT_DEBUG
1250+# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
1251+ btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big)
1252+#else
1253+# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
1254+ btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big)
1255+#endif
1256+
1257 /*******************************************************************//**
1258 Frees the space in an externally stored field to the file space
1259 management if the field in data is owned the externally stored field,
1260
1261=== modified file 'plugin/innobase/include/buf0buf.h'
1262--- plugin/innobase/include/buf0buf.h 2012-05-23 00:15:24 +0000
1263+++ plugin/innobase/include/buf0buf.h 2012-05-23 00:15:24 +0000
1264@@ -273,9 +273,9 @@
1265 buf_block_t*
1266 buf_block_alloc(
1267 /*============*/
1268- buf_pool_t* buf_pool, /*!< buffer pool instance */
1269- ulint zip_size); /*!< in: compressed page size in bytes,
1270- or 0 if uncompressed tablespace */
1271+ buf_pool_t* buf_pool); /*!< in: buffer pool instance,
1272+ or NULL for round-robin selection
1273+ of the buffer pool */
1274 /********************************************************************//**
1275 Frees a buffer block which does not contain a file page. */
1276 UNIV_INLINE
1277@@ -477,7 +477,7 @@
1278 /*================================*/
1279 ulint space, /*!< in: space id */
1280 ulint offset);/*!< in: page number */
1281-#ifdef UNIV_DEBUG_FILE_ACCESSES
1282+#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1283 /********************************************************************//**
1284 Sets file_page_was_freed TRUE if the page is found in the buffer pool.
1285 This function should be called when we free a file page and want the
1286@@ -502,7 +502,7 @@
1287 /*===============================*/
1288 ulint space, /*!< in: space id */
1289 ulint offset); /*!< in: page number */
1290-#endif /* UNIV_DEBUG_FILE_ACCESSES */
1291+#endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
1292 /********************************************************************//**
1293 Reads the freed_page_clock of a buffer block.
1294 @return freed_page_clock */
1295@@ -1400,11 +1400,11 @@
1296 0 if the block was never accessed
1297 in the buffer pool */
1298 /* @} */
1299-# ifdef UNIV_DEBUG_FILE_ACCESSES
1300+# if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
1301 ibool file_page_was_freed;
1302 /*!< this is set to TRUE when fsp
1303 frees a page in buffer pool */
1304-# endif /* UNIV_DEBUG_FILE_ACCESSES */
1305+# endif /* UNIV_DEBUG_FILE_ACCESSES || UNIV_DEBUG */
1306 #endif /* !UNIV_HOTBACKUP */
1307 };
1308
1309
1310=== modified file 'plugin/innobase/include/buf0lru.h'
1311--- plugin/innobase/include/buf0lru.h 2011-04-07 12:10:16 +0000
1312+++ plugin/innobase/include/buf0lru.h 2012-05-23 00:15:24 +0000
1313@@ -113,12 +113,9 @@
1314 buf_LRU_free_block(
1315 /*===============*/
1316 buf_page_t* bpage, /*!< in: block to be freed */
1317- ibool zip, /*!< in: TRUE if should remove also the
1318+ ibool zip) /*!< in: TRUE if should remove also the
1319 compressed page of an uncompressed page */
1320- ibool* buf_pool_mutex_released);
1321- /*!< in: pointer to a variable that will
1322- be assigned TRUE if buf_pool->mutex
1323- was temporarily released, or NULL */
1324+ __attribute__((nonnull));
1325 /******************************************************************//**
1326 Try to free a replaceable block.
1327 @return TRUE if found and freed */
1328@@ -155,9 +152,8 @@
1329 buf_block_t*
1330 buf_LRU_get_free_block(
1331 /*===================*/
1332- buf_pool_t* buf_pool, /*!< in: preferred buffer pool */
1333- ulint zip_size); /*!< in: compressed page size in bytes,
1334- or 0 if uncompressed tablespace */
1335+ buf_pool_t* buf_pool) /*!< in/out: buffer pool instance */
1336+ __attribute__((nonnull,warn_unused_result));
1337
1338 /******************************************************************//**
1339 Puts a block back to the free list. */
1340
1341=== modified file 'plugin/innobase/include/dict0mem.h'
1342--- plugin/innobase/include/dict0mem.h 2012-05-23 00:15:24 +0000
1343+++ plugin/innobase/include/dict0mem.h 2012-05-23 00:15:24 +0000
1344@@ -377,6 +377,12 @@
1345 dict_get_n_unique(index); we
1346 periodically calculate new
1347 estimates */
1348+ ib_int64_t* stat_n_non_null_key_vals;
1349+ /* approximate number of non-null key values
1350+ for this index, for each column where
1351+ n < dict_get_n_unique(index); This
1352+ is used when innodb_stats_method is
1353+ "nulls_ignored". */
1354 ulint stat_index_size;
1355 /*!< approximate index size in
1356 database pages */
1357
1358=== modified file 'plugin/innobase/include/dict0types.h'
1359--- plugin/innobase/include/dict0types.h 2011-03-14 05:40:28 +0000
1360+++ plugin/innobase/include/dict0types.h 2012-05-23 00:15:24 +0000
1361@@ -34,11 +34,6 @@
1362 typedef struct dict_table_struct dict_table_t;
1363 typedef struct dict_foreign_struct dict_foreign_t;
1364
1365-/* A cluster object is a table object with the type field set to
1366-DICT_CLUSTERED */
1367-
1368-typedef dict_table_t dict_cluster_t;
1369-
1370 typedef struct ind_node_struct ind_node_t;
1371 typedef struct tab_node_struct tab_node_t;
1372
1373
1374=== modified file 'plugin/innobase/include/rem0cmp.h'
1375--- plugin/innobase/include/rem0cmp.h 2011-03-14 05:40:28 +0000
1376+++ plugin/innobase/include/rem0cmp.h 2012-05-23 00:15:24 +0000
1377@@ -166,6 +166,10 @@
1378 const ulint* offsets1,/*!< in: rec_get_offsets(rec1, index) */
1379 const ulint* offsets2,/*!< in: rec_get_offsets(rec2, index) */
1380 dict_index_t* index, /*!< in: data dictionary index */
1381+ ibool nulls_unequal,
1382+ /* in: TRUE if this is for index statistics
1383+ cardinality estimation, and innodb_stats_method
1384+ is "nulls_unequal" or "nulls_ignored" */
1385 ulint* matched_fields, /*!< in/out: number of already completely
1386 matched fields; when the function returns,
1387 contains the value the for current
1388
1389=== modified file 'plugin/innobase/include/rem0cmp.ic'
1390--- plugin/innobase/include/rem0cmp.ic 2010-12-18 04:43:40 +0000
1391+++ plugin/innobase/include/rem0cmp.ic 2012-05-23 00:15:24 +0000
1392@@ -87,5 +87,5 @@
1393 ulint match_b = 0;
1394
1395 return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
1396- &match_f, &match_b));
1397+ FALSE, &match_f, &match_b));
1398 }
1399
1400=== modified file 'plugin/innobase/include/row0upd.h'
1401--- plugin/innobase/include/row0upd.h 2012-05-23 00:15:24 +0000
1402+++ plugin/innobase/include/row0upd.h 2012-05-23 00:15:24 +0000
1403@@ -281,19 +281,29 @@
1404 @return TRUE if update vector changes an ordering field in the index record */
1405 UNIV_INTERN
1406 ibool
1407-row_upd_changes_ord_field_binary(
1408-/*=============================*/
1409+row_upd_changes_ord_field_binary_func(
1410+/*==================================*/
1411+ dict_index_t* index, /*!< in: index of the record */
1412+ const upd_t* update, /*!< in: update vector for the row; NOTE: the
1413+ field numbers in this MUST be clustered index
1414+ positions! */
1415+#ifdef UNIV_DEBUG
1416+ const que_thr_t*thr, /*!< in: query thread */
1417+#endif /* UNIV_DEBUG */
1418 const dtuple_t* row, /*!< in: old value of row, or NULL if the
1419 row and the data values in update are not
1420 known when this function is called, e.g., at
1421 compile time */
1422- const row_ext_t*ext, /*!< NULL, or prefixes of the externally
1423+ const row_ext_t*ext) /*!< NULL, or prefixes of the externally
1424 stored columns in the old row */
1425- dict_index_t* index, /*!< in: index of the record */
1426- const upd_t* update) /*!< in: update vector for the row; NOTE: the
1427- field numbers in this MUST be clustered index
1428- positions! */
1429- __attribute__((nonnull(3,4), warn_unused_result));
1430+ __attribute__((nonnull(1,2), warn_unused_result));
1431+#ifdef UNIV_DEBUG
1432+# define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \
1433+ row_upd_changes_ord_field_binary_func(index,update,thr,row,ext)
1434+#else /* UNIV_DEBUG */
1435+# define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \
1436+ row_upd_changes_ord_field_binary_func(index,update,row,ext)
1437+#endif /* UNIV_DEBUG */
1438 /***********************************************************//**
1439 Checks if an update vector changes an ordering field of an index record.
1440 This function is fast if the update vector is short or the number of ordering
1441
1442=== modified file 'plugin/innobase/include/srv0srv.h'
1443--- plugin/innobase/include/srv0srv.h 2012-05-23 00:15:24 +0000
1444+++ plugin/innobase/include/srv0srv.h 2012-05-23 00:15:24 +0000
1445@@ -183,6 +183,11 @@
1446 is 5% of the max where max is srv_io_capacity. */
1447 #define PCT_IO(p) ((ulong) (srv_io_capacity * ((double) p / 100.0)))
1448
1449+/* The "innodb_stats_method" setting, decides how InnoDB is going
1450+to treat NULL value when collecting statistics. It is not defined
1451+as enum type because the configure option takes unsigned integer type. */
1452+extern ulong srv_innodb_stats_method;
1453+
1454 #ifdef UNIV_LOG_ARCHIVE
1455 extern ibool srv_log_archive_on;
1456 extern ibool srv_archive_recovery;
1457@@ -445,6 +450,19 @@
1458 in connection with recovery */
1459 };
1460
1461+/* Alternatives for srv_innodb_stats_method, which could be changed by
1462+setting innodb_stats_method */
1463+enum srv_stats_method_name_enum {
1464+ SRV_STATS_NULLS_EQUAL, /* All NULL values are treated as
1465+ equal. This is the default setting
1466+ for innodb_stats_method */
1467+ SRV_STATS_NULLS_UNEQUAL, /* All NULL values are treated as
1468+ NOT equal. */
1469+ SRV_STATS_NULLS_IGNORED /* NULL values are ignored */
1470+};
1471+
1472+typedef enum srv_stats_method_name_enum srv_stats_method_name_t;
1473+
1474 #ifndef UNIV_HOTBACKUP
1475 /** Types of threads existing in the system. */
1476 enum srv_thread_type {
1477
1478=== modified file 'plugin/innobase/include/sync0rw.h'
1479--- plugin/innobase/include/sync0rw.h 2012-05-23 00:15:24 +0000
1480+++ plugin/innobase/include/sync0rw.h 2012-05-23 00:15:24 +0000
1481@@ -1,6 +1,6 @@
1482 /*****************************************************************************
1483
1484-Copyright (C) 1995, 2010, Innobase Oy. All Rights Reserved.
1485+Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
1486 Copyright (C) 2008, Google Inc.
1487
1488 Portions of this file contain modifications contributed and copyrighted by
1489@@ -556,6 +556,7 @@
1490 void
1491 rw_lock_debug_print(
1492 /*================*/
1493+ FILE* f, /*!< in: output stream */
1494 rw_lock_debug_t* info); /*!< in: debug struct */
1495 #endif /* UNIV_SYNC_DEBUG */
1496
1497
1498=== modified file 'plugin/innobase/include/trx0rseg.h'
1499--- plugin/innobase/include/trx0rseg.h 2011-03-14 05:40:28 +0000
1500+++ plugin/innobase/include/trx0rseg.h 2012-05-23 00:15:24 +0000
1501@@ -142,9 +142,7 @@
1502 ulint id; /*!< rollback segment id == the index of
1503 its slot in the trx system file copy */
1504 mutex_t mutex; /*!< mutex protecting the fields in this
1505- struct except id; NOTE that the latching
1506- order must always be kernel mutex ->
1507- rseg mutex */
1508+ struct except id, which is constant */
1509 ulint space; /*!< space where the rollback segment is
1510 header is placed */
1511 ulint zip_size;/* compressed page size of space
1512
1513=== modified file 'plugin/innobase/include/trx0trx.h'
1514--- plugin/innobase/include/trx0trx.h 2011-03-14 05:40:28 +0000
1515+++ plugin/innobase/include/trx0trx.h 2012-05-23 00:15:24 +0000
1516@@ -225,12 +225,12 @@
1517 /*******************************************************************//**
1518 This function is used to find one X/Open XA distributed transaction
1519 which is in the prepared state
1520-@return trx or NULL */
1521+@return trx or NULL; on match, the trx->xid will be invalidated */
1522 UNIV_INTERN
1523 trx_t *
1524 trx_get_trx_by_xid(
1525 /*===============*/
1526- XID* xid); /*!< in: X/Open XA transaction identification */
1527+ const XID* xid); /*!< in: X/Open XA transaction identifier */
1528 /**********************************************************************//**
1529 If required, flushes the log to disk if we called trx_commit_for_mysql()
1530 with trx->flush_log_later == TRUE.
1531
1532=== modified file 'plugin/innobase/include/univ.i'
1533--- plugin/innobase/include/univ.i 2012-05-23 00:15:24 +0000
1534+++ plugin/innobase/include/univ.i 2012-05-23 00:15:24 +0000
1535@@ -204,14 +204,15 @@
1536 debugging without UNIV_DEBUG */
1537 #define UNIV_BUF_DEBUG /* Enable buffer pool
1538 debugging without UNIV_DEBUG */
1539+#define UNIV_BLOB_LIGHT_DEBUG /* Enable off-page column
1540+ debugging without UNIV_DEBUG */
1541 #define UNIV_DEBUG /* Enable ut_ad() assertions
1542 and disable UNIV_INLINE */
1543 #define UNIV_DEBUG_LOCK_VALIDATE /* Enable
1544 ut_ad(lock_rec_validate_page())
1545 assertions. */
1546-#define UNIV_DEBUG_FILE_ACCESSES /* Debug .ibd file access
1547- (field file_page_was_freed
1548- in buf_page_t) */
1549+#define UNIV_DEBUG_FILE_ACCESSES /* Enable freed block access
1550+ debugging without UNIV_DEBUG */
1551 #define UNIV_LRU_DEBUG /* debug the buffer pool LRU */
1552 #define UNIV_HASH_DEBUG /* debug HASH_ macros */
1553 #define UNIV_LIST_DEBUG /* debug UT_LIST_ macros */
1554
1555=== modified file 'plugin/innobase/mem/mem0mem.cc'
1556--- plugin/innobase/mem/mem0mem.cc 2010-12-26 00:22:34 +0000
1557+++ plugin/innobase/mem/mem0mem.cc 2012-05-23 00:15:24 +0000
1558@@ -348,7 +348,7 @@
1559 return(NULL);
1560 }
1561 } else {
1562- buf_block = buf_block_alloc(NULL, 0);
1563+ buf_block = buf_block_alloc(NULL);
1564 }
1565
1566 block = (mem_block_t*) buf_block->frame;
1567
1568=== modified file 'plugin/innobase/page/page0zip.cc'
1569--- plugin/innobase/page/page0zip.cc 2011-04-05 10:32:12 +0000
1570+++ plugin/innobase/page/page0zip.cc 2012-05-23 00:15:24 +0000
1571@@ -4434,7 +4434,7 @@
1572 log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
1573
1574 #ifndef UNIV_HOTBACKUP
1575- temp_block = buf_block_alloc(buf_pool, 0);
1576+ temp_block = buf_block_alloc(buf_pool);
1577 btr_search_drop_page_hash_index(block);
1578 block->check_index_page_at_flush = TRUE;
1579 #else /* !UNIV_HOTBACKUP */
1580
1581=== modified file 'plugin/innobase/rem/rem0cmp.cc'
1582--- plugin/innobase/rem/rem0cmp.cc 2010-12-27 05:56:47 +0000
1583+++ plugin/innobase/rem/rem0cmp.cc 2012-05-23 00:15:24 +0000
1584@@ -861,6 +861,10 @@
1585 const ulint* offsets1,/*!< in: rec_get_offsets(rec1, index) */
1586 const ulint* offsets2,/*!< in: rec_get_offsets(rec2, index) */
1587 dict_index_t* index, /*!< in: data dictionary index */
1588+ ibool nulls_unequal,
1589+ /* in: TRUE if this is for index statistics
1590+ cardinality estimation, and innodb_stats_method
1591+ is "nulls_unequal" or "nulls_ignored" */
1592 ulint* matched_fields, /*!< in/out: number of already completely
1593 matched fields; when the function returns,
1594 contains the value the for current
1595@@ -960,9 +964,13 @@
1596 || rec2_f_len == UNIV_SQL_NULL) {
1597
1598 if (rec1_f_len == rec2_f_len) {
1599-
1600- goto next_field;
1601-
1602+ /* This is limited to stats collection,
1603+ cannot use it for regular search */
1604+ if (nulls_unequal) {
1605+ ret = -1;
1606+ } else {
1607+ goto next_field;
1608+ }
1609 } else if (rec2_f_len == UNIV_SQL_NULL) {
1610
1611 /* We define the SQL null to be the
1612
1613=== modified file 'plugin/innobase/row/row0ins.cc'
1614--- plugin/innobase/row/row0ins.cc 2012-05-23 00:15:24 +0000
1615+++ plugin/innobase/row/row0ins.cc 2012-05-23 00:15:24 +0000
1616@@ -2123,7 +2123,7 @@
1617
1618 err = btr_store_big_rec_extern_fields(
1619 index, btr_cur_get_block(&cursor),
1620- exit_rec, offsets, big_rec, &mtr);
1621+ exit_rec, offsets, &mtr, FALSE, big_rec);
1622
1623 if (modify) {
1624 dtuple_big_rec_free(big_rec);
1625
1626=== modified file 'plugin/innobase/row/row0merge.cc'
1627--- plugin/innobase/row/row0merge.cc 2012-05-23 00:15:24 +0000
1628+++ plugin/innobase/row/row0merge.cc 2012-05-23 00:15:24 +0000
1629@@ -2193,13 +2193,15 @@
1630 }
1631
1632 /*********************************************************************//**
1633-Create a merge file. */
1634-static
1635-void
1636-row_merge_file_create(
1637-/*==================*/
1638- merge_file_t* merge_file) /*!< out: merge file structure */
1639+Creates temperary merge files, and if UNIV_PFS_IO defined, register
1640+the file descriptor with Performance Schema.
1641+@return File descriptor */
1642+UNIV_INLINE
1643+int
1644+row_merge_file_create_low(void)
1645+/*===========================*/
1646 {
1647+ int fd;
1648 #ifdef UNIV_PFS_IO
1649 /* This temp file open does not go through normal
1650 file APIs, add instrumentation to register with
1651@@ -2211,15 +2213,47 @@
1652 "Innodb Merge Temp File",
1653 __FILE__, __LINE__);
1654 #endif
1655- merge_file->fd = innobase_mysql_tmpfile();
1656+ fd = innobase_mysql_tmpfile();
1657+#ifdef UNIV_PFS_IO
1658+ register_pfs_file_open_end(locker, fd);
1659+#endif
1660+ return(fd);
1661+}
1662+/*********************************************************************//**
1663+Create a merge file. */
1664+static
1665+void
1666+row_merge_file_create(
1667+/*==================*/
1668+ merge_file_t* merge_file) /*!< out: merge file structure */
1669+{
1670+ merge_file->fd = row_merge_file_create_low();
1671 merge_file->offset = 0;
1672 merge_file->n_rec = 0;
1673-#ifdef UNIV_PFS_IO
1674- register_pfs_file_open_end(locker, merge_file->fd);
1675-#endif
1676 }
1677
1678 /*********************************************************************//**
1679+Destroy a merge file. And de-register the file from Performance Schema
1680+if UNIV_PFS_IO is defined. */
1681+UNIV_INLINE
1682+void
1683+row_merge_file_destroy_low(
1684+/*=======================*/
1685+ int fd) /*!< in: merge file descriptor */
1686+{
1687+#ifdef UNIV_PFS_IO
1688+ struct PSI_file_locker* locker = NULL;
1689+ PSI_file_locker_state state;
1690+ register_pfs_file_io_begin(&state, locker,
1691+ fd, 0, PSI_FILE_CLOSE,
1692+ __FILE__, __LINE__);
1693+#endif
1694+ close(fd);
1695+#ifdef UNIV_PFS_IO
1696+ register_pfs_file_io_end(locker, 0);
1697+#endif
1698+}
1699+/*********************************************************************//**
1700 Destroy a merge file. */
1701 static
1702 void
1703@@ -2227,20 +2261,10 @@
1704 /*===================*/
1705 merge_file_t* merge_file) /*!< out: merge file structure */
1706 {
1707-#ifdef UNIV_PFS_IO
1708- struct PSI_file_locker* locker = NULL;
1709- PSI_file_locker_state state;
1710- register_pfs_file_io_begin(&state, locker, merge_file->fd, 0, PSI_FILE_CLOSE,
1711- __FILE__, __LINE__);
1712-#endif
1713 if (merge_file->fd != -1) {
1714- close(merge_file->fd);
1715+ row_merge_file_destroy_low(merge_file->fd);
1716 merge_file->fd = -1;
1717 }
1718-
1719-#ifdef UNIV_PFS_IO
1720- register_pfs_file_io_end(locker, 0);
1721-#endif
1722 }
1723
1724 /*********************************************************************//**
1725@@ -2646,7 +2670,7 @@
1726 row_merge_file_create(&merge_files[i]);
1727 }
1728
1729- tmpfd = innobase_mysql_tmpfile();
1730+ tmpfd = row_merge_file_create_low();
1731
1732 /* Reset the MySQL row buffer that is used when reporting
1733 duplicate keys. */
1734@@ -2688,7 +2712,7 @@
1735 }
1736
1737 func_exit:
1738- close(tmpfd);
1739+ row_merge_file_destroy_low(tmpfd);
1740
1741 for (i = 0; i < n_indexes; i++) {
1742 row_merge_file_destroy(&merge_files[i]);
1743
1744=== modified file 'plugin/innobase/row/row0purge.cc'
1745--- plugin/innobase/row/row0purge.cc 2012-05-23 00:15:24 +0000
1746+++ plugin/innobase/row/row0purge.cc 2012-05-23 00:15:24 +0000
1747@@ -499,8 +499,11 @@
1748 marked record if that record contained an externally stored field. */
1749 static
1750 void
1751-row_purge_upd_exist_or_extern(
1752-/*==========================*/
1753+row_purge_upd_exist_or_extern_func(
1754+/*===============================*/
1755+#ifdef UNIV_DEBUG
1756+ const que_thr_t*thr, /*!< in: query thread */
1757+#endif /* UNIV_DEBUG */
1758 purge_node_t* node) /*!< in: row purge node */
1759 {
1760 mem_heap_t* heap;
1761@@ -525,8 +528,8 @@
1762 while (node->index != NULL) {
1763 index = node->index;
1764
1765- if (row_upd_changes_ord_field_binary(NULL, NULL, node->index,
1766- node->update)) {
1767+ if (row_upd_changes_ord_field_binary(node->index, node->update,
1768+ thr, NULL, NULL)) {
1769 /* Build the older version of the index entry */
1770 entry = row_build_index_entry(node->row, NULL,
1771 index, heap);
1772@@ -608,6 +611,14 @@
1773 }
1774 }
1775
1776+#ifdef UNIV_DEBUG
1777+# define row_purge_upd_exist_or_extern(thr,node) \
1778+ row_purge_upd_exist_or_extern_func(thr,node)
1779+#else /* UNIV_DEBUG */
1780+# define row_purge_upd_exist_or_extern(thr,node) \
1781+ row_purge_upd_exist_or_extern_func(node)
1782+#endif /* UNIV_DEBUG */
1783+
1784 /***********************************************************//**
1785 Parses the row reference and other info in a modify undo log record.
1786 @return TRUE if purge operation required: NOTE that then the CALLER
1787@@ -714,47 +725,32 @@
1788 /***********************************************************//**
1789 Fetches an undo log record and does the purge for the recorded operation.
1790 If none left, or the current purge completed, returns the control to the
1791-parent node, which is always a query thread node.
1792-@return DB_SUCCESS if operation successfully completed, else error code */
1793-static
1794-ulint
1795+parent node, which is always a query thread node. */
1796+static __attribute__((nonnull))
1797+void
1798 row_purge(
1799 /*======*/
1800 purge_node_t* node, /*!< in: row purge node */
1801 que_thr_t* thr) /*!< in: query thread */
1802 {
1803- roll_ptr_t roll_ptr;
1804- ibool purge_needed;
1805 ibool updated_extern;
1806- trx_t* trx;
1807-
1808- ut_ad(node && thr);
1809-
1810- trx = thr_get_trx(thr);
1811-
1812- node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr,
1813- &(node->reservation),
1814+
1815+ ut_ad(node);
1816+ ut_ad(thr);
1817+
1818+ node->undo_rec = trx_purge_fetch_next_rec(&node->roll_ptr,
1819+ &node->reservation,
1820 node->heap);
1821 if (!node->undo_rec) {
1822 /* Purge completed for this query thread */
1823
1824 thr->run_node = que_node_get_parent(node);
1825
1826- return(DB_SUCCESS);
1827- }
1828-
1829- node->roll_ptr = roll_ptr;
1830-
1831- if (node->undo_rec == &trx_purge_dummy_rec) {
1832- purge_needed = FALSE;
1833- } else {
1834- purge_needed = row_purge_parse_undo_rec(node, &updated_extern,
1835- thr);
1836- /* If purge_needed == TRUE, we must also remember to unfreeze
1837- data dictionary! */
1838- }
1839-
1840- if (purge_needed) {
1841+ return;
1842+ }
1843+
1844+ if (node->undo_rec != &trx_purge_dummy_rec
1845+ && row_purge_parse_undo_rec(node, &updated_extern, thr)) {
1846 node->found_clust = FALSE;
1847
1848 node->index = dict_table_get_next_index(
1849@@ -766,14 +762,14 @@
1850 } else if (updated_extern
1851 || node->rec_type == TRX_UNDO_UPD_EXIST_REC) {
1852
1853- row_purge_upd_exist_or_extern(node);
1854+ row_purge_upd_exist_or_extern(thr, node);
1855 }
1856
1857 if (node->found_clust) {
1858 btr_pcur_close(&(node->pcur));
1859 }
1860
1861- row_mysql_unfreeze_data_dictionary(trx);
1862+ row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
1863 }
1864
1865 /* Do some cleanup */
1866@@ -781,8 +777,6 @@
1867 mem_heap_empty(node->heap);
1868
1869 thr->run_node = node;
1870-
1871- return(DB_SUCCESS);
1872 }
1873
1874 /***********************************************************//**
1875@@ -796,9 +790,6 @@
1876 que_thr_t* thr) /*!< in: query thread */
1877 {
1878 purge_node_t* node;
1879-#ifdef UNIV_DEBUG
1880- ulint err;
1881-#endif /* UNIV_DEBUG */
1882
1883 ut_ad(thr);
1884
1885@@ -806,14 +797,7 @@
1886
1887 ut_ad(que_node_get_type(node) == QUE_NODE_PURGE);
1888
1889-#ifdef UNIV_DEBUG
1890- err =
1891-#endif /* UNIV_DEBUG */
1892 row_purge(node, thr);
1893
1894-#ifdef UNIV_DEBUG
1895- ut_a(err == DB_SUCCESS);
1896-#endif /* UNIV_DEBUG */
1897-
1898 return(thr);
1899 }
1900
1901=== modified file 'plugin/innobase/row/row0umod.cc'
1902--- plugin/innobase/row/row0umod.cc 2012-05-23 00:15:24 +0000
1903+++ plugin/innobase/row/row0umod.cc 2012-05-23 00:15:24 +0000
1904@@ -173,40 +173,26 @@
1905 mtr_t* mtr, /*!< in: mtr */
1906 ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
1907 {
1908- btr_pcur_t* pcur;
1909 btr_cur_t* btr_cur;
1910 ulint err;
1911- ibool success;
1912
1913 ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC);
1914- pcur = &(node->pcur);
1915- btr_cur = btr_pcur_get_btr_cur(pcur);
1916-
1917- success = btr_pcur_restore_position(mode, pcur, mtr);
1918-
1919- if (!success) {
1920-
1921- return(DB_SUCCESS);
1922- }
1923-
1924- /* Find out if we can remove the whole clustered index record */
1925-
1926- if (node->rec_type == TRX_UNDO_UPD_DEL_REC
1927- && !row_vers_must_preserve_del_marked(node->new_trx_id, mtr)) {
1928-
1929- /* Ok, we can remove */
1930- } else {
1931- return(DB_SUCCESS);
1932- }
1933+
1934+ /* Find out if the record has been purged already
1935+ or if we can remove it. */
1936+
1937+ if (!btr_pcur_restore_position(mode, &node->pcur, mtr)
1938+ || row_vers_must_preserve_del_marked(node->new_trx_id, mtr)) {
1939+
1940+ return(DB_SUCCESS);
1941+ }
1942+
1943+ btr_cur = btr_pcur_get_btr_cur(&node->pcur);
1944
1945 if (mode == BTR_MODIFY_LEAF) {
1946- success = btr_cur_optimistic_delete(btr_cur, mtr);
1947-
1948- if (success) {
1949- err = DB_SUCCESS;
1950- } else {
1951- err = DB_FAIL;
1952- }
1953+ err = btr_cur_optimistic_delete(btr_cur, mtr)
1954+ ? DB_SUCCESS
1955+ : DB_FAIL;
1956 } else {
1957 ut_ad(mode == BTR_MODIFY_TREE);
1958
1959@@ -693,8 +679,9 @@
1960 while (node->index != NULL) {
1961 index = node->index;
1962
1963- if (row_upd_changes_ord_field_binary(
1964- node->row, node->ext, node->index, node->update)) {
1965+ if (row_upd_changes_ord_field_binary(node->index, node->update,
1966+ thr,
1967+ node->row, node->ext)) {
1968
1969 /* Build the newest version of the index entry */
1970 entry = row_build_index_entry(node->row, node->ext,
1971
1972=== modified file 'plugin/innobase/row/row0upd.cc'
1973--- plugin/innobase/row/row0upd.cc 2012-05-23 00:15:24 +0000
1974+++ plugin/innobase/row/row0upd.cc 2012-05-23 00:15:24 +0000
1975@@ -1202,25 +1202,31 @@
1976 @return TRUE if update vector changes an ordering field in the index record */
1977 UNIV_INTERN
1978 ibool
1979-row_upd_changes_ord_field_binary(
1980-/*=============================*/
1981+row_upd_changes_ord_field_binary_func(
1982+/*==================================*/
1983+ dict_index_t* index, /*!< in: index of the record */
1984+ const upd_t* update, /*!< in: update vector for the row; NOTE: the
1985+ field numbers in this MUST be clustered index
1986+ positions! */
1987+#ifdef UNIV_DEBUG
1988+ const que_thr_t*thr, /*!< in: query thread */
1989+#endif /* UNIV_DEBUG */
1990 const dtuple_t* row, /*!< in: old value of row, or NULL if the
1991 row and the data values in update are not
1992 known when this function is called, e.g., at
1993 compile time */
1994- const row_ext_t*ext, /*!< NULL, or prefixes of the externally
1995+ const row_ext_t*ext) /*!< NULL, or prefixes of the externally
1996 stored columns in the old row */
1997- dict_index_t* index, /*!< in: index of the record */
1998- const upd_t* update) /*!< in: update vector for the row; NOTE: the
1999- field numbers in this MUST be clustered index
2000- positions! */
2001 {
2002 ulint n_unique;
2003 ulint i;
2004 const dict_index_t* clust_index;
2005
2006+ ut_ad(index);
2007 ut_ad(update);
2008- ut_ad(index);
2009+ ut_ad(thr);
2010+ ut_ad(thr->graph);
2011+ ut_ad(thr->graph->trx);
2012
2013 n_unique = dict_index_get_n_unique(index);
2014
2015@@ -1262,6 +1268,10 @@
2016 || dfield_is_null(dfield)) {
2017 /* do nothing special */
2018 } else if (UNIV_LIKELY_NULL(ext)) {
2019+ /* Silence a compiler warning without
2020+ silencing a Valgrind error. */
2021+ dfield_len = 0;
2022+ UNIV_MEM_INVALID(&dfield_len, sizeof dfield_len);
2023 /* See if the column is stored externally. */
2024 buf = row_ext_lookup(ext, col_no, &dfield_len);
2025
2026@@ -1269,9 +1279,14 @@
2027
2028 if (UNIV_LIKELY_NULL(buf)) {
2029 if (UNIV_UNLIKELY(buf == field_ref_zero)) {
2030- /* This should never happen, but
2031- we try to fail safe here. */
2032- ut_ad(0);
2033+ /* The externally stored field
2034+ was not written yet. This
2035+ record should only be seen by
2036+ recv_recovery_rollback_active(),
2037+ when the server had crashed before
2038+ storing the field. */
2039+ ut_ad(thr->graph->trx->is_recovered);
2040+ ut_ad(trx_is_recv(thr->graph->trx));
2041 return(TRUE);
2042 }
2043
2044@@ -1646,8 +1661,8 @@
2045 ut_ad(!dict_index_is_clust(node->index));
2046
2047 if (node->state == UPD_NODE_UPDATE_ALL_SEC
2048- || row_upd_changes_ord_field_binary(node->row, node->ext,
2049- node->index, node->update)) {
2050+ || row_upd_changes_ord_field_binary(node->index, node->update,
2051+ thr, node->row, node->ext)) {
2052 return(row_upd_sec_index_entry(node, thr));
2053 }
2054
2055@@ -1978,7 +1993,7 @@
2056 index, btr_cur_get_block(btr_cur), rec,
2057 rec_get_offsets(rec, index, offsets_,
2058 ULINT_UNDEFINED, &heap),
2059- big_rec, mtr);
2060+ mtr, TRUE, big_rec);
2061 mtr_commit(mtr);
2062 }
2063
2064@@ -2176,8 +2191,8 @@
2065
2066 row_upd_store_row(node);
2067
2068- if (row_upd_changes_ord_field_binary(node->row, node->ext, index,
2069- node->update)) {
2070+ if (row_upd_changes_ord_field_binary(index, node->update, thr,
2071+ node->row, node->ext)) {
2072
2073 /* Update causes an ordering field (ordering fields within
2074 the B-tree) of the clustered index record to change: perform
2075
2076=== modified file 'plugin/innobase/row/row0vers.cc'
2077--- plugin/innobase/row/row0vers.cc 2010-12-26 15:48:26 +0000
2078+++ plugin/innobase/row/row0vers.cc 2012-05-23 00:15:24 +0000
2079@@ -669,11 +669,15 @@
2080
2081 mutex_enter(&kernel_mutex);
2082 version_trx = trx_get_on_id(version_trx_id);
2083+ if (version_trx
2084+ && (version_trx->conc_state == TRX_COMMITTED_IN_MEMORY
2085+ || version_trx->conc_state == TRX_NOT_STARTED)) {
2086+
2087+ version_trx = NULL;
2088+ }
2089 mutex_exit(&kernel_mutex);
2090
2091- if (!version_trx
2092- || version_trx->conc_state == TRX_NOT_STARTED
2093- || version_trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
2094+ if (!version_trx) {
2095
2096 /* We found a version that belongs to a
2097 committed transaction: return it. */
2098
2099=== modified file 'plugin/innobase/srv/srv0srv.cc'
2100--- plugin/innobase/srv/srv0srv.cc 2012-05-23 00:15:24 +0000
2101+++ plugin/innobase/srv/srv0srv.cc 2012-05-23 00:15:24 +0000
2102@@ -321,6 +321,11 @@
2103 /* variable counts amount of data read in total (in bytes) */
2104 UNIV_INTERN ulint srv_data_read = 0;
2105
2106+/* Internal setting for "innodb_stats_method". Decides how InnoDB treats
2107+NULL value when collecting statistics. By default, it is set to
2108+SRV_STATS_NULLS_EQUAL(0), ie. all NULL value are treated equal */
2109+ulong srv_innodb_stats_method = SRV_STATS_NULLS_EQUAL;
2110+
2111 /* here we count the amount of data written in total (in bytes) */
2112 UNIV_INTERN ulint srv_data_written = 0;
2113
2114@@ -1067,7 +1072,7 @@
2115
2116 slot = srv_table_get_nth_slot(i);
2117
2118- if (slot->in_use && slot->type == type) {
2119+ if (slot->in_use && slot->type == (unsigned int)type) {
2120 slot_no = i;
2121 break;
2122 }
2123
2124=== modified file 'plugin/innobase/srv/srv0start.cc'
2125--- plugin/innobase/srv/srv0start.cc 2012-05-23 00:15:24 +0000
2126+++ plugin/innobase/srv/srv0start.cc 2012-05-23 00:15:24 +0000
2127@@ -1261,13 +1261,16 @@
2128
2129 ut_a(srv_n_file_io_threads <= SRV_MAX_N_IO_THREADS);
2130
2131- /* TODO: Investigate if SRV_N_PENDING_IOS_PER_THREAD (32) limit
2132- still applies to windows. */
2133- if (!srv_use_native_aio) {
2134- io_limit = 8 * SRV_N_PENDING_IOS_PER_THREAD;
2135- } else {
2136+ io_limit = 8 * SRV_N_PENDING_IOS_PER_THREAD;
2137+
2138+ /* On Windows when using native aio the number of aio requests
2139+ that a thread can handle at a given time is limited to 32
2140+ i.e.: SRV_N_PENDING_IOS_PER_THREAD */
2141+# ifdef __WIN__
2142+ if (srv_use_native_aio) {
2143 io_limit = SRV_N_PENDING_IOS_PER_THREAD;
2144 }
2145+# endif /* __WIN__ */
2146
2147 os_aio_init(io_limit,
2148 srv_n_read_io_threads,
2149
2150=== modified file 'plugin/innobase/sync/sync0arr.cc'
2151--- plugin/innobase/sync/sync0arr.cc 2012-05-23 00:15:24 +0000
2152+++ plugin/innobase/sync/sync0arr.cc 2012-05-23 00:15:24 +0000
2153@@ -1,6 +1,6 @@
2154 /*****************************************************************************
2155
2156-Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
2157+Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
2158 Copyright (C) 2008, Google Inc.
2159
2160 Portions of this file contain modifications contributed and copyrighted by
2161@@ -714,7 +714,7 @@
2162 fprintf(stderr, "rw-lock %p ",
2163 (void*) lock);
2164 sync_array_cell_print(stderr, cell);
2165- rw_lock_debug_print(debug);
2166+ rw_lock_debug_print(stderr, debug);
2167 return(TRUE);
2168 }
2169 }
2170
2171=== modified file 'plugin/innobase/sync/sync0rw.cc'
2172--- plugin/innobase/sync/sync0rw.cc 2010-12-24 00:04:05 +0000
2173+++ plugin/innobase/sync/sync0rw.cc 2012-05-23 00:15:24 +0000
2174@@ -1,6 +1,6 @@
2175 /*****************************************************************************
2176
2177-Copyright (C) 1995, 2009, Innobase Oy. All Rights Reserved.
2178+Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
2179 Copyright (C) 2008, Google Inc.
2180
2181 Portions of this file contain modifications contributed and copyrighted by
2182@@ -936,7 +936,7 @@
2183
2184 info = UT_LIST_GET_FIRST(lock->debug_list);
2185 while (info != NULL) {
2186- rw_lock_debug_print(info);
2187+ rw_lock_debug_print(file, info);
2188 info = UT_LIST_GET_NEXT(list, info);
2189 }
2190 }
2191@@ -984,7 +984,7 @@
2192
2193 info = UT_LIST_GET_FIRST(lock->debug_list);
2194 while (info != NULL) {
2195- rw_lock_debug_print(info);
2196+ rw_lock_debug_print(stderr, info);
2197 info = UT_LIST_GET_NEXT(list, info);
2198 }
2199 }
2200@@ -996,28 +996,29 @@
2201 void
2202 rw_lock_debug_print(
2203 /*================*/
2204+ FILE* f, /*!< in: output stream */
2205 rw_lock_debug_t* info) /*!< in: debug struct */
2206 {
2207 ulint rwt;
2208
2209 rwt = info->lock_type;
2210
2211- fprintf(stderr, "Locked: thread %lu file %s line %lu ",
2212+ fprintf(f, "Locked: thread %lu file %s line %lu ",
2213 (ulong) os_thread_pf(info->thread_id), info->file_name,
2214 (ulong) info->line);
2215 if (rwt == RW_LOCK_SHARED) {
2216- fputs("S-LOCK", stderr);
2217+ fputs("S-LOCK", f);
2218 } else if (rwt == RW_LOCK_EX) {
2219- fputs("X-LOCK", stderr);
2220+ fputs("X-LOCK", f);
2221 } else if (rwt == RW_LOCK_WAIT_EX) {
2222- fputs("WAIT X-LOCK", stderr);
2223+ fputs("WAIT X-LOCK", f);
2224 } else {
2225 ut_error;
2226 }
2227 if (info->pass != 0) {
2228- fprintf(stderr, " pass value %lu", (ulong) info->pass);
2229+ fprintf(f, " pass value %lu", (ulong) info->pass);
2230 }
2231- putc('\n', stderr);
2232+ putc('\n', f);
2233 }
2234
2235 /***************************************************************//**
2236
2237=== modified file 'plugin/innobase/sync/sync0sync.cc'
2238--- plugin/innobase/sync/sync0sync.cc 2011-10-20 02:45:57 +0000
2239+++ plugin/innobase/sync/sync0sync.cc 2012-05-23 00:15:24 +0000
2240@@ -189,11 +189,12 @@
2241 UNIV_INTERN ibool sync_initialized = FALSE;
2242
2243 /** An acquired mutex or rw-lock and its level in the latching order */
2244-typedef struct sync_level_struct sync_priority_t;
2245+typedef struct sync_level_struct sync_level_t;
2246 /** Mutexes or rw-locks held by a thread */
2247 typedef struct sync_thread_struct sync_thread_t;
2248
2249 #ifdef UNIV_SYNC_DEBUG
2250+
2251 /** The latch levels currently owned by threads are stored in this data
2252 structure; the size of this array is OS_THREAD_MAX_N */
2253
2254@@ -222,21 +223,40 @@
2255 UNIV_INTERN ibool sync_order_checks_on = FALSE;
2256 #endif /* UNIV_SYNC_DEBUG */
2257
2258+/** Number of slots reserved for each OS thread in the sync level array */
2259+static const ulint SYNC_THREAD_N_LEVELS = 10000;
2260+
2261+typedef struct sync_arr_struct sync_arr_t;
2262+
2263+/** Array for tracking sync levels per thread. */
2264+struct sync_arr_struct {
2265+ ulint in_use; /*!< Number of active cells */
2266+ ulint n_elems; /*!< Number of elements in the array */
2267+ ulint max_elems; /*!< Maximum elements */
2268+ ulint next_free; /*!< ULINT_UNDEFINED or index of next
2269+ free slot */
2270+ sync_level_t* elems; /*!< Array elements */
2271+};
2272+
2273 /** Mutexes or rw-locks held by a thread */
2274 struct sync_thread_struct{
2275- os_thread_id_t id; /*!< OS thread id */
2276- sync_priority_t* levels; /*!< level array for this thread; if
2277- this is NULL this slot is unused */
2278+ os_thread_id_t id; /*!< OS thread id */
2279+ sync_arr_t* levels; /*!< level array for this thread; if
2280+ this is NULL this slot is unused */
2281 };
2282
2283-/** Number of slots reserved for each OS thread in the sync level array */
2284-#define SYNC_THREAD_N_LEVELS 10000
2285-
2286 /** An acquired mutex or rw-lock and its level in the latching order */
2287 struct sync_level_struct{
2288- void* latch; /*!< pointer to a mutex or an rw-lock; NULL means that
2289- the slot is empty */
2290- ulint level; /*!< level of the latch in the latching order */
2291+ void* latch; /*!< pointer to a mutex or an
2292+ rw-lock; NULL means that
2293+ the slot is empty */
2294+ ulint level; /*!< level of the latch in the
2295+ latching order. This field is
2296+ overloaded to serve as a node in a
2297+ linked list of free nodes too. When
2298+ latch == NULL then this will contain
2299+ the ordinal value of the next free
2300+ element */
2301 };
2302
2303 /******************************************************************//**
2304@@ -745,27 +765,28 @@
2305 /*==================*/
2306 {
2307 mutex_t* mutex;
2308- ulint count = 0;
2309+ ulint count = 0;
2310
2311 mutex_enter(&mutex_list_mutex);
2312
2313- mutex = UT_LIST_GET_FIRST(mutex_list);
2314+ for (mutex = UT_LIST_GET_FIRST(mutex_list);
2315+ mutex != NULL;
2316+ mutex = UT_LIST_GET_NEXT(list, mutex)) {
2317
2318- while (mutex != NULL) {
2319 if (mutex_get_lock_word(mutex) != 0) {
2320
2321 count++;
2322 }
2323-
2324- mutex = UT_LIST_GET_NEXT(list, mutex);
2325 }
2326
2327 mutex_exit(&mutex_list_mutex);
2328
2329 ut_a(count >= 1);
2330
2331- return(count - 1); /* Subtract one, because this function itself
2332- was holding one mutex (mutex_list_mutex) */
2333+ /* Subtract one, because this function itself was holding
2334+ one mutex (mutex_list_mutex) */
2335+
2336+ return(count - 1);
2337 }
2338
2339 /******************************************************************//**
2340@@ -781,20 +802,6 @@
2341 }
2342
2343 /******************************************************************//**
2344-Gets the value in the nth slot in the thread level arrays.
2345-@return pointer to thread slot */
2346-static
2347-sync_thread_t*
2348-sync_thread_level_arrays_get_nth(
2349-/*=============================*/
2350- ulint n) /*!< in: slot number */
2351-{
2352- ut_ad(n < OS_THREAD_MAX_N);
2353-
2354- return(sync_thread_level_arrays + n);
2355-}
2356-
2357-/******************************************************************//**
2358 Looks for the thread slot for the calling thread.
2359 @return pointer to thread slot, NULL if not found */
2360 static
2361@@ -803,15 +810,15 @@
2362 /*====================================*/
2363
2364 {
2365- sync_thread_t* slot;
2366+ ulint i;
2367 os_thread_id_t id;
2368- ulint i;
2369
2370 id = os_thread_get_curr_id();
2371
2372 for (i = 0; i < OS_THREAD_MAX_N; i++) {
2373+ sync_thread_t* slot;
2374
2375- slot = sync_thread_level_arrays_get_nth(i);
2376+ slot = &sync_thread_level_arrays[i];
2377
2378 if (slot->levels && os_thread_eq(slot->id, id)) {
2379
2380@@ -831,12 +838,12 @@
2381 /*====================================*/
2382
2383 {
2384- sync_thread_t* slot;
2385 ulint i;
2386
2387 for (i = 0; i < OS_THREAD_MAX_N; i++) {
2388+ sync_thread_t* slot;
2389
2390- slot = sync_thread_level_arrays_get_nth(i);
2391+ slot = &sync_thread_level_arrays[i];
2392
2393 if (slot->levels == NULL) {
2394
2395@@ -849,18 +856,44 @@
2396
2397 /******************************************************************//**
2398 Gets the value in the nth slot in the thread level array.
2399-@return pointer to level slot */
2400+Print warning. */
2401 static
2402-sync_priority_t*
2403-sync_thread_levels_get_nth(
2404-/*=======================*/
2405- sync_priority_t* arr, /*!< in: pointer to level array for an OS
2406- thread */
2407- ulint n) /*!< in: slot number */
2408+void
2409+sync_print_warning(
2410+/*===============*/
2411+ const sync_level_t* slot) /*!< in: slot for which to
2412+ print warning */
2413 {
2414- ut_ad(n < SYNC_THREAD_N_LEVELS);
2415-
2416- return(arr + n);
2417+ mutex_t* mutex;
2418+
2419+ mutex = slot->latch;
2420+
2421+ if (mutex->magic_n == MUTEX_MAGIC_N) {
2422+ fprintf(stderr,
2423+ "Mutex created at %s %lu\n",
2424+ mutex->cfile_name, (ulong) mutex->cline);
2425+
2426+ if (mutex_get_lock_word(mutex) != 0) {
2427+ ulint line;
2428+ const char* file_name;
2429+ os_thread_id_t thread_id;
2430+
2431+ mutex_get_debug_info(
2432+ mutex, &file_name, &line, &thread_id);
2433+
2434+ fprintf(stderr,
2435+ "InnoDB: Locked mutex:"
2436+ " addr %p thread %ld file %s line %ld\n",
2437+ (void*) mutex, os_thread_pf(thread_id),
2438+ file_name, (ulong) line);
2439+ } else {
2440+ fputs("Not locked\n", stderr);
2441+ }
2442+ } else {
2443+ rw_lock_t* lock = slot->latch;
2444+
2445+ rw_lock_print(lock);
2446+ }
2447 }
2448
2449 /******************************************************************//**
2450@@ -871,69 +904,29 @@
2451 ibool
2452 sync_thread_levels_g(
2453 /*=================*/
2454- sync_priority_t* arr, /*!< in: pointer to level array for an OS
2455+ sync_arr_t* arr, /*!< in: pointer to level array for an OS
2456 thread */
2457 ulint limit, /*!< in: level limit */
2458 ulint warn) /*!< in: TRUE=display a diagnostic message */
2459 {
2460- sync_priority_t* slot;
2461- rw_lock_t* lock;
2462- mutex_t* mutex;
2463 ulint i;
2464
2465- for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
2466-
2467- slot = sync_thread_levels_get_nth(arr, i);
2468-
2469- if (slot->latch != NULL) {
2470- if (slot->level <= limit) {
2471-
2472- if (!warn) {
2473-
2474- return(FALSE);
2475- }
2476-
2477- lock = slot->latch;
2478- mutex = slot->latch;
2479-
2480+ for (i = 0; i < arr->n_elems; i++) {
2481+ const sync_level_t* slot;
2482+
2483+ slot = &arr->elems[i];
2484+
2485+ if (slot->latch != NULL && slot->level <= limit) {
2486+ if (warn) {
2487 fprintf(stderr,
2488 "InnoDB: sync levels should be"
2489 " > %lu but a level is %lu\n",
2490 (ulong) limit, (ulong) slot->level);
2491-
2492- if (mutex->magic_n == MUTEX_MAGIC_N) {
2493- fprintf(stderr,
2494- "Mutex created at %s %lu\n",
2495- mutex->cfile_name,
2496- (ulong) mutex->cline);
2497-
2498- if (mutex_get_lock_word(mutex) != 0) {
2499- const char* file_name;
2500- ulint line;
2501- os_thread_id_t thread_id;
2502-
2503- mutex_get_debug_info(
2504- mutex, &file_name,
2505- &line, &thread_id);
2506-
2507- fprintf(stderr,
2508- "InnoDB: Locked mutex:"
2509- " addr %p thread %ld"
2510- " file %s line %ld\n",
2511- (void*) mutex,
2512- os_thread_pf(
2513- thread_id),
2514- file_name,
2515- (ulong) line);
2516- } else {
2517- fputs("Not locked\n", stderr);
2518- }
2519- } else {
2520- rw_lock_print(lock);
2521- }
2522-
2523- return(FALSE);
2524+ sync_print_warning(slot);
2525 }
2526+
2527+ return(FALSE);
2528+
2529 }
2530 }
2531
2532@@ -942,31 +935,28 @@
2533
2534 /******************************************************************//**
2535 Checks if the level value is stored in the level array.
2536-@return TRUE if stored */
2537+@return slot if found or NULL */
2538 static
2539-ibool
2540+const sync_level_t*
2541 sync_thread_levels_contain(
2542 /*=======================*/
2543- sync_priority_t* arr, /*!< in: pointer to level array for an OS
2544+ sync_arr_t* arr, /*!< in: pointer to level array for an OS
2545 thread */
2546 ulint level) /*!< in: level */
2547 {
2548- sync_priority_t* slot;
2549 ulint i;
2550
2551- for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
2552-
2553- slot = sync_thread_levels_get_nth(arr, i);
2554-
2555- if (slot->latch != NULL) {
2556- if (slot->level == level) {
2557-
2558- return(TRUE);
2559- }
2560+ for (i = 0; i < arr->n_elems; i++) {
2561+ const sync_level_t* slot;
2562+
2563+ slot = &arr->elems[i];
2564+
2565+ if (slot->latch != NULL && slot->level == level) {
2566+ return(slot);
2567 }
2568 }
2569
2570- return(FALSE);
2571+ return(NULL);
2572 }
2573
2574 /******************************************************************//**
2575@@ -980,10 +970,9 @@
2576 ulint level) /*!< in: latching order level
2577 (SYNC_DICT, ...)*/
2578 {
2579- sync_priority_t* arr;
2580+ ulint i;
2581+ sync_arr_t* arr;
2582 sync_thread_t* thread_slot;
2583- sync_priority_t* slot;
2584- ulint i;
2585
2586 if (!sync_order_checks_on) {
2587
2588@@ -1003,9 +992,10 @@
2589
2590 arr = thread_slot->levels;
2591
2592- for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
2593+ for (i = 0; i < arr->n_elems; i++) {
2594+ sync_level_t* slot;
2595
2596- slot = sync_thread_levels_get_nth(arr, i);
2597+ slot = &arr->elems[i];
2598
2599 if (slot->latch != NULL && slot->level == level) {
2600
2601@@ -1031,10 +1021,9 @@
2602 also purge_is_running mutex is
2603 allowed */
2604 {
2605- sync_priority_t* arr;
2606+ ulint i;
2607+ sync_arr_t* arr;
2608 sync_thread_t* thread_slot;
2609- sync_priority_t* slot;
2610- ulint i;
2611
2612 if (!sync_order_checks_on) {
2613
2614@@ -1054,9 +1043,10 @@
2615
2616 arr = thread_slot->levels;
2617
2618- for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
2619+ for (i = 0; i < arr->n_elems; ++i) {
2620+ const sync_level_t* slot;
2621
2622- slot = sync_thread_levels_get_nth(arr, i);
2623+ slot = &arr->elems[i];
2624
2625 if (slot->latch != NULL
2626 && (!dict_mutex_allowed
2627@@ -1098,10 +1088,10 @@
2628 ulint level) /*!< in: level in the latching order; if
2629 SYNC_LEVEL_VARYING, nothing is done */
2630 {
2631- sync_priority_t* array;
2632- sync_priority_t* slot;
2633+ ulint i;
2634+ sync_level_t* slot;
2635+ sync_arr_t* array;
2636 sync_thread_t* thread_slot;
2637- ulint i;
2638
2639 if (!sync_order_checks_on) {
2640
2641@@ -1126,20 +1116,22 @@
2642 thread_slot = sync_thread_level_arrays_find_slot();
2643
2644 if (thread_slot == NULL) {
2645+ ulint sz;
2646+
2647+ sz = sizeof(*array)
2648+ + (sizeof(*array->elems) * SYNC_THREAD_N_LEVELS);
2649+
2650 /* We have to allocate the level array for a new thread */
2651- array = ut_malloc(sizeof(sync_priority_t) * SYNC_THREAD_N_LEVELS);
2652+ array = calloc(sz, sizeof(char));
2653+ ut_a(array != NULL);
2654+
2655+ array->next_free = ULINT_UNDEFINED;
2656+ array->max_elems = SYNC_THREAD_N_LEVELS;
2657+ array->elems = (sync_level_t*) &array[1];
2658
2659 thread_slot = sync_thread_level_arrays_find_free();
2660-
2661+ thread_slot->levels = array;
2662 thread_slot->id = os_thread_get_curr_id();
2663- thread_slot->levels = array;
2664-
2665- for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
2666-
2667- slot = sync_thread_levels_get_nth(array, i);
2668-
2669- slot->latch = NULL;
2670- }
2671 }
2672
2673 array = thread_slot->levels;
2674@@ -1303,19 +1295,26 @@
2675 ut_error;
2676 }
2677
2678- for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
2679-
2680- slot = sync_thread_levels_get_nth(array, i);
2681-
2682- if (slot->latch == NULL) {
2683- slot->latch = latch;
2684- slot->level = level;
2685-
2686- break;
2687- }
2688+ if (array->next_free == ULINT_UNDEFINED) {
2689+ ut_a(array->n_elems < array->max_elems);
2690+
2691+ i = array->n_elems++;
2692+ } else {
2693+ i = array->next_free;
2694+ array->next_free = array->elems[i].level;
2695 }
2696
2697- ut_a(i < SYNC_THREAD_N_LEVELS);
2698+ ut_a(i < array->n_elems);
2699+ ut_a(i != ULINT_UNDEFINED);
2700+
2701+ ++array->in_use;
2702+
2703+ slot = &array->elems[i];
2704+
2705+ ut_a(slot->latch == NULL);
2706+
2707+ slot->latch = latch;
2708+ slot->level = level;
2709
2710 mutex_exit(&sync_thread_mutex);
2711 }
2712@@ -1331,8 +1330,7 @@
2713 /*====================*/
2714 void* latch) /*!< in: pointer to a mutex or an rw-lock */
2715 {
2716- sync_priority_t* array;
2717- sync_priority_t* slot;
2718+ sync_arr_t* array;
2719 sync_thread_t* thread_slot;
2720 ulint i;
2721
2722@@ -1363,17 +1361,37 @@
2723
2724 array = thread_slot->levels;
2725
2726- for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) {
2727-
2728- slot = sync_thread_levels_get_nth(array, i);
2729-
2730- if (slot->latch == latch) {
2731- slot->latch = NULL;
2732-
2733- mutex_exit(&sync_thread_mutex);
2734-
2735- return(TRUE);
2736- }
2737+ for (i = 0; i < array->n_elems; i++) {
2738+ sync_level_t* slot;
2739+
2740+ slot = &array->elems[i];
2741+
2742+ if (slot->latch != latch) {
2743+ continue;
2744+ }
2745+
2746+ slot->latch = NULL;
2747+
2748+ /* Update the free slot list. See comment in sync_level_t
2749+ for the level field. */
2750+ slot->level = array->next_free;
2751+ array->next_free = i;
2752+
2753+ ut_a(array->in_use >= 1);
2754+ --array->in_use;
2755+
2756+ /* If all cells are idle then reset the free
2757+ list. The assumption is that this will save
2758+ time when we need to scan up to n_elems. */
2759+
2760+ if (array->in_use == 0) {
2761+ array->n_elems = 0;
2762+ array->next_free = ULINT_UNDEFINED;
2763+ }
2764+
2765+ mutex_exit(&sync_thread_mutex);
2766+
2767+ return(TRUE);
2768 }
2769
2770 if (((mutex_t*) latch)->magic_n != MUTEX_MAGIC_N) {
2771@@ -1403,11 +1421,6 @@
2772 sync_init(void)
2773 /*===========*/
2774 {
2775-#ifdef UNIV_SYNC_DEBUG
2776- sync_thread_t* thread_slot;
2777- ulint i;
2778-#endif /* UNIV_SYNC_DEBUG */
2779-
2780 ut_a(sync_initialized == FALSE);
2781
2782 sync_initialized = TRUE;
2783@@ -1421,13 +1434,10 @@
2784 /* Create the thread latch level array where the latch levels
2785 are stored for each OS thread */
2786
2787- sync_thread_level_arrays = ut_malloc(OS_THREAD_MAX_N
2788- * sizeof(sync_thread_t));
2789- for (i = 0; i < OS_THREAD_MAX_N; i++) {
2790+ sync_thread_level_arrays = calloc(
2791+ sizeof(sync_thread_t), OS_THREAD_MAX_N);
2792+ ut_a(sync_thread_level_arrays != NULL);
2793
2794- thread_slot = sync_thread_level_arrays_get_nth(i);
2795- thread_slot->levels = NULL;
2796- }
2797 #endif /* UNIV_SYNC_DEBUG */
2798 /* Init the mutex list and create the mutex to protect it. */
2799
2800@@ -1454,6 +1464,34 @@
2801 #endif /* UNIV_SYNC_DEBUG */
2802 }
2803
2804+#ifdef UNIV_SYNC_DEBUG
2805+/******************************************************************//**
2806+Frees all debug memory. */
2807+static
2808+void
2809+sync_thread_level_arrays_free(void)
2810+/*===============================*/
2811+
2812+{
2813+ ulint i;
2814+
2815+ for (i = 0; i < OS_THREAD_MAX_N; i++) {
2816+ sync_thread_t* slot;
2817+
2818+ slot = &sync_thread_level_arrays[i];
2819+
2820+ /* If this slot was allocated then free the slot memory too. */
2821+ if (slot->levels != NULL) {
2822+ free(slot->levels);
2823+ slot->levels = NULL;
2824+ }
2825+ }
2826+
2827+ free(sync_thread_level_arrays);
2828+ sync_thread_level_arrays = NULL;
2829+}
2830+#endif /* UNIV_SYNC_DEBUG */
2831+
2832 /******************************************************************//**
2833 Frees the resources in InnoDB's own synchronization data structures. Use
2834 os_sync_free() after calling this. */
2835@@ -1466,17 +1504,20 @@
2836
2837 sync_array_free(sync_primary_wait_array);
2838
2839- mutex = UT_LIST_GET_FIRST(mutex_list);
2840+ for (mutex = UT_LIST_GET_FIRST(mutex_list);
2841+ mutex != NULL;
2842+ /* No op */) {
2843
2844- while (mutex) {
2845 #ifdef UNIV_MEM_DEBUG
2846 if (mutex == &mem_hash_mutex) {
2847 mutex = UT_LIST_GET_NEXT(list, mutex);
2848 continue;
2849 }
2850 #endif /* UNIV_MEM_DEBUG */
2851+
2852 mutex_free(mutex);
2853- mutex = UT_LIST_GET_FIRST(mutex_list);
2854+
2855+ mutex = UT_LIST_GET_FIRST(mutex_list);
2856 }
2857
2858 mutex_free(&mutex_list_mutex);
2859@@ -1485,6 +1526,8 @@
2860
2861 /* Switch latching order checks on in sync0sync.c */
2862 sync_order_checks_on = FALSE;
2863+
2864+ sync_thread_level_arrays_free();
2865 #endif /* UNIV_SYNC_DEBUG */
2866
2867 sync_initialized = FALSE;
2868
2869=== modified file 'plugin/innobase/trx/trx0roll.cc'
2870--- plugin/innobase/trx/trx0roll.cc 2010-12-27 18:39:11 +0000
2871+++ plugin/innobase/trx/trx0roll.cc 2012-05-23 00:15:24 +0000
2872@@ -47,8 +47,8 @@
2873 rollback */
2874 #define TRX_ROLL_TRUNC_THRESHOLD 1
2875
2876-/** In crash recovery, the current trx to be rolled back */
2877-static trx_t* trx_roll_crash_recv_trx = NULL;
2878+/** In crash recovery, the current trx to be rolled back; NULL otherwise */
2879+static const trx_t* trx_roll_crash_recv_trx = NULL;
2880
2881 /** In crash recovery we set this to the undo n:o of the current trx to be
2882 rolled back. Then we can print how many % the rollback has progressed. */
2883
2884=== modified file 'plugin/innobase/trx/trx0trx.cc'
2885--- plugin/innobase/trx/trx0trx.cc 2011-02-07 03:54:06 +0000
2886+++ plugin/innobase/trx/trx0trx.cc 2012-05-23 00:15:24 +0000
2887@@ -1994,18 +1994,18 @@
2888 /*******************************************************************//**
2889 This function is used to find one X/Open XA distributed transaction
2890 which is in the prepared state
2891-@return trx or NULL */
2892+@return trx or NULL; on match, the trx->xid will be invalidated */
2893 UNIV_INTERN
2894 trx_t*
2895 trx_get_trx_by_xid(
2896 /*===============*/
2897- XID* xid) /*!< in: X/Open XA transaction identification */
2898+ const XID* xid) /*!< in: X/Open XA transaction identifier */
2899 {
2900 trx_t* trx;
2901
2902 if (xid == NULL) {
2903
2904- return (NULL);
2905+ return(NULL);
2906 }
2907
2908 mutex_enter(&kernel_mutex);
2909@@ -2018,10 +2018,16 @@
2910 of gtrid_length+bqual_length bytes should be
2911 the same */
2912
2913- if (xid->gtrid_length == trx->xid.gtrid_length
2914+ if (trx->conc_state == TRX_PREPARED
2915+ && xid->gtrid_length == trx->xid.gtrid_length
2916 && xid->bqual_length == trx->xid.bqual_length
2917 && memcmp(xid->data, trx->xid.data,
2918 xid->gtrid_length + xid->bqual_length) == 0) {
2919+
2920+ /* Invalidate the XID, so that subsequent calls
2921+ will not find it. */
2922+ memset(&trx->xid, 0, sizeof(trx->xid));
2923+ trx->xid.formatID = -1;
2924 break;
2925 }
2926
2927@@ -2030,14 +2036,5 @@
2928
2929 mutex_exit(&kernel_mutex);
2930
2931- if (trx) {
2932- if (trx->conc_state != TRX_PREPARED) {
2933-
2934- return(NULL);
2935- }
2936-
2937- return(trx);
2938- } else {
2939- return(NULL);
2940- }
2941+ return(trx);
2942 }

Subscribers

People subscribed via source and target branches

to all changes: