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 zlob0index_h
27 #define zlob0index_h
28 
29 #include "fil0fil.h"
30 #include "fut0lst.h"
31 #include "lob0impl.h"
32 
33 namespace lob {
34 
35 /** In-memory copy of the information from z_index_entry_t.  */
36 struct z_index_entry_mem_t {
z_index_entry_mem_tz_index_entry_mem_t37   z_index_entry_mem_t()
38       : m_trx_id(0), m_z_page_no(FIL_NULL), m_z_frag_id(FRAG_ID_NULL) {}
39 
40   /** The location of this index entry node. */
41   fil_addr_t m_self;
42 
43   fil_addr_t m_prev;
44   fil_addr_t m_next;
45   flst_bnode_t m_versions;
46   trx_id_t m_trx_id;
47   trx_id_t m_trx_id_modifier;
48   undo_no_t m_trx_undo_no;
49   undo_no_t m_trx_undo_no_modifier;
50   page_no_t m_z_page_no;
51   frag_id_t m_z_frag_id;
52 
53   /** Uncompressed data length. */
54   ulint m_data_len;
55 
56   /** Compressed data length. */
57   ulint m_z_data_len;
58 
59   std::ostream &print(std::ostream &out) const;
60 
61   /** Initialize all the members. */
resetz_index_entry_mem_t62   void reset() {
63     m_self = fil_addr_null;
64     m_prev = fil_addr_null;
65     m_next = fil_addr_null;
66     m_versions.reset();
67     m_trx_id = 0;
68     m_trx_id_modifier = 0;
69     m_trx_undo_no = 0;
70     m_trx_undo_no_modifier = 0;
71     m_z_page_no = FIL_NULL;
72     m_z_frag_id = 0;
73     m_data_len = 0;
74     m_z_data_len = 0;
75   }
76 
is_nullz_index_entry_mem_t77   bool is_null() { return (m_self.is_equal(fil_addr_null)); }
78 };
79 
80 inline std::ostream &operator<<(std::ostream &out,
81                                 const z_index_entry_mem_t &obj) {
82   return (obj.print(out));
83 }
84 
85 /** An index entry pointing to one zlib stream. */
86 struct z_index_entry_t {
87   /** Offset with index entry pointing to the prev index entry. */
88   static const ulint OFFSET_PREV = 0;
89 
90   /** Offset with index entry pointing to the next index entry. */
91   static const ulint OFFSET_NEXT = OFFSET_PREV + FIL_ADDR_SIZE;
92 
93   /** Offset within index entry pointing to base node of list of
94   versions.*/
95   static const ulint OFFSET_VERSIONS = OFFSET_NEXT + FIL_ADDR_SIZE;
96 
97   /** Offset within index entry pointing to creator trxid.*/
98   static const ulint OFFSET_TRXID = OFFSET_VERSIONS + FLST_BASE_NODE_SIZE;
99 
100   /** The modifier trx id. */
101   static const ulint OFFSET_TRXID_MODIFIER = OFFSET_TRXID + 6;
102 
103   /** Offset within index entry pointing to trx undo no.*/
104   static const ulint OFFSET_TRX_UNDO_NO = OFFSET_TRXID_MODIFIER + 6;
105 
106   /** Offset within index entry pointing to modifier trx undo no.*/
107   static const ulint OFFSET_TRX_UNDO_NO_MODIFIER = OFFSET_TRX_UNDO_NO + 4;
108 
109   /** Offset within index entry pointing to page number where zlib
110   stream starts. This could be a data page or a fragment page. */
111   static const ulint OFFSET_Z_PAGE_NO = OFFSET_TRX_UNDO_NO_MODIFIER + 4;
112 
113   /** Offset within index entry pointing to location of zlib stream.*/
114   static const ulint OFFSET_Z_FRAG_ID = OFFSET_Z_PAGE_NO + 4;
115 
116   /** Offset within index entry pointing to uncompressed data
117   len (bytes).*/
118   static const ulint OFFSET_DATA_LEN = OFFSET_Z_FRAG_ID + 2;
119 
120   /** Offset within index entry pointing to compressed data len
121   (bytes).*/
122   static const ulint OFFSET_ZDATA_LEN = OFFSET_DATA_LEN + 4;
123 
124   /** LOB version */
125   static const ulint OFFSET_LOB_VERSION = OFFSET_ZDATA_LEN + 4;
126 
127   /** Total size of one index entry. */
128   static const ulint SIZE = OFFSET_LOB_VERSION + 4;
129 
130   /** Constructor. */
z_index_entry_tz_index_entry_t131   z_index_entry_t(flst_node_t *node, mtr_t *mtr) : m_node(node), m_mtr(mtr) {}
132 
133   /** Constructor. */
z_index_entry_tz_index_entry_t134   z_index_entry_t(flst_node_t *node, mtr_t *mtr, dict_index_t *index)
135       : m_node(node), m_mtr(mtr), m_index(index) {}
136 
137   /** Constructor
138   @param[in]	mtr	the mini transaction
139   @param[in]	index	the clustered index to which LOB belongs. */
z_index_entry_tz_index_entry_t140   z_index_entry_t(mtr_t *mtr, dict_index_t *index)
141       : m_node(nullptr),
142         m_mtr(mtr),
143         m_index(index),
144         m_block(nullptr),
145         m_page_no(FIL_NULL) {}
146 
147   /** Constructor
148   @param[in]	node	the location where index entry starts. */
z_index_entry_tz_index_entry_t149   z_index_entry_t(flst_node_t *node)
150       : m_node(node),
151         m_mtr(nullptr),
152         m_index(nullptr),
153         m_block(nullptr),
154         m_page_no(FIL_NULL) {}
155 
156   /** Default constructor */
z_index_entry_tz_index_entry_t157   z_index_entry_t()
158       : m_node(nullptr),
159         m_mtr(nullptr),
160         m_index(nullptr),
161         m_block(nullptr),
162         m_page_no(FIL_NULL) {}
163 
set_indexz_index_entry_t164   void set_index(dict_index_t *index) { m_index = index; }
165 
166   /** Point to another index entry.
167   @param[in]  node  point to this file list node. */
resetz_index_entry_t168   void reset(flst_node_t *node) { m_node = node; }
169 
170   /** Point to another index entry.
171   @param[in]  entry  another index entry.*/
resetz_index_entry_t172   void reset(const z_index_entry_t &entry) { m_node = entry.m_node; }
173 
174   /** Initialize an index entry to some sane value. */
initz_index_entry_t175   void init() {
176     ut_ad(m_mtr != nullptr);
177 
178     set_prev_null();
179     set_next_null();
180     set_versions_null();
181     set_trx_id(0);
182     set_trx_undo_no(0);
183     set_z_page_no(FIL_NULL);
184     set_z_frag_id(FRAG_ID_NULL);
185     set_data_len(0);
186     set_zdata_len(0);
187   }
188 
189   /** Determine if the current index entry be rolled back.
190   @param[in]	trxid		the transaction that is being rolled
191                                   back.
192   @param[in]	undo_no		the savepoint undo number of trx,
193                                   upto which rollback happens.
194   @return true if this entry can be rolled back, false otherwise. */
can_rollbackz_index_entry_t195   bool can_rollback(trx_id_t trxid, undo_no_t undo_no) {
196     /* For rollback, make use of creator trx id. */
197     return ((trxid == get_trx_id()) && (get_trx_undo_no() >= undo_no));
198   }
199 
200   /** Determine if the current index entry be purged.
201   @param[in]	trxid		the transaction that is being purged.
202   @param[in]	undo_no		the undo number of trx.
203   @return true if this entry can be purged, false otherwise. */
can_be_purgedz_index_entry_t204   bool can_be_purged(trx_id_t trxid, undo_no_t undo_no) {
205     return ((trxid == get_trx_id_modifier()) &&
206             (get_trx_undo_no_modifier() == undo_no));
207   }
208 
209   /** Purge one index entry.
210   @param[in]	index		index to which LOB belongs.
211   @param[in]	trxid		purging data belonging to trxid.
212   @param[in]	first		first page of LOB.
213   @param[in,out]	lst		list from which this entry will be
214                                   removed.
215   @param[in,out]	free_list	list to which this entry will be
216                                   added.*/
217   fil_addr_t purge_version(dict_index_t *index, trx_id_t trxid,
218                            z_first_page_t &first, flst_base_node_t *lst,
219                            flst_base_node_t *free_list);
220 
221   /** Purge the current index entry. An index entry points to either a
222   FIRST page or DATA page.  That LOB page will be freed if it is DATA
223   page.  A FIRST page should not be freed. */
224   void purge(dict_index_t *index, z_first_page_t &first);
225 
226   /** Remove this node from the given list.
227   @param[in]	bnode	the base node of the list from which to remove
228                           current node. */
removez_index_entry_t229   void remove(flst_base_node_t *bnode) {
230     ut_ad(m_mtr != nullptr);
231 
232     flst_remove(bnode, m_node, m_mtr);
233   }
234 
235   /** Insert the given index entry after the current index entry.
236   @param[in]	base	the base node of the file based list.
237   @param[in]	entry	the new node to be inserted.*/
insert_afterz_index_entry_t238   void insert_after(flst_base_node_t *base, z_index_entry_t &entry) {
239     ut_ad(m_mtr != nullptr);
240 
241     flst_insert_after(base, m_node, entry.get_node(), m_mtr);
242   }
243 
insert_beforez_index_entry_t244   void insert_before(flst_base_node_t *base, z_index_entry_t &entry) {
245     ut_ad(m_mtr != nullptr);
246 
247     flst_insert_before(base, entry.get_node(), m_node, m_mtr);
248   }
249 
250   /** Add this node as the last node in the given list.
251   @param[in]  bnode  the base node of the file list. */
push_backz_index_entry_t252   void push_back(flst_base_node_t *bnode) {
253     ut_ad(m_mtr != nullptr);
254 
255     flst_add_last(bnode, m_node, m_mtr);
256   }
257 
258   /** Add this node as the last node in the given list.
259   @param[in]  bnode  the base node of the file list. */
push_frontz_index_entry_t260   void push_front(flst_base_node_t *bnode) {
261     ut_ad(m_mtr != nullptr);
262     flst_add_first(bnode, m_node, m_mtr);
263   }
264 
265   /** Set the previous index entry as null. */
set_prev_nullz_index_entry_t266   void set_prev_null() {
267     flst_write_addr(m_node + OFFSET_PREV, fil_addr_null, m_mtr);
268   }
269 
270   /** Get the location of previous index entry. */
get_prevz_index_entry_t271   fil_addr_t get_prev() const {
272     return (flst_read_addr(m_node + OFFSET_PREV, m_mtr));
273   }
274 
275   /** Get the location of next index entry.
276   @return the file address of the next index entry. */
get_nextz_index_entry_t277   fil_addr_t get_next() const {
278     return (flst_read_addr(m_node + OFFSET_NEXT, m_mtr));
279   }
280 
281   /** Set the next index entry as null. */
set_next_nullz_index_entry_t282   void set_next_null() {
283     ut_ad(m_mtr != nullptr);
284     flst_write_addr(m_node + OFFSET_NEXT, fil_addr_null, m_mtr);
285   }
286 
287   /** Set the versions list as null. */
set_versions_nullz_index_entry_t288   void set_versions_null() {
289     flst_base_node_t *bnode = get_versions_list();
290     flst_init(bnode, m_mtr);
291   }
292 
293   /** Get the base node of the list of versions. */
get_versions_listz_index_entry_t294   flst_base_node_t *get_versions_list() const {
295     return (m_node + OFFSET_VERSIONS);
296   }
297 
298   /** Get the base node of the list of versions. */
get_versions_memz_index_entry_t299   flst_bnode_t get_versions_mem() const {
300     ut_ad(m_mtr != nullptr);
301     flst_base_node_t *node = get_versions_list();
302     return (flst_bnode_t(node, m_mtr));
303   }
304 
get_trx_idz_index_entry_t305   trx_id_t get_trx_id() const {
306     return (mach_read_from_6(m_node + OFFSET_TRXID));
307   }
308 
get_trx_id_modifierz_index_entry_t309   trx_id_t get_trx_id_modifier() const {
310     return (mach_read_from_6(m_node + OFFSET_TRXID_MODIFIER));
311   }
312 
313   /** Get the undo number of the creator transaction.  This is used
314   for rollback purposes.
315   @return the undo number of creator trx. */
get_trx_undo_noz_index_entry_t316   undo_no_t get_trx_undo_no() const {
317     byte *ptr = m_node + OFFSET_TRX_UNDO_NO;
318     return (mach_read_from_4(ptr));
319   }
320 
321   /** Get the undo number of the modifier transaction.  This is used
322   for purging purposes.
323   @return the undo number of modifier trx. */
get_trx_undo_no_modifierz_index_entry_t324   undo_no_t get_trx_undo_no_modifier() const {
325     byte *ptr = m_node + OFFSET_TRX_UNDO_NO_MODIFIER;
326     return (mach_read_from_4(ptr));
327   }
328 
329   /** Set the trx identifier to given value, without generating redo
330   log records.
331   @param[in]	id	the given trx identifier.*/
set_trx_id_no_redoz_index_entry_t332   void set_trx_id_no_redo(trx_id_t id) {
333     byte *ptr = m_node + OFFSET_TRXID;
334     mach_write_to_6(ptr, id);
335   }
336 
337   /** Set the trx identifier to given value.
338   @param[in]	id	the given trx identifier.*/
set_trx_idz_index_entry_t339   void set_trx_id(trx_id_t id) {
340     ut_ad(m_mtr != nullptr);
341     byte *ptr = m_node + OFFSET_TRXID;
342     mach_write_to_6(ptr, id);
343     mlog_log_string(ptr, 6, m_mtr);
344   }
345 
346   /** Set the modifier trxid to the given value.
347   @param[in]	id	the modifier trxid.*/
set_trx_id_modifierz_index_entry_t348   void set_trx_id_modifier(trx_id_t id) {
349     ut_ad(m_mtr != nullptr);
350 
351     byte *ptr = m_node + OFFSET_TRXID_MODIFIER;
352     mach_write_to_6(ptr, id);
353     mlog_log_string(ptr, 6, m_mtr);
354   }
355 
356   /** Set the modifier trxid to the given value, without generating
357   redo log records.
358   @param[in]	id	the modifier trxid.*/
set_trx_id_modifier_no_redoz_index_entry_t359   void set_trx_id_modifier_no_redo(trx_id_t id) {
360     byte *ptr = m_node + OFFSET_TRXID_MODIFIER;
361     mach_write_to_6(ptr, id);
362   }
363 
364   /** Set the undo number of the creator trx.
365   @param[in]	undo_no		the undo number value.*/
set_trx_undo_noz_index_entry_t366   void set_trx_undo_no(undo_no_t undo_no) {
367     ut_ad(m_mtr != nullptr);
368     byte *ptr = m_node + OFFSET_TRX_UNDO_NO;
369     mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr);
370   }
371 
372   /** Set the undo number of the modifier trx.
373   @param[in]	undo_no		the undo number value.*/
set_trx_undo_no_modifierz_index_entry_t374   void set_trx_undo_no_modifier(undo_no_t undo_no) {
375     ut_ad(m_mtr != nullptr);
376     byte *ptr = m_node + OFFSET_TRX_UNDO_NO_MODIFIER;
377     mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr);
378   }
379 
get_z_page_noz_index_entry_t380   page_no_t get_z_page_no() const {
381     return (mach_read_from_4(m_node + OFFSET_Z_PAGE_NO));
382   }
383 
384   /** Set the page number pointed to by this index entry to FIL_NULL.
385    @param[in]   mtr    The mini transaction used for this modification. */
set_z_page_no_nullz_index_entry_t386   void set_z_page_no_null(mtr_t *mtr) {
387     mlog_write_ulint(m_node + OFFSET_Z_PAGE_NO, FIL_NULL, MLOG_4BYTES, mtr);
388   }
389 
390   /** Free the data pages pointed to by this index entry.
391   @param[in]   mtr   the mini transaction used to free the pages.
392   @return the number of pages freed. */
393   size_t free_data_pages(mtr_t *mtr);
394 
395   /** Set the page number pointed to by this index entry to given value.
396    @param[in]   page_no    Page number to be put in index entry. */
set_z_page_noz_index_entry_t397   void set_z_page_no(page_no_t page_no) {
398     ut_ad(m_mtr != nullptr);
399     mlog_write_ulint(m_node + OFFSET_Z_PAGE_NO, page_no, MLOG_4BYTES, m_mtr);
400   }
401 
get_z_frag_idz_index_entry_t402   page_no_t get_z_frag_id() const {
403     return (mach_read_from_2(m_node + OFFSET_Z_FRAG_ID));
404   }
405 
set_z_frag_idz_index_entry_t406   void set_z_frag_id(frag_id_t id) {
407     ut_ad(m_mtr != nullptr);
408     mlog_write_ulint(m_node + OFFSET_Z_FRAG_ID, id, MLOG_2BYTES, m_mtr);
409   }
410 
411   /** Get the uncompressed data length in bytes. */
get_data_lenz_index_entry_t412   ulint get_data_len() const {
413     return (mach_read_from_4(m_node + OFFSET_DATA_LEN));
414   }
415 
416   /** Set the uncompressed data length in bytes.
417   @param[in]  len  the uncompressed data length in bytes */
set_data_lenz_index_entry_t418   void set_data_len(ulint len) {
419     ut_ad(m_mtr != nullptr);
420     mlog_write_ulint(m_node + OFFSET_DATA_LEN, len, MLOG_4BYTES, m_mtr);
421   }
422 
423   /** Get the compressed data length in bytes. */
get_zdata_lenz_index_entry_t424   ulint get_zdata_len() const {
425     return (mach_read_from_4(m_node + OFFSET_ZDATA_LEN));
426   }
427 
428   /** Set the compressed data length in bytes.
429   @param[in]  len  the compressed data length in bytes */
set_zdata_lenz_index_entry_t430   void set_zdata_len(ulint len) {
431     ut_ad(m_mtr != nullptr);
432     mlog_write_ulint(m_node + OFFSET_ZDATA_LEN, len, MLOG_4BYTES, m_mtr);
433   }
434 
435   /** Get the LOB version. */
get_lob_versionz_index_entry_t436   uint32_t get_lob_version() const {
437     return (mach_read_from_4(m_node + OFFSET_LOB_VERSION));
438   }
439 
440   /** Set the LOB version .
441   @param[in]  version  the lob version. */
set_lob_versionz_index_entry_t442   void set_lob_version(ulint version) {
443     ut_ad(m_mtr != nullptr);
444     mlog_write_ulint(m_node + OFFSET_LOB_VERSION, version, MLOG_4BYTES, m_mtr);
445   }
446 
447   /* The given entry becomes the old version of the current entry.
448   Move the version base node from old entry to current entry.
449   @param[in]  entry  the old entry */
450   void set_old_version(z_index_entry_t &entry);
451 
452   /** The current index entry points to a latest LOB page.  It may or
453   may not have older versions.  If older version is there, bring it
454   back to the index list from the versions list.  Then remove the
455   current entry from the index list.  Move the versions list from
456   current entry to older entry.
457   @param[in]	index	the index in which LOB exists.
458   @param[in]	trxid	The transaction identifier.
459   @param[in]	first	The first lob page containing index list
460                           and free list. */
461   fil_addr_t make_old_version_current(dict_index_t *index, trx_id_t trxid,
462                                       z_first_page_t &first);
463 
get_nodez_index_entry_t464   flst_node_t *get_node() { return (m_node); }
is_nullz_index_entry_t465   bool is_null() const { return (m_node == nullptr); }
466 
467   std::ostream &print(std::ostream &out) const;
468   std::ostream &print_pages(std::ostream &out) const;
469 
470   /** Load the page (in shared mode) whose number was cached.
471   @return	the buffer block of the page loaded. */
load_sz_index_entry_t472   buf_block_t *load_s() {
473     ut_ad(m_page_no != FIL_NULL);
474 
475     page_id_t page_id(dict_index_get_space(m_index), m_page_no);
476     page_size_t page_size(dict_table_page_size(m_index->table));
477     m_block = buf_page_get(page_id, page_size, RW_S_LATCH, m_mtr);
478     return (m_block);
479   }
480 
481   /** Load the given file address in s mode.
482   @param[in]	addr	the file address of the required node. */
load_sz_index_entry_t483   void load_s(fil_addr_t &addr) {
484     space_id_t space = dict_index_get_space(m_index);
485     const page_size_t page_size = dict_table_page_size(m_index->table);
486     m_node = fut_get_ptr(space, page_size, addr, RW_S_LATCH, m_mtr, &m_block);
487     m_page_no = m_block->get_page_no();
488   }
489 
490   /** Load the given file address in x mode.
491   @param[in]	addr	the file address of the required node. */
load_xz_index_entry_t492   void load_x(fil_addr_t &addr) {
493     space_id_t space = dict_index_get_space(m_index);
494     const page_size_t page_size = dict_table_page_size(m_index->table);
495     m_node = fut_get_ptr(space, page_size, addr, RW_X_LATCH, m_mtr, &m_block);
496     m_page_no = m_block->get_page_no();
497   }
498 
499   /** Read the given LOB index entry.
500   @param[in]	entry_mem	the LOB index entry. */
501   void read(z_index_entry_mem_t &entry_mem) const;
502 
503   /** Read the given LOB index entry and then commit the mtr.
504   @param[in]	entry_mem	the LOB index entry. */
read_and_commitz_index_entry_t505   void read_and_commit(z_index_entry_mem_t &entry_mem) {
506     read(entry_mem);
507     mtr_commit(m_mtr);
508     m_node = nullptr;
509   }
510 
511   /** Get the location of the current index entry. */
512   fil_addr_t get_self() const;
513 
514  private:
515   /** Move the version base node from current entry to the given entry.
516   @param[in]	entry	The index entry to which the version base
517                           node is moved to. */
518   void move_version_base_node(z_index_entry_t &entry);
519 
520   /** The file list node in a db page. This node is persisted. */
521   flst_node_t *m_node;
522 
523   /** A mini transaction. */
524   mtr_t *m_mtr;
525 
526   /** The index containing the LOB. */
527   dict_index_t *m_index;
528 
529   /** The buffer block in which this entry exists.  While reading data
530   from m_node, appropriate latches must be held on this block. */
531   buf_block_t *m_block;
532 
533   /** The page number in which this entry is available.  This
534   information will be cached and can be used to reload the page
535   conveniently. */
536   page_no_t m_page_no;
537 };
538 
539 inline std::ostream &operator<<(std::ostream &out, const z_index_entry_t &obj) {
540   return (obj.print(out));
541 }
542 
543 } /* namespace lob */
544 
545 #endif /* zlob0index_h */
546