1 /* 2 Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License, version 2.0, 6 as published by the Free Software Foundation. 7 8 This program is also distributed with certain software (including 9 but not limited to OpenSSL) that is licensed under separate terms, 10 as designated in a particular file or component or in included license 11 documentation. The authors of MySQL hereby grant you an additional 12 permission to link the program and your derivative works with the 13 separately licensed software that they have included with MySQL. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License, version 2.0, for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 */ 24 25 #ifndef __NDB_TUP_PAGE_HPP 26 #define __NDB_TUP_PAGE_HPP 27 28 #include <pc.hpp> 29 #include <ndb_types.h> 30 #include "../diskpage.hpp" 31 #include <Bitmask.hpp> 32 #include <portlib/ndb_prefetch.h> 33 #define JAM_FILE_ID 419 34 35 36 struct Tup_page 37 { Tup_pageTup_page38 Tup_page() {} 39 struct File_formats::Page_header m_page_header; 40 Uint32 m_restart_seq; 41 Uint32 page_state; 42 union { 43 Uint32 next_page; 44 Uint32 nextList; 45 }; 46 union { 47 Uint32 prev_page; 48 Uint32 prevList; 49 }; 50 Uint32 unused_cluster_page[3]; 51 Uint32 m_gci; 52 Uint32 frag_page_id; 53 Uint32 physical_page_id; 54 Uint32 free_space; 55 Uint32 next_free_index; 56 /** 57 * list_index used by disk pages and varsized pages. 58 * free space in page bits/list, 0x8000 means not in free 59 */ 60 Uint32 list_index; 61 Uint32 uncommitted_used_space; 62 Uint32 m_page_no; 63 Uint32 m_file_no; 64 Uint32 m_table_id; 65 Uint32 m_fragment_id; 66 Uint32 m_extent_no; 67 Uint32 m_extent_info_ptr; 68 Uint32 unused_high_index; // size of index + 1 69 Uint32 unused_insert_pos; 70 Uint32 m_flags; /* Currently only LCP_SKIP flag in bit 0 */ 71 Uint32 m_ndb_version; 72 Uint32 m_create_table_version; 73 Uint32 m_change_map[4]; 74 75 STATIC_CONST( HEADER_WORDS = 32 ); 76 STATIC_CONST( DATA_WORDS = File_formats::NDB_PAGE_SIZE_WORDS - 77 HEADER_WORDS ); 78 79 Uint32 m_data[DATA_WORDS]; 80 81 STATIC_CONST ( LCP_SKIP_FLAG = 1 ); 82 is_page_to_skip_lcpTup_page83 bool is_page_to_skip_lcp() const 84 { 85 if (m_flags & LCP_SKIP_FLAG) 86 { 87 return true; 88 } 89 return false; 90 } set_page_to_skip_lcpTup_page91 void set_page_to_skip_lcp() 92 { 93 m_flags |= LCP_SKIP_FLAG; 94 } clear_page_to_skip_lcpTup_page95 void clear_page_to_skip_lcp() 96 { 97 m_flags &= (~LCP_SKIP_FLAG); 98 } 99 }; 100 101 struct Tup_fixsize_page 102 { 103 struct File_formats::Page_header m_page_header; 104 Uint32 m_restart_seq; 105 Uint32 page_state; 106 union { 107 Uint32 next_page; 108 Uint32 nextList; 109 }; 110 union { 111 Uint32 prev_page; 112 Uint32 prevList; 113 }; 114 Uint32 unused_cluster_page[3]; 115 Uint32 m_gci; 116 Uint32 frag_page_id; 117 Uint32 physical_page_id; 118 Uint32 free_space; 119 Uint32 next_free_index; 120 Uint32 list_index; 121 Uint32 uncommitted_used_space; 122 Uint32 m_page_no; 123 Uint32 m_file_no; 124 Uint32 m_table_id; 125 Uint32 m_fragment_id; 126 Uint32 m_extent_no; 127 Uint32 m_extent_info_ptr; 128 Uint32 unused_high_index; // size of index + 1 129 Uint32 unused_insert_pos; 130 /** 131 * Currently LCP_SKIP flag in bit 0 and 132 * change map bits in bits 24-31 (4 kB per bit) 133 */ 134 Uint32 m_flags; 135 Uint32 m_ndb_version; 136 Uint32 m_schema_version; 137 Uint32 m_change_map[4]; 138 139 /** 140 * Don't set/reset LCP_SKIP/LCP_DELETE flags 141 * The LCP_SKIP and LCP_DELETE flags are alive also after the record has 142 * been deleted. This is to track rows that have been scanned, LCP scans 143 * also scans deleted rows to ensure that any deleted rows since last LCP 144 * are tracked. 145 */ 146 STATIC_CONST( FREE_RECORD = 0xeeffffff ); 147 STATIC_CONST( HEADER_WORDS = 32 ); 148 STATIC_CONST( DATA_WORDS = File_formats::NDB_PAGE_SIZE_WORDS - 149 HEADER_WORDS ); 150 STATIC_CONST( FIRST_BIT_CHANGE_MAP = 24); 151 STATIC_CONST( PAGE_CHANGED_WHILE_LCP_SCAN_BIT = 23); 152 STATIC_CONST( PAGE_IS_BEING_LCP_SCANNED_BIT = 22); 153 154 Uint32 m_data[DATA_WORDS]; 155 get_ptrTup_fixsize_page156 Uint32* get_ptr(Uint32 page_idx, Uint32 rec_size) 157 { 158 require(page_idx + rec_size <= DATA_WORDS); 159 return m_data + page_idx; 160 } get_next_large_idxTup_fixsize_page161 Uint32 get_next_large_idx(Uint32 idx, Uint32 size) 162 { 163 /* First move idx to next 1024 word boundary */ 164 Uint32 new_idx = ((idx + 1024) / 1024) * 1024; 165 /* Next move idx forward to size word boundary */ 166 new_idx = ((new_idx + size - 1) / size) * size; 167 return new_idx; 168 } get_next_small_idxTup_fixsize_page169 Uint32 get_next_small_idx(Uint32 idx, Uint32 size) 170 { 171 /* First move idx to next 64 word boundary */ 172 Uint32 new_idx = ((idx + 64) / 64) * 64; 173 /* Next move idx forward to size word boundary */ 174 new_idx = ((new_idx + size - 1) / size) * size; 175 return new_idx; 176 } get_and_clear_change_while_lcp_scanTup_fixsize_page177 bool get_and_clear_change_while_lcp_scan() 178 { 179 Uint32 flags = m_flags; 180 Uint32 bit_pos = Tup_fixsize_page::PAGE_CHANGED_WHILE_LCP_SCAN_BIT; 181 Uint32 flags_bit = 1 << bit_pos; 182 bool bit_set = ((flags & flags_bit) != 0); 183 Uint32 flags_clear_val = ~flags_bit; 184 Uint32 flags_new_val = flags & flags_clear_val; 185 m_flags = flags_new_val; 186 return bit_set; 187 } set_change_while_lcp_scanTup_fixsize_page188 void set_change_while_lcp_scan() 189 { 190 Uint32 flags = m_flags; 191 Uint32 bit_pos = Tup_fixsize_page::PAGE_CHANGED_WHILE_LCP_SCAN_BIT; 192 Uint32 flags_bit = 1 << bit_pos; 193 Uint32 new_flags = flags | flags_bit; 194 m_flags = new_flags; 195 } get_page_being_lcp_scannedTup_fixsize_page196 bool get_page_being_lcp_scanned() 197 { 198 Uint32 flags = m_flags; 199 Uint32 bit_pos = Tup_fixsize_page::PAGE_IS_BEING_LCP_SCANNED_BIT; 200 Uint32 flags_bit = 1 << bit_pos; 201 bool bit_set = ((flags & flags_bit) != 0); 202 return bit_set; 203 } set_page_being_lcp_scannedTup_fixsize_page204 void set_page_being_lcp_scanned() 205 { 206 Uint32 flags = m_flags; 207 Uint32 bit_pos = Tup_fixsize_page::PAGE_IS_BEING_LCP_SCANNED_BIT; 208 Uint32 flags_bit = 1 << bit_pos; 209 Uint32 new_flags = flags | flags_bit; 210 m_flags = new_flags; 211 } clear_page_being_lcp_scannedTup_fixsize_page212 void clear_page_being_lcp_scanned() 213 { 214 Uint32 flags = m_flags; 215 Uint32 bit_pos = Tup_fixsize_page::PAGE_IS_BEING_LCP_SCANNED_BIT; 216 Uint32 flags_bit = 1 << bit_pos; 217 Uint32 flags_clear_val = ~flags_bit; 218 Uint32 flags_new_val = flags & flags_clear_val; 219 m_flags = flags_new_val; 220 } prefetch_change_mapTup_fixsize_page221 void prefetch_change_map() 222 { 223 NDB_PREFETCH_WRITE(&frag_page_id); 224 NDB_PREFETCH_WRITE(&m_flags); 225 } clear_small_change_mapTup_fixsize_page226 void clear_small_change_map() 227 { 228 m_change_map[0] = 0; 229 m_change_map[1] = 0; 230 m_change_map[2] = 0; 231 m_change_map[3] = 0; 232 } clear_large_change_mapTup_fixsize_page233 void clear_large_change_map() 234 { 235 Uint32 map_val = m_flags; 236 map_val <<= 8; 237 map_val >>= 8; 238 m_flags = map_val; 239 } set_all_change_mapTup_fixsize_page240 void set_all_change_map() 241 { 242 m_change_map[0] = 0xFFFFFFFF; 243 m_change_map[1] = 0xFFFFFFFF; 244 m_change_map[2] = 0xFFFFFFFF; 245 m_change_map[3] = 0xFFFFFFFF; 246 Uint32 map_val = 0xFF; 247 map_val <<= Tup_fixsize_page::FIRST_BIT_CHANGE_MAP; 248 Uint32 flags = m_flags; 249 flags |= map_val; 250 m_flags = flags; 251 } verify_small_map_clearTup_fixsize_page252 void verify_small_map_clear(Uint32 bit_pos) 253 { 254 /** 255 * Verify that also small change map is zero when the large 256 * map is zero. 257 */ 258 Uint32 i = (bit_pos - Tup_fixsize_page::FIRST_BIT_CHANGE_MAP) / 2; 259 Uint32 small_bit_map = m_change_map[i]; 260 if ((bit_pos & 1) == 0) 261 { 262 small_bit_map &= 0xFFFF; 263 } 264 else 265 { 266 small_bit_map >>= 16; 267 } 268 require(small_bit_map == 0); 269 } verify_small_map_not_clearTup_fixsize_page270 void verify_small_map_not_clear(Uint32 bit_pos) 271 { 272 /** 273 * Verify that also small change map is not zero when the large 274 * map is not zero. 275 */ 276 Uint32 i = (bit_pos - Tup_fixsize_page::FIRST_BIT_CHANGE_MAP) / 2; 277 Uint32 small_bit_map = m_change_map[i]; 278 if ((bit_pos & 1) == 0) 279 { 280 small_bit_map &= 0xFFFF; 281 } 282 else 283 { 284 small_bit_map >>= 16; 285 } 286 require(small_bit_map != 0); 287 } set_change_mapsTup_fixsize_page288 void set_change_maps(Uint32 page_index) 289 { 290 if (unlikely(get_page_being_lcp_scanned())) 291 { 292 set_change_while_lcp_scan(); 293 return; 294 } 295 assert(page_index < Tup_fixsize_page::DATA_WORDS); 296 Uint32 *map_ptr = &m_change_map[0]; 297 /** 298 * Each bit maps a 64 word region, the starting word is 299 * used as the word to calculate the map index based on. 300 */ 301 Uint32 map_id = page_index / 64; 302 Uint32 idx = map_id / 32; 303 Uint32 bit_pos = map_id & 31; 304 assert(idx < 4); 305 Uint32 map_val = map_ptr[idx]; 306 Uint32 map_set_val = 1 << bit_pos; 307 map_val |= map_set_val; 308 map_ptr[idx] = map_val; 309 /** 310 * Also set the change map with only 8 bits, one bit per 311 * 4 kB. 312 */ 313 Uint32 large_map_idx = Tup_fixsize_page::FIRST_BIT_CHANGE_MAP + 314 (page_index >> 10); 315 assert(large_map_idx <= 31); 316 map_set_val = 1 << large_map_idx; 317 m_flags |= map_set_val; 318 verify_small_map_not_clear(large_map_idx); 319 } clear_large_change_mapTup_fixsize_page320 void clear_large_change_map(Uint32 page_index) 321 { 322 assert(page_index < Tup_fixsize_page::DATA_WORDS); 323 Uint32 map_val = m_flags; 324 Uint32 bit_pos = Tup_fixsize_page::FIRST_BIT_CHANGE_MAP + 325 (page_index >> 10); 326 assert(bit_pos <= 31); 327 Uint32 map_get_val = 1 << bit_pos; 328 Uint32 map_clear_val = ~map_get_val; 329 Uint32 map_new_val = map_val & map_clear_val; 330 m_flags = map_new_val; 331 verify_small_map_clear(bit_pos); 332 } get_large_change_mapTup_fixsize_page333 bool get_large_change_map(Uint32 page_index) 334 { 335 /** 336 * Get the large change map bit. 337 * If the bit is set, we will not reset it yet to ensure 338 * that the page bits are always in a consistent state. 339 * Instead we will reset it when the last small change 340 * map bit is reset. 341 */ 342 assert(page_index < Tup_fixsize_page::DATA_WORDS); 343 Uint32 map_val = m_flags; 344 Uint32 bit_pos = Tup_fixsize_page::FIRST_BIT_CHANGE_MAP + 345 (page_index >> 10); 346 assert(bit_pos <= 31); 347 Uint32 map_get_val = 1 << bit_pos; 348 bool bit_set = ((map_get_val & map_val) != 0); 349 if (!bit_set) 350 { 351 verify_small_map_clear(bit_pos); 352 } 353 else 354 { 355 verify_small_map_not_clear(bit_pos); 356 } 357 return bit_set; 358 } get_and_clear_change_mapsTup_fixsize_page359 bool get_and_clear_change_maps(Uint32 page_index) 360 { 361 assert(page_index < Tup_fixsize_page::DATA_WORDS); 362 Uint32 *map_ptr = &m_change_map[0]; 363 Uint32 map_id = page_index / 64; 364 Uint32 idx = map_id / 32; 365 assert(idx < 4); 366 Uint32 bit_pos = map_id & 31; 367 Uint32 map_val = map_ptr[idx]; 368 Uint32 map_get_val = 1 << bit_pos; 369 Uint32 map_clear_val = ~map_get_val; 370 Uint32 map_new_val = map_val & map_clear_val; 371 map_ptr[idx] = map_new_val; 372 373 /** 374 * Ensure that large map is cleared when we clear the 375 * last bit in the small change map corresponding to 376 * the large bit. 377 * 378 * Only necessary to perform this check when we actually 379 * changed a bit in the small map. 380 */ 381 bool any_change = ((map_get_val & map_val) != 0); 382 if (any_change) 383 { 384 Uint32 small_bit_map = map_new_val; 385 if (bit_pos < 16) 386 { 387 small_bit_map &= 0xFFFF; 388 } 389 else 390 { 391 small_bit_map >>= 16; 392 } 393 if (small_bit_map == 0) 394 { 395 clear_large_change_map(page_index); 396 } 397 } 398 return any_change; 399 } get_any_changesTup_fixsize_page400 bool get_any_changes() 401 { 402 Uint32 map_val = m_flags; 403 map_val >>= Tup_fixsize_page::FIRST_BIT_CHANGE_MAP; 404 #ifdef VM_TRACE 405 if (map_val == 0) 406 { 407 Uint32 sum_small_maps = 408 m_change_map[0] + m_change_map[1] + m_change_map[2] + m_change_map[3]; 409 assert(sum_small_maps == 0); 410 } 411 #endif 412 return (map_val != 0); 413 } verify_change_mapsTup_fixsize_page414 bool verify_change_maps(EmulatedJamBuffer *jamBuf) 415 { 416 for (Uint32 i = 0; i < 4; i++) 417 { 418 Uint32 small_map = m_change_map[i]; 419 Uint32 bit_pos = 2 * i + Tup_fixsize_page::FIRST_BIT_CHANGE_MAP; 420 Uint32 bit_val = m_flags & (1 << bit_pos); 421 if (bit_val != 0) 422 { 423 Uint32 small_bit_map = small_map & 0xFFFF; 424 if (small_bit_map == 0) 425 { 426 thrjamDebug(jamBuf); 427 thrjamLineDebug(jamBuf, (Uint16(i))); 428 return false; 429 } 430 } 431 else 432 { 433 Uint32 small_bit_map = small_map & 0xFFFF; 434 if (small_bit_map != 0) 435 { 436 thrjamDebug(jamBuf); 437 thrjamLineDebug(jamBuf, (Uint16(i))); 438 thrjamLineDebug(jamBuf, (Uint16(small_bit_map))); 439 return false; 440 } 441 } 442 bit_pos = 2 * i + Tup_fixsize_page::FIRST_BIT_CHANGE_MAP + 1; 443 bit_val = m_flags & (1 << bit_pos); 444 if (bit_val != 0) 445 { 446 Uint32 small_bit_map = small_map >> 16; 447 if (small_bit_map == 0) 448 { 449 thrjamDebug(jamBuf); 450 thrjamLineDebug(jamBuf, (Uint16(i))); 451 return false; 452 } 453 } 454 else 455 { 456 Uint32 small_bit_map = small_map >> 16; 457 if (small_bit_map != 0) 458 { 459 thrjamDebug(jamBuf); 460 thrjamLineDebug(jamBuf, (Uint16(i))); 461 thrjamLineDebug(jamBuf, (Uint16(small_bit_map))); 462 return false; 463 } 464 } 465 } 466 return true; 467 } get_num_changesTup_fixsize_page468 Uint32 get_num_changes() 469 { 470 Uint32 bit_count = 0; 471 Uint32 map_val; 472 map_val = m_change_map[0]; 473 bit_count += BitmaskImpl::count_bits(map_val); 474 map_val = m_change_map[1]; 475 bit_count += BitmaskImpl::count_bits(map_val); 476 map_val = m_change_map[2]; 477 bit_count += BitmaskImpl::count_bits(map_val); 478 map_val = m_change_map[3]; 479 bit_count += BitmaskImpl::count_bits(map_val); 480 return bit_count; 481 } clear_max_gciTup_fixsize_page482 void clear_max_gci() 483 { 484 m_gci = 0; 485 } get_max_gciTup_fixsize_page486 Uint32 get_max_gci() 487 { 488 return m_gci; 489 } set_max_gciTup_fixsize_page490 void set_max_gci(Uint32 gci) 491 { 492 if (gci > m_gci) 493 m_gci = gci; 494 } 495 496 /** 497 * Alloc record from page 498 * return page_idx 499 **/ Tup_fixsize_pageTup_fixsize_page500 Tup_fixsize_page() {} 501 Uint32 alloc_record(); 502 Uint32 alloc_record(Uint32 page_idx); 503 Uint32 free_record(Uint32 page_idx); 504 }; 505 506 struct Tup_varsize_page 507 { 508 struct File_formats::Page_header m_page_header; 509 Uint32 m_restart_seq; 510 Uint32 page_state; 511 union { 512 Uint32 next_page; 513 Uint32 nextList; 514 }; 515 union { 516 Uint32 prev_page; 517 Uint32 prevList; 518 }; 519 Uint32 unused_cluster_page[3]; 520 Uint32 m_gci; 521 Uint32 frag_page_id; 522 Uint32 physical_page_id; 523 Uint32 free_space; 524 Uint32 next_free_index; 525 Uint32 list_index; 526 Uint32 uncommitted_used_space; 527 Uint32 m_page_no; 528 Uint32 m_file_no; 529 Uint32 m_table_id; 530 Uint32 m_fragment_id; 531 Uint32 m_extent_no; 532 Uint32 m_extent_info_ptr; 533 Uint32 high_index; // size of index + 1 534 Uint32 insert_pos; 535 Uint32 m_flags; /* Currently only LCP_SKIP flag in bit 0 */ 536 Uint32 m_ndb_version; 537 Uint32 m_schema_version; 538 Uint32 m_change_map[4]; 539 540 STATIC_CONST( HEADER_WORDS = 32 ); 541 STATIC_CONST( DATA_WORDS = File_formats::NDB_PAGE_SIZE_WORDS - 542 HEADER_WORDS ); 543 STATIC_CONST( CHAIN = 0x80000000 ); 544 STATIC_CONST( FREE = 0x40000000 ); 545 STATIC_CONST( LEN_MASK = 0x3FFF8000 ); 546 STATIC_CONST( POS_MASK = 0x00007FFF ); 547 STATIC_CONST( LEN_SHIFT = 15 ); 548 STATIC_CONST( POS_SHIFT = 0 ); 549 STATIC_CONST( END_OF_FREE_LIST = POS_MASK ); 550 551 STATIC_CONST( NEXT_MASK = POS_MASK ); 552 STATIC_CONST( NEXT_SHIFT = POS_SHIFT ); 553 STATIC_CONST( PREV_MASK = LEN_MASK ); 554 STATIC_CONST( PREV_SHIFT = LEN_SHIFT ); 555 556 Uint32 m_data[DATA_WORDS]; 557 Tup_varsize_pageTup_varsize_page558 Tup_varsize_page() {} 559 void init(); 560 get_free_space_ptrTup_varsize_page561 Uint32* get_free_space_ptr() { 562 return m_data+insert_pos; 563 } 564 largest_frag_sizeTup_varsize_page565 Uint32 largest_frag_size() const { 566 return DATA_WORDS - (high_index + insert_pos); 567 } 568 get_index_ptrTup_varsize_page569 Uint32 *get_index_ptr(Uint32 page_idx) { 570 assert(page_idx < high_index); 571 return (m_data + (DATA_WORDS - page_idx)); 572 } 573 get_index_wordTup_varsize_page574 Uint32 get_index_word(Uint32 page_idx) const { 575 assert(page_idx < high_index); 576 return * (m_data + (DATA_WORDS - page_idx)); 577 } 578 579 /** 580 * Alloc record from page, return page_idx 581 * temp is used when having to reorg page before allocating 582 */ 583 Uint32 alloc_record(Uint32 size, Tup_varsize_page* temp, Uint32 chain); 584 585 /** 586 * Alloc page_idx from page, return page_idx 587 * temp is used when having to reorg page before allocating 588 */ 589 Uint32 alloc_record(Uint32 page_idx, Uint32 size, Tup_varsize_page* temp); 590 591 /** 592 * Free record from page 593 */ 594 Uint32 free_record(Uint32 page_idx, Uint32 chain); 595 596 void reorg(Tup_varsize_page* temp); 597 void rebuild_index(Uint32* ptr); 598 599 /** 600 * Check if one can grow tuple wo/ reorg 601 */ is_space_behind_entryTup_varsize_page602 bool is_space_behind_entry(Uint32 page_index, Uint32 growth_len) const { 603 Uint32 idx= get_index_word(page_index); 604 Uint32 pos= (idx & POS_MASK) >> POS_SHIFT; 605 Uint32 len= (idx & LEN_MASK) >> LEN_SHIFT; 606 if ((pos + len == insert_pos) && 607 (insert_pos + growth_len < DATA_WORDS - high_index)) 608 return true; 609 return false; 610 } 611 grow_entryTup_varsize_page612 void grow_entry(Uint32 page_index, Uint32 growth_len) { 613 assert(free_space >= growth_len); 614 615 Uint32 *pos= get_index_ptr(page_index); 616 Uint32 idx= *pos; 617 assert(! (idx & FREE)); 618 assert((((idx & POS_MASK) >> POS_SHIFT) + ((idx & LEN_MASK) >> LEN_SHIFT)) 619 == insert_pos); 620 621 * pos= idx + (growth_len << LEN_SHIFT); 622 insert_pos+= growth_len; 623 free_space-= growth_len; 624 } 625 shrink_entryTup_varsize_page626 void shrink_entry(Uint32 page_index, Uint32 new_size){ 627 Uint32 *pos= get_index_ptr(page_index); 628 Uint32 idx= *pos; 629 Uint32 old_pos = (idx & POS_MASK) >> POS_SHIFT; 630 Uint32 old_size = (idx & LEN_MASK) >> LEN_SHIFT; 631 632 assert( ! (idx & FREE)); 633 assert(old_size >= new_size); 634 635 * pos= (idx & ~LEN_MASK) + (new_size << LEN_SHIFT); 636 Uint32 shrink = old_size - new_size; 637 #ifdef VM_TRACE 638 memset(m_data + old_pos + new_size, 0xF1, 4 * shrink); 639 #endif 640 free_space+= shrink; 641 if(insert_pos == (old_pos + old_size)) 642 insert_pos -= shrink; 643 } 644 get_ptrTup_varsize_page645 Uint32* get_ptr(Uint32 page_idx) { 646 return m_data + ((get_index_word(page_idx) & POS_MASK) >> POS_SHIFT); 647 } 648 set_entry_offsetTup_varsize_page649 void set_entry_offset(Uint32 page_idx, Uint32 offset){ 650 Uint32 *pos= get_index_ptr(page_idx); 651 * pos = (* pos & ~POS_MASK) + (offset << POS_SHIFT); 652 } 653 set_entry_lenTup_varsize_page654 void set_entry_len(Uint32 page_idx, Uint32 len) { 655 Uint32 *pos= get_index_ptr(page_idx); 656 * pos = (*pos & ~LEN_MASK) + (len << LEN_SHIFT); 657 } 658 get_entry_lenTup_varsize_page659 Uint32 get_entry_len(Uint32 page_idx) const { 660 return (get_index_word(page_idx) & LEN_MASK) >> LEN_SHIFT; 661 } 662 get_entry_chainTup_varsize_page663 Uint32 get_entry_chain(Uint32 page_idx) const { 664 return get_index_word(page_idx) & CHAIN; 665 } 666 is_freeTup_varsize_page667 bool is_free(Uint32 page_idx) const 668 { 669 return ((get_index_word(page_idx) & FREE) != 0) ? true : false; 670 } 671 is_emptyTup_varsize_page672 bool is_empty() const 673 { 674 return high_index == 1; 675 } 676 }; 677 678 NdbOut& operator<< (NdbOut& out, const Tup_varsize_page& page); 679 NdbOut& operator<< (NdbOut& out, const Tup_fixsize_page& page); 680 681 682 #undef JAM_FILE_ID 683 684 #endif 685