1
1
/*****************************************************************************
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
3
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
4
4
Copyright (c) 2008, Google Inc.
6
6
Portions of this file contain modifications contributed and copyrighted by
46
46
/** Flag: has the search system been enabled?
47
Protected by btr_search_latch and btr_search_enabled_mutex. */
47
Protected by btr_search_latch. */
48
48
UNIV_INTERN char btr_search_enabled = TRUE;
49
UNIV_INTERN ibool btr_search_fully_disabled = FALSE;
51
/** Mutex protecting btr_search_enabled */
52
static mutex_t btr_search_enabled_mutex;
54
50
/** A dummy variable to fool the compiler */
55
51
UNIV_INTERN ulint btr_search_this_is_zero = 0;
141
137
be enough free space in the hash table. */
143
139
if (heap->free_block == NULL) {
144
buf_block_t* block = buf_block_alloc(0);
140
buf_block_t* block = buf_block_alloc();
146
142
rw_lock_x_lock(&btr_search_latch);
169
165
btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t));
171
167
rw_lock_create(&btr_search_latch, SYNC_SEARCH_SYS);
172
mutex_create(&btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF);
174
169
btr_search_sys = mem_alloc(sizeof(btr_search_sys_t));
199
194
btr_search_disable(void)
200
195
/*====================*/
202
mutex_enter(&btr_search_enabled_mutex);
199
mutex_enter(&dict_sys->mutex);
203
200
rw_lock_x_lock(&btr_search_latch);
205
/* Disable access to hash index, also tell ha_insert_for_fold()
206
stop adding new nodes to hash index, but still allow updating
208
202
btr_search_enabled = FALSE;
210
/* Clear all block->is_hashed flags and remove all entries
211
from btr_search_sys->hash_index. */
212
buf_pool_drop_hash_index();
214
/* hash index has been cleaned up, disallow any operation to
216
btr_search_fully_disabled = TRUE;
218
/* btr_search_enabled_mutex should guarantee this. */
219
ut_ad(!btr_search_enabled);
204
/* Clear the index->search_info->ref_count of every index in
205
the data dictionary cache. */
206
for (table = UT_LIST_GET_FIRST(dict_sys->table_LRU); table;
207
table = UT_LIST_GET_NEXT(table_LRU, table)) {
211
for (index = dict_table_get_first_index(table); index;
212
index = dict_table_get_next_index(index)) {
214
index->search_info->ref_count = 0;
218
mutex_exit(&dict_sys->mutex);
220
/* Set all block->index = NULL. */
221
buf_pool_clear_hash_index();
223
/* Clear the adaptive hash index. */
224
hash_table_clear(btr_search_sys->hash_index);
225
mem_heap_empty(btr_search_sys->hash_index->heap);
221
227
rw_lock_x_unlock(&btr_search_latch);
222
mutex_exit(&btr_search_enabled_mutex);
225
230
/********************************************************************//**
229
234
btr_search_enable(void)
230
235
/*====================*/
232
mutex_enter(&btr_search_enabled_mutex);
233
237
rw_lock_x_lock(&btr_search_latch);
235
239
btr_search_enabled = TRUE;
236
btr_search_fully_disabled = FALSE;
238
241
rw_lock_x_unlock(&btr_search_latch);
239
mutex_exit(&btr_search_enabled_mutex);
242
244
/*****************************************************************//**
459
461
&& (block->n_bytes == info->n_bytes)
460
462
&& (block->left_side == info->left_side)) {
462
if ((block->is_hashed)
463
465
&& (block->curr_n_fields == info->n_fields)
464
466
&& (block->curr_n_bytes == info->n_bytes)
465
467
&& (block->curr_left_side == info->left_side)) {
533
535
ut_ad(page_align(btr_cur_get_rec(cursor))
534
536
== buf_block_get_frame(block));
536
if (!block->is_hashed) {
538
index = block->index;
541
ut_a(block->index == cursor->index);
542
ut_a(!dict_index_is_ibuf(cursor->index));
545
ut_a(index == cursor->index);
546
ut_a(!dict_index_is_ibuf(index));
544
548
if ((info->n_hash_potential > 0)
545
549
&& (block->curr_n_fields == info->n_fields)
559
index_id = cursor->index->id;
560
563
fold = rec_fold(rec,
561
rec_get_offsets(rec, cursor->index, offsets_,
564
rec_get_offsets(rec, index, offsets_,
562
565
ULINT_UNDEFINED, &heap),
563
566
block->curr_n_fields,
564
block->curr_n_bytes, index_id);
567
block->curr_n_bytes, index->id);
565
568
if (UNIV_LIKELY_NULL(heap)) {
566
569
mem_heap_free(heap);
910
914
ut_ad(page_rec_is_user_rec(rec));
912
btr_cur_position(index, rec, block, cursor);
916
btr_cur_position(index, (rec_t*) rec, block, cursor);
914
918
/* Check the validity of the guess within the page */
1042
1046
rw_lock_s_lock(&btr_search_latch);
1043
page = block->frame;
1047
index = block->index;
1045
if (UNIV_LIKELY(!block->is_hashed)) {
1049
if (UNIV_LIKELY(!index)) {
1047
1051
rw_lock_s_unlock(&btr_search_latch);
1056
ut_a(!dict_index_is_ibuf(index));
1052
1057
table = btr_search_sys->hash_index;
1054
1059
#ifdef UNIV_SYNC_DEBUG
1060
1065
n_fields = block->curr_n_fields;
1061
1066
n_bytes = block->curr_n_bytes;
1062
index = block->index;
1063
ut_a(!dict_index_is_ibuf(index));
1065
1068
/* NOTE: The fields of block must not be accessed after
1066
1069
releasing btr_search_latch, as the index page might only
1146
1150
ut_a(index->search_info->ref_count > 0);
1147
1151
index->search_info->ref_count--;
1149
block->is_hashed = FALSE;
1150
1153
block->index = NULL;
1153
1156
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
1154
1157
if (UNIV_UNLIKELY(block->n_pointers)) {
1176
1179
/********************************************************************//**
1177
Drops a page hash index when a page is freed from a fseg to the file system.
1178
Drops possible hash index if the page happens to be in the buffer pool. */
1180
Drops a possible page hash index when a page is evicted from the buffer pool
1181
or freed in a file segment. */
1181
1184
btr_search_drop_page_hash_when_freed(
1188
1191
buf_block_t* block;
1191
if (!buf_page_peek_if_search_hashed(space, page_no)) {
1196
1194
mtr_start(&mtr);
1198
/* We assume that if the caller has a latch on the page, then the
1199
caller has already dropped the hash index for the page, and we never
1200
get here. Therefore we can acquire the s-latch to the page without
1201
having to fear a deadlock. */
1203
block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH, NULL,
1204
BUF_GET_IF_IN_POOL, __FILE__, __LINE__,
1206
/* Because the buffer pool mutex was released by
1207
buf_page_peek_if_search_hashed(), it is possible that the
1208
block was removed from the buffer pool by another thread
1209
before buf_page_get_gen() got a chance to acquire the buffer
1210
pool mutex again. Thus, we must check for a NULL return. */
1212
if (UNIV_LIKELY(block != NULL)) {
1196
/* If the caller has a latch on the page, then the caller must
1197
have a x-latch on the page and it must have already dropped
1198
the hash index for the page. Because of the x-latch that we
1199
are possibly holding, we cannot s-latch the page, but must
1200
(recursively) x-latch it, even though we are only reading. */
1202
block = buf_page_get_gen(space, zip_size, page_no, RW_X_LATCH, NULL,
1203
BUF_PEEK_IF_IN_POOL, __FILE__, __LINE__,
1206
if (block && block->index) {
1214
1208
buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
1256
1249
ut_a(!dict_index_is_ibuf(index));
1251
#ifdef UNIV_SYNC_DEBUG
1252
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1253
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
1254
|| rw_lock_own(&(block->lock), RW_LOCK_EX));
1255
#endif /* UNIV_SYNC_DEBUG */
1257
rw_lock_s_lock(&btr_search_latch);
1259
if (!btr_search_enabled) {
1260
rw_lock_s_unlock(&btr_search_latch);
1258
1264
table = btr_search_sys->hash_index;
1259
1265
page = buf_block_get_frame(block);
1261
#ifdef UNIV_SYNC_DEBUG
1262
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
1263
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
1264
|| rw_lock_own(&(block->lock), RW_LOCK_EX));
1265
#endif /* UNIV_SYNC_DEBUG */
1267
rw_lock_s_lock(&btr_search_latch);
1269
if (block->is_hashed && ((block->curr_n_fields != n_fields)
1270
|| (block->curr_n_bytes != n_bytes)
1271
|| (block->curr_left_side != left_side))) {
1267
if (block->index && ((block->curr_n_fields != n_fields)
1268
|| (block->curr_n_bytes != n_bytes)
1269
|| (block->curr_left_side != left_side))) {
1273
1271
rw_lock_s_unlock(&btr_search_latch);
1323
fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id);
1321
fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id);
1325
1323
if (left_side) {
1347
1345
offsets = rec_get_offsets(next_rec, index, offsets,
1348
1346
n_fields + (n_bytes > 0), &heap);
1349
1347
next_fold = rec_fold(next_rec, offsets, n_fields,
1348
n_bytes, index->id);
1352
1350
if (fold != next_fold) {
1353
1351
/* Insert an entry into the hash index */
1373
1371
rw_lock_x_lock(&btr_search_latch);
1375
if (UNIV_UNLIKELY(btr_search_fully_disabled)) {
1373
if (UNIV_UNLIKELY(!btr_search_enabled)) {
1376
1374
goto exit_func;
1379
if (block->is_hashed && ((block->curr_n_fields != n_fields)
1380
|| (block->curr_n_bytes != n_bytes)
1381
|| (block->curr_left_side != left_side))) {
1377
if (block->index && ((block->curr_n_fields != n_fields)
1378
|| (block->curr_n_bytes != n_bytes)
1379
|| (block->curr_left_side != left_side))) {
1382
1380
goto exit_func;
1387
1385
rebuild hash index for a page that is already hashed, we
1388
1386
have to take care not to increment the counter in that
1390
if (!block->is_hashed) {
1388
if (!block->index) {
1391
1389
index->search_info->ref_count++;
1394
block->is_hashed = TRUE;
1395
1392
block->n_hash_helps = 0;
1397
1394
block->curr_n_fields = n_fields;
1439
1436
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
1440
1437
ut_ad(rw_lock_own(&(new_block->lock), RW_LOCK_EX));
1441
1438
#endif /* UNIV_SYNC_DEBUG */
1442
ut_a(!new_block->is_hashed || new_block->index == index);
1443
ut_a(!block->is_hashed || block->index == index);
1444
ut_a(!(new_block->is_hashed || block->is_hashed)
1440
rw_lock_s_lock(&btr_search_latch);
1442
ut_a(!new_block->index || new_block->index == index);
1443
ut_a(!block->index || block->index == index);
1444
ut_a(!(new_block->index || block->index)
1445
1445
|| !dict_index_is_ibuf(index));
1447
rw_lock_s_lock(&btr_search_latch);
1449
if (new_block->is_hashed) {
1447
if (new_block->index) {
1451
1449
rw_lock_s_unlock(&btr_search_latch);
1493
1491
hash_table_t* table;
1494
1492
buf_block_t* block;
1495
dict_index_t* index;
1498
1496
ulint offsets_[REC_OFFS_NORMAL_SIZE];
1499
1497
mem_heap_t* heap = NULL;
1500
1498
rec_offs_init(offsets_);
1502
rec = btr_cur_get_rec(cursor);
1504
1500
block = btr_cur_get_block(cursor);
1506
1502
#ifdef UNIV_SYNC_DEBUG
1507
1503
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
1508
1504
#endif /* UNIV_SYNC_DEBUG */
1510
if (!block->is_hashed) {
1506
index = block->index;
1515
ut_a(block->index == cursor->index);
1513
ut_a(index == cursor->index);
1516
1514
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
1517
ut_a(!dict_index_is_ibuf(cursor->index));
1515
ut_a(!dict_index_is_ibuf(index));
1519
1517
table = btr_search_sys->hash_index;
1521
index_id = cursor->index->id;
1522
fold = rec_fold(rec, rec_get_offsets(rec, cursor->index, offsets_,
1519
rec = btr_cur_get_rec(cursor);
1521
fold = rec_fold(rec, rec_get_offsets(rec, index, offsets_,
1523
1522
ULINT_UNDEFINED, &heap),
1524
block->curr_n_fields, block->curr_n_bytes, index_id);
1523
block->curr_n_fields, block->curr_n_bytes, index->id);
1525
1524
if (UNIV_LIKELY_NULL(heap)) {
1526
1525
mem_heap_free(heap);
1528
1528
rw_lock_x_lock(&btr_search_latch);
1530
ha_search_and_delete_if_found(table, fold, rec);
1531
ut_a(block->index == index);
1533
ha_search_and_delete_if_found(table, fold, rec);
1532
1536
rw_lock_x_unlock(&btr_search_latch);
1555
1560
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
1556
1561
#endif /* UNIV_SYNC_DEBUG */
1558
if (!block->is_hashed) {
1563
index = block->index;
1563
ut_a(block->index == cursor->index);
1564
ut_a(!dict_index_is_ibuf(cursor->index));
1570
ut_a(cursor->index == index);
1571
ut_a(!dict_index_is_ibuf(index));
1566
1573
rw_lock_x_lock(&btr_search_latch);
1575
if (!block->index) {
1580
ut_a(block->index == index);
1568
1582
if ((cursor->flag == BTR_CUR_HASH)
1569
1583
&& (cursor->n_fields == block->curr_n_fields)
1570
1584
&& (cursor->n_bytes == block->curr_n_bytes)
1575
1589
ha_search_and_update_if_found(table, cursor->fold, rec,
1576
1590
block, page_rec_get_next(rec));
1578
1593
rw_lock_x_unlock(&btr_search_latch);
1580
1595
rw_lock_x_unlock(&btr_search_latch);
1624
1639
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
1625
1640
#endif /* UNIV_SYNC_DEBUG */
1627
if (!block->is_hashed) {
1642
index = block->index;
1632
ut_a(block->index == cursor->index);
1633
ut_a(!dict_index_is_ibuf(cursor->index));
1635
index_id = cursor->index->id;
1649
ut_a(index == cursor->index);
1650
ut_a(!dict_index_is_ibuf(index));
1637
1652
n_fields = block->curr_n_fields;
1638
1653
n_bytes = block->curr_n_bytes;
1641
1656
ins_rec = page_rec_get_next(rec);
1642
1657
next_rec = page_rec_get_next(ins_rec);
1644
offsets = rec_get_offsets(ins_rec, cursor->index, offsets,
1659
offsets = rec_get_offsets(ins_rec, index, offsets,
1645
1660
ULINT_UNDEFINED, &heap);
1646
ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index_id);
1661
ins_fold = rec_fold(ins_rec, offsets, n_fields, n_bytes, index->id);
1648
1663
if (!page_rec_is_supremum(next_rec)) {
1649
offsets = rec_get_offsets(next_rec, cursor->index, offsets,
1664
offsets = rec_get_offsets(next_rec, index, offsets,
1650
1665
n_fields + (n_bytes > 0), &heap);
1651
1666
next_fold = rec_fold(next_rec, offsets, n_fields,
1667
n_bytes, index->id);
1655
1670
if (!page_rec_is_infimum(rec)) {
1656
offsets = rec_get_offsets(rec, cursor->index, offsets,
1671
offsets = rec_get_offsets(rec, index, offsets,
1657
1672
n_fields + (n_bytes > 0), &heap);
1658
fold = rec_fold(rec, offsets, n_fields, n_bytes, index_id);
1673
fold = rec_fold(rec, offsets, n_fields, n_bytes, index->id);
1660
1675
if (left_side) {
1694
1717
rw_lock_x_lock(&btr_search_latch);
1721
if (!btr_search_enabled) {
1699
1726
ha_insert_for_fold(table, ins_fold, block, ins_rec);
1716
1747
ha_insert_for_fold(table, ins_fold, block, ins_rec);
1718
1749
fputs("Hash insert for ", stderr);
1719
dict_index_name_print(stderr, cursor->index);
1750
dict_index_name_print(stderr, index);
1720
1751
fprintf(stderr, " fold %lu\n", ins_fold);
1820
1851
+ (block->curr_n_bytes > 0),
1823
if (!block->is_hashed || node->fold
1854
if (!block->index || node->fold
1824
1855
!= rec_fold((rec_t*)(node->data),
1826
1857
block->curr_n_fields,
1855
1886
rec_print_new(stderr, (rec_t*)node->data,
1857
1888
fprintf(stderr, "\nInnoDB: on that page."
1858
" Page mem address %p, is hashed %lu,"
1889
" Page mem address %p, is hashed %p,"
1859
1890
" n fields %lu, n bytes %lu\n"
1860
1891
"InnoDB: side %lu\n",
1861
(void*) page, (ulong) block->is_hashed,
1892
(void*) page, (void*) block->index,
1862
1893
(ulong) block->curr_n_fields,
1863
1894
(ulong) block->curr_n_bytes,
1864
1895
(ulong) block->curr_left_side);