1 /*****************************************************************************
2 
3 Copyright (c) 2016, 2019, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8 
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 
25 *****************************************************************************/
26 #ifndef zlob0first_h
27 #define zlob0first_h
28 
29 #include "fil0types.h"
30 #include "fut0lst.h"
31 #include "lob0impl.h"
32 #include "univ.i"
33 
34 namespace lob {
35 
36 /** The first page of an zlob. */
37 struct z_first_page_t {
38   /** Version information. One byte. */
39   static const ulint OFFSET_VERSION = FIL_PAGE_DATA;
40 
41   /** One byte of flag bits.  Currently only one bit (the least
42   significant bit) is used, other 7 bits are available for future use.*/
43   static const ulint OFFSET_FLAGS = FIL_PAGE_DATA + 1;
44 
45   /** LOB version. 4 bytes.*/
46   static const uint32_t OFFSET_LOB_VERSION = OFFSET_FLAGS + 1;
47 
48   /** The last transaction that modified this LOB. */
49   static const ulint OFFSET_LAST_TRX_ID = OFFSET_LOB_VERSION + 4;
50 
51   /** The last transaction that modified this LOB. */
52   static const ulint OFFSET_LAST_UNDO_NO = OFFSET_LAST_TRX_ID + 6;
53 
54   /** The length of compressed data stored in this page. */
55   static const ulint OFFSET_DATA_LEN = OFFSET_LAST_UNDO_NO + 4;
56 
57   /** The transaction that created data in the data portion. */
58   static const ulint OFFSET_TRX_ID = OFFSET_DATA_LEN + 4;
59 
60   /** The next index page. */
61   static const ulint OFFSET_INDEX_PAGE_NO = OFFSET_TRX_ID + 6;
62 
63   /** The next frag nodes page. */
64   static const ulint OFFSET_FRAG_NODES_PAGE_NO = OFFSET_INDEX_PAGE_NO + 4;
65 
66   /** List of free index entries. */
67   static const ulint OFFSET_FREE_LIST = OFFSET_FRAG_NODES_PAGE_NO + 4;
68 
69   /** List of index entries. */
70   static const ulint OFFSET_INDEX_LIST = OFFSET_FREE_LIST + FLST_BASE_NODE_SIZE;
71 
72   /** List of free frag entries. */
73   static const ulint OFFSET_FREE_FRAG_LIST =
74       OFFSET_INDEX_LIST + FLST_BASE_NODE_SIZE;
75 
76   /** List of frag entries. */
77   static const ulint OFFSET_FRAG_LIST =
78       OFFSET_FREE_FRAG_LIST + FLST_BASE_NODE_SIZE;
79 
80   /** Begin of index entries. */
81   static const ulint OFFSET_INDEX_BEGIN =
82       OFFSET_FRAG_LIST + FLST_BASE_NODE_SIZE;
83 
84   /** Given the page size, what is the number of index entries the
85   first page can contain. */
86   ulint get_n_index_entries() const;
87 
88   /** Given the page size, what is the number of frag entries the
89   first page can contain. */
90   ulint get_n_frag_entries() const;
91 
92   ulint size_of_index_entries() const;
93 
size_of_frag_entriesz_first_page_t94   ulint size_of_frag_entries() const {
95     return (z_frag_entry_t::SIZE * get_n_frag_entries());
96   }
97 
begin_frag_entriesz_first_page_t98   ulint begin_frag_entries() const {
99     return (OFFSET_INDEX_BEGIN + size_of_index_entries());
100   }
101 
begin_dataz_first_page_t102   ulint begin_data() const {
103     return (begin_frag_entries() + size_of_frag_entries());
104   }
105 
is_emptyz_first_page_t106   bool is_empty() const {
107     flst_base_node_t *flst = index_list();
108     return (flst_get_len(flst) == 0);
109   }
110 
111   /** Get the length of the index list.
112   @return length of the index list. */
get_index_list_lengthz_first_page_t113   ulint get_index_list_length() const {
114     flst_base_node_t *flst = index_list();
115     return (flst_get_len(flst));
116   }
117 
set_version_0z_first_page_t118   void set_version_0() {
119     mlog_write_ulint(frame() + OFFSET_VERSION, 0, MLOG_1BYTE, m_mtr);
120   }
121 
begin_data_ptrz_first_page_t122   byte *begin_data_ptr() const { return (frame() + begin_data()); }
123 
124   /** Amount of zlob data that can be stored in first page (in bytes). */
payloadz_first_page_t125   ulint payload() {
126     page_size_t page_size(dict_table_page_size(m_index->table));
127     ut_ad(begin_data() + FIL_PAGE_DATA_END < page_size.physical());
128     return (page_size.physical() - begin_data() - FIL_PAGE_DATA_END);
129   }
130 
z_first_page_tz_first_page_t131   z_first_page_t() : m_block(nullptr), m_mtr(nullptr), m_index(nullptr) {}
132 
z_first_page_tz_first_page_t133   z_first_page_t(mtr_t *mtr, dict_index_t *index)
134       : m_block(nullptr), m_mtr(mtr), m_index(index) {}
135 
z_first_page_tz_first_page_t136   z_first_page_t(buf_block_t *block) : m_block(block) {}
137 
z_first_page_tz_first_page_t138   z_first_page_t(buf_block_t *block, mtr_t *mtr, dict_index_t *index)
139       : m_block(block), m_mtr(mtr), m_index(index) {}
140 
141   buf_block_t *alloc(bool bulk);
142 
143   void import(trx_id_t trx_id);
144 
get_page_typez_first_page_t145   page_type_t get_page_type() const {
146     return (mach_read_from_2(frame() + FIL_PAGE_TYPE));
147   }
148 
149   /** Load the given page number as the first page in x-latch mode.
150   @param[in]	page_no		the first page number.
151   @return	the buffer block of the given page number. */
load_xz_first_page_t152   buf_block_t *load_x(page_no_t page_no) {
153     page_id_t page_id(dict_index_get_space(m_index), page_no);
154     page_size_t page_size(dict_table_page_size(m_index->table));
155     m_block = buf_page_get(page_id, page_size, RW_X_LATCH, m_mtr);
156     return (m_block);
157   }
158 
159   /** Load the first page using given mini transaction. The first page must
160   already be x-latched by the m_mtr.
161   @param[in]	mtr   the mini transaction in which first page is to be loaded.
162   @return the buffer block of first page. */
load_xz_first_page_t163   buf_block_t *load_x(mtr_t *mtr) const {
164     ut_ad(mtr_memo_contains(m_mtr, m_block, MTR_MEMO_PAGE_X_FIX));
165     buf_block_t *tmp = buf_page_get(m_block->page.id, m_index->get_page_size(),
166                                     RW_X_LATCH, mtr);
167     ut_ad(tmp == m_block);
168     return (tmp);
169   }
170 
171   /** Load the first page of the compressed LOB with x-latch.
172   @param[in]   page_id   the page identifier of first page
173   @param[in]   page_size the page size information of table.
174   @return buffer block of the first page. */
175   buf_block_t *load_x(const page_id_t &page_id, const page_size_t &page_size);
176 
177   /** Load the given page number as the first page in s-latch mode.
178   @param[in]	page_no		the first page number.
179   @return	the buffer block of the given page number. */
load_sz_first_page_t180   buf_block_t *load_s(page_no_t page_no) {
181     ut_ad(m_block == nullptr);
182 
183     page_id_t page_id(dict_index_get_space(m_index), page_no);
184     page_size_t page_size(dict_table_page_size(m_index->table));
185     m_block = buf_page_get(page_id, page_size, RW_S_LATCH, m_mtr);
186     return (m_block);
187   }
188 
189   /** Deallocate the first page of a compressed LOB. */
190   void dealloc();
191 
192   /** Set the FIL_PAGE_NEXT to FIL_NULL. */
set_next_page_nullz_first_page_t193   void set_next_page_null() { set_next_page_no(FIL_NULL, m_mtr); }
194 
195   /** Set the FIL_PAGE_PREV to FIL_NULL. */
set_prev_page_nullz_first_page_t196   void set_prev_page_null() { set_prev_page_no(FIL_NULL, m_mtr); }
197 
198   /** Set the FIL_PAGE_NEXT to the given value.
199   @param[in]    page_no   the page number to set in FIL_PAGE_NEXT.
200   @param[in]    mtr       mini trx to be used for this modification. */
set_next_page_noz_first_page_t201   void set_next_page_no(page_no_t page_no, mtr_t *mtr) {
202     ut_ad(mtr != nullptr);
203     mlog_write_ulint(frame() + FIL_PAGE_NEXT, page_no, MLOG_4BYTES, mtr);
204   }
205 
206   /** Set the FIL_PAGE_PREV to the given value.
207   @param[in]    page_no   the page number to set in FIL_PAGE_PREV.
208   @param[in]    mtr       mini trx to be used for this modification. */
set_prev_page_noz_first_page_t209   void set_prev_page_no(page_no_t page_no, mtr_t *mtr) {
210     ut_ad(mtr != nullptr);
211     mlog_write_ulint(frame() + FIL_PAGE_PREV, page_no, MLOG_4BYTES, mtr);
212   }
213 
214   /** Write the space identifier to the page header, without generating
215   redo log records.
216   @param[in]	space_id	the space identifier. */
set_space_id_no_redoz_first_page_t217   void set_space_id_no_redo(space_id_t space_id) {
218     mlog_write_ulint(frame() + FIL_PAGE_SPACE_ID, space_id, MLOG_4BYTES,
219                      nullptr);
220   }
221 
initz_first_page_t222   void init() {
223     ut_ad(m_mtr != nullptr);
224 
225     set_page_type();
226     set_version_0();
227     set_data_len(0);
228     set_next_page_null();
229     set_prev_page_null();
230     set_trx_id(0);
231     flst_base_node_t *flst = free_list();
232     flst_init(flst, m_mtr);
233     flst_base_node_t *ilst = index_list();
234     flst_init(ilst, m_mtr);
235     flst_base_node_t *free_frag_lst = free_frag_list();
236     flst_init(free_frag_lst, m_mtr);
237     flst_base_node_t *frag_lst = frag_list();
238     flst_init(frag_lst, m_mtr);
239     init_index_entries();
240     init_frag_entries();
241     set_frag_node_page_no(FIL_NULL);
242     set_index_page_no(FIL_NULL);
243   }
244 
245   /** Get the amount of zlob data stored in this page. */
get_data_lenz_first_page_t246   ulint get_data_len() const {
247     return (mach_read_from_4(frame() + OFFSET_DATA_LEN));
248   }
249 
250   /** Get the page number. */
get_page_noz_first_page_t251   page_no_t get_page_no() const { return (m_block->page.id.page_no()); }
252 
253   /** Get the page id of the first page of compressed LOB.
254   @return page id of the first page of compressed LOB. */
get_page_idz_first_page_t255   page_id_t get_page_id() const {
256     ut_ad(m_block != nullptr);
257 
258     return (m_block->page.id);
259   }
260 
get_self_addrz_first_page_t261   fil_addr_t get_self_addr() const {
262     page_no_t page_no = get_page_no();
263     uint32_t offset = static_cast<uint32_t>(begin_data());
264     return (fil_addr_t(page_no, offset));
265   }
266 
267   /** All the index pages are singled linked with each other, and
268   the first page contains the link to one index page.
269   @param[in]  page_no  the page number of an index page. */
set_index_page_noz_first_page_t270   void set_index_page_no(page_no_t page_no) {
271     ut_ad(m_mtr != nullptr);
272     mlog_write_ulint(frame() + OFFSET_INDEX_PAGE_NO, page_no, MLOG_4BYTES,
273                      m_mtr);
274   }
275 
276   /** All the index pages are singled linked with each other, and
277   the first page contains the link to one index page. Get that index
278   page number.
279   @return the index page number. */
get_index_page_noz_first_page_t280   page_no_t get_index_page_no() const {
281     return (mach_read_from_4(frame() + OFFSET_INDEX_PAGE_NO));
282   }
283 
284   /** All the fragment pages are doubly linked with each other, and
285   the first page contains the link to one fragment page in FIL_PAGE_PREV. Get
286   that frag page number.
287   @return the frag page number. */
get_frag_page_noz_first_page_t288   page_no_t get_frag_page_no() const { return (m_block->get_prev_page_no()); }
289 
290   /** All the fragment pages are doubly linked with each other, and
291   the first page contains the link to one fragment page in FIL_PAGE_PREV. Get
292   that frag page number.
293   @param[in]   mtr   mini transaction to use for this read operation.
294   @return the frag page number. */
get_frag_page_noz_first_page_t295   page_no_t get_frag_page_no(mtr_t *mtr) const {
296     return (mtr_read_ulint(frame() + FIL_PAGE_PREV, MLOG_4BYTES, mtr));
297   }
298 
299 #ifdef UNIV_DEBUG
300   /** Verify that the page number pointed to by FIL_PAGE_PREV of the first page
301   of LOB is indeed a fragment page.  It uses its own mtr internally.
302   @return true if it is a fragment page, false otherwise. */
303   bool verify_frag_page_no();
304 #endif /* UNIV_DEBUG */
305 
306   /** All the fragment pages are doubly linked with each other, and
307   the first page contains the link to one fragment page in FIL_PAGE_PREV.
308   @param[in]  mtr      mini transaction for this modification.
309   @param[in]  page_no  the page number of a fragment page. */
set_frag_page_noz_first_page_t310   void set_frag_page_no(mtr_t *mtr, page_no_t page_no) {
311     ut_ad(verify_frag_page_no());
312     set_prev_page_no(page_no, mtr);
313   }
314 
315   /** All the fragment pages are doubly linked with each other, and
316   the first page contains the link to one fragment page in FIL_PAGE_PREV.
317   @param[in]  page_no  the page number of a fragment page. */
set_frag_page_noz_first_page_t318   void set_frag_page_no(page_no_t page_no) {
319     ut_ad(verify_frag_page_no());
320     set_prev_page_no(page_no, m_mtr);
321   }
322 
323   /** All the frag node pages are singled linked with each other, and
324   the first page contains the link to one frag node page.
325   @param[in]  page_no  the page number of an frag node page. */
set_frag_node_page_noz_first_page_t326   void set_frag_node_page_no(page_no_t page_no) {
327     ut_ad(m_mtr != nullptr);
328     mlog_write_ulint(frame() + OFFSET_FRAG_NODES_PAGE_NO, page_no, MLOG_4BYTES,
329                      m_mtr);
330   }
331 
332   /** Free all the z_frag_page_t pages. All the z_frag_page_t pages are
333   singly linked to each other.  The head of the list is maintained in the
334   first page.
335   @return the number of pages freed. */
336   size_t free_all_frag_node_pages();
337 
338   /** Free all the index pages.
339   @return the number of pages freed. */
340   size_t free_all_index_pages();
341 
342   /** Free all the fragment pages.
343   @return the number of pages freed. */
344   size_t free_all_frag_pages();
345 
346  private:
347   /** Free all the fragment pages when the next page of the first LOB page IS
348    * NOT USED to link the fragment pages.
349   @return the number of pages freed. */
350   size_t free_all_frag_pages_old();
351 
352   /** Free all the fragment pages when the next page of the first LOB page IS
353    * USED to link the fragment pages.
354   @return the number of pages freed. */
355   size_t free_all_frag_pages_new();
356 
357  public:
358   /** Free all the data pages.
359   @return the number of pages freed. */
360   size_t free_all_data_pages();
361 
362   /** All the frag node pages are singled linked with each other, and the
363   first page contains the link to one frag node page. Get that frag node
364   page number.
365   @return the index page number. */
get_frag_node_page_noz_first_page_t366   page_no_t get_frag_node_page_no() {
367     return (mach_read_from_4(frame() + OFFSET_FRAG_NODES_PAGE_NO));
368   }
369 
370   /** Set the page type to FIL_PAGE_TYPE_UNKNOWN.  This is done while
371   deallocating this page. */
set_page_type_unknownz_first_page_t372   void set_page_type_unknown() {
373     ut_ad(m_mtr != nullptr);
374     mlog_write_ulint(frame() + FIL_PAGE_TYPE, FIL_PAGE_TYPE_UNKNOWN,
375                      MLOG_2BYTES, m_mtr);
376   }
377 
set_page_typez_first_page_t378   void set_page_type() {
379     ut_ad(m_mtr != nullptr);
380     mlog_write_ulint(frame() + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ZLOB_FIRST,
381                      MLOG_2BYTES, m_mtr);
382   }
383 
set_data_lenz_first_page_t384   void set_data_len(ulint len) {
385     ut_ad(m_mtr != nullptr);
386     mlog_write_ulint(frame() + OFFSET_DATA_LEN, len, MLOG_4BYTES, m_mtr);
387   }
388 
389   /** Update the trx id in the header.
390   @param[in]	tid	the given transaction identifier. */
set_trx_idz_first_page_t391   void set_trx_id(trx_id_t tid) {
392     byte *ptr = frame() + OFFSET_TRX_ID;
393     mach_write_to_6(ptr, tid);
394     mlog_log_string(ptr, 6, m_mtr);
395   }
396 
397   /** Update the trx id in the header, without generating redo
398   log records.
399   @param[in]	tid	the given transaction identifier. */
set_trx_id_no_redoz_first_page_t400   void set_trx_id_no_redo(trx_id_t tid) {
401     byte *ptr = frame() + OFFSET_TRX_ID;
402     mach_write_to_6(ptr, tid);
403   }
404 
405   /** Initialize the LOB version to 1. */
init_lob_versionz_first_page_t406   void init_lob_version() {
407     ut_ad(m_mtr != nullptr);
408 
409     mlog_write_ulint(frame() + OFFSET_LOB_VERSION, 1, MLOG_4BYTES, m_mtr);
410   }
411 
412   /** Get the LOB version
413   @return the LOB version. */
get_lob_versionz_first_page_t414   uint32_t get_lob_version() {
415     return (mach_read_from_4(frame() + OFFSET_LOB_VERSION));
416   }
417 
418   /** Increment LOB version by 1. */
419   uint32_t incr_lob_version();
420 
421   /** Get one byte of flags
422   @return one byte of flags. */
get_flagsz_first_page_t423   uint8_t get_flags() { return (mach_read_from_1(frame() + OFFSET_FLAGS)); }
424 
425   /** When the bit is set, the LOB is not partially updatable anymore.
426   @return true, if partially updatable.
427   @return false, if partially NOT updatable. */
can_be_partially_updatedz_first_page_t428   bool can_be_partially_updated() {
429     uint8_t flags = get_flags();
430     return (!(flags & 0x01));
431   }
432 
433   /** When the bit is set, the LOB is not partially updatable anymore.
434   Enable the bit.
435   @param[in]	trx	the current transaction.*/
436   void mark_cannot_be_partially_updated(trx_t *trx);
437 
set_last_trx_idz_first_page_t438   void set_last_trx_id(trx_id_t tid) {
439     byte *ptr = frame() + OFFSET_LAST_TRX_ID;
440     mach_write_to_6(ptr, tid);
441     mlog_log_string(ptr, 6, m_mtr);
442   }
443 
444   /** Update the last transaction identifier in the header, without
445   generating redo logs.
446   @param[in]	tid	given transaction identifier.*/
set_last_trx_id_no_redoz_first_page_t447   void set_last_trx_id_no_redo(trx_id_t tid) {
448     byte *ptr = frame() + OFFSET_LAST_TRX_ID;
449     mach_write_to_6(ptr, tid);
450   }
451 
set_last_trx_undo_noz_first_page_t452   void set_last_trx_undo_no(undo_no_t undo_no) {
453     ut_ad(m_mtr != nullptr);
454 
455     byte *ptr = frame() + OFFSET_LAST_UNDO_NO;
456     mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr);
457   }
458 
get_last_trx_idz_first_page_t459   trx_id_t get_last_trx_id() const {
460     byte *ptr = frame() + OFFSET_LAST_TRX_ID;
461     return (mach_read_from_6(ptr));
462   }
463 
get_last_trx_undo_noz_first_page_t464   undo_no_t get_last_trx_undo_no() const {
465     byte *ptr = frame() + OFFSET_LAST_UNDO_NO;
466     return (mach_read_from_4(ptr));
467   }
468 
free_listz_first_page_t469   flst_base_node_t *free_list() const { return (frame() + OFFSET_FREE_LIST); }
470 
index_listz_first_page_t471   flst_base_node_t *index_list() const { return (frame() + OFFSET_INDEX_LIST); }
472 
free_frag_listz_first_page_t473   flst_base_node_t *free_frag_list() const {
474     return (frame() + OFFSET_FREE_FRAG_LIST);
475   }
476 
frag_listz_first_page_t477   flst_base_node_t *frag_list() const { return (frame() + OFFSET_FRAG_LIST); }
478 
init_frag_entriesz_first_page_t479   void init_frag_entries() {
480     flst_base_node_t *free_frag_lst = free_frag_list();
481     ulint n = get_n_frag_entries();
482     for (ulint i = 0; i < n; ++i) {
483       flst_node_t *ptr = frame() + begin_frag_entries();
484       ptr += (i * z_frag_entry_t::SIZE);
485       z_frag_entry_t frag_entry(ptr, m_mtr);
486       frag_entry.init();
487       frag_entry.push_back(free_frag_lst);
488     }
489   }
490 
491   void init_index_entries();
492 
493   /** Allocate a fragment of the given size.  This involves finding a
494   fragment page, that has space to store len bytes of data. If necessary,
495   allocate a new fragment page.
496   @param[in]	bulk		true if it is bulk operation
497                                   (OPCODE_INSERT_BULK), false otherwise.
498   @param[in]	len		length of data to be stored in
499                                   fragment page.
500   @param[out]	frag_page	the fragment page with the needed
501                                   free space.
502   @param[out]   entry           fragment page entry representing frag_page.
503   @return fragment identifier within the fragment page.
504   @return FRAG_ID_NULL if fragment could not be allocated. */
505   frag_id_t alloc_fragment(bool bulk, ulint len, z_frag_page_t &frag_page,
506                            z_frag_entry_t &entry);
507 
508   /** Allocate one index entry.  If there is no free index entry,
509   allocate an index page (a page full of z_index_entry_t objects)
510   and service the request.
511   @return the allocated index entry. */
512   z_index_entry_t alloc_index_entry(bool bulk);
513 
514   /** Allocate one frag page entry.  If there is no free frag
515   entry, allocate an frag node page (a page full of z_frag_entry_t
516   objects) and service the request.
517   @return the allocated frag entry. */
518   z_frag_entry_t alloc_frag_entry(bool bulk);
519 
520   /** Print the index entries. */
521   std::ostream &print_index_entries(std::ostream &out) const;
522 
523   /** Print the index entries. */
524   std::ostream &print_frag_entries(std::ostream &out) const;
525 
526   /** Print the page. */
527   std::ostream &print(std::ostream &out) const;
528 
framez_first_page_t529   byte *frame() const { return (buf_block_get_frame(m_block)); }
530 
531   /** Load the page, in x-latch mode, containing the given file address.
532   @param[in]	addr	given file address
533   @return	the file list node pointer. */
addr2ptr_xz_first_page_t534   flst_node_t *addr2ptr_x(fil_addr_t &addr) const {
535     return (addr2ptr_x(addr, m_mtr));
536   }
537 
538   /** Load the page, in x-latch mode, containing the given file address.
539   @param[in]	addr	given file address
540   @param[in]	mtr     the mini transaction context to be used.
541   @return	the file list node pointer. */
addr2ptr_xz_first_page_t542   flst_node_t *addr2ptr_x(fil_addr_t &addr, mtr_t *mtr) const {
543     space_id_t space = dict_index_get_space(m_index);
544     const page_size_t page_size = dict_table_page_size(m_index->table);
545     return (fut_get_ptr(space, page_size, addr, RW_X_LATCH, mtr));
546   }
547 
548   /** Load the page, in s-latch mode, containing the given file address.
549   @param[in]	addr	given file address
550   @return	the file list node pointer. */
addr2ptr_sz_first_page_t551   flst_node_t *addr2ptr_s(fil_addr_t &addr) {
552     space_id_t space = dict_index_get_space(m_index);
553     const page_size_t page_size = dict_table_page_size(m_index->table);
554     return (fut_get_ptr(space, page_size, addr, RW_S_LATCH, m_mtr));
555   }
556 
557   /** Load the entry available in the given file address.
558   @param[in]	addr	file address
559   @param[out]	entry	the entry to be loaded.*/
560   void load_entry_s(fil_addr_t &addr, z_index_entry_t &entry);
561 
562   /** Load the entry available in the given file address.
563   @param[in]	addr	file address
564   @param[out]	entry	the entry to be loaded.*/
565   void load_entry_x(fil_addr_t &addr, z_index_entry_t &entry);
566 
567   /** Free all the pages of the zlob.
568   @return the total number of pages freed. */
569   size_t destroy();
570 
571 #ifdef UNIV_DEBUG
572  private:
573   /** Validate the LOB.  This is a costly function.  We need to avoid using
574   this directly, instead call z_first_page_t::validate().
575   @return true if valid, false otherwise. */
576   bool validate_low();
577 
578  public:
579   /** Validate the LOB.
580   @return true if valid, false otherwise. */
validatez_first_page_t581   bool validate() {
582     static const uint32_t FREQ = 50;
583     static std::atomic<uint32_t> n{0};
584 
585     bool valid = true;
586     if (++n % FREQ == 0) {
587       valid = validate_low();
588     }
589     return (valid);
590   }
591 #endif /* UNIV_DEBUG */
592 
593   /** Get the buffer block of the first page of LOB.
594   @return the buffer block of the first page of LOB. */
get_blockz_first_page_t595   buf_block_t *get_block() const { return (m_block); }
596 
597  public:
set_mtrz_first_page_t598   void set_mtr(mtr_t *mtr) { m_mtr = mtr; }
599 
600   /** Restart the given mtr. The first page must already be x-latched by the
601   m_mtr.
602   @param[in]   mtr   the mini transaction context which is to be restarted. */
restart_mtrz_first_page_t603   void restart_mtr(mtr_t *mtr) {
604     ut_ad(mtr != m_mtr);
605 
606     mtr_commit(mtr);
607     mtr_start(mtr);
608     mtr->set_log_mode(m_mtr->get_log_mode());
609     load_x(mtr);
610   }
611 
612  private:
613   /** The buffer block of the first page. */
614   buf_block_t *m_block;
615 
616   /** The mini-transaction context. */
617   mtr_t *m_mtr;
618 
619   /** The index dictionary object. */
620   dict_index_t *m_index;
621 
622 };  // struct z_first_page_t
623 
624 /** Overloading the global output parameter to print object of type
625 z_first_page_t into the given output stream.
626 @param[in,out]		out	output stream.
627 @param[in]		obj	object to be printed.
628 @return	the output stream. */
629 inline std::ostream &operator<<(std::ostream &out, const z_first_page_t &obj) {
630   return (obj.print(out));
631 }
632 
633 } /* namespace lob */
634 
635 #endif /* zlob0first_h */
636