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