1 /*****************************************************************************
2
3 Copyright (c) 2016, 2018, 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
27 #include <list>
28 #include "btr0btr.h"
29 #include "buf0buf.h"
30 #include "dict0dict.h"
31 #include "lob0first.h"
32 #include "lob0index.h"
33 #include "lob0lob.h"
34 #include "table.h"
35 #include "trx0trx.h"
36
37 namespace lob {
38
39 /** Allocate one LOB page.
40 @param[in] index the index in which LOB exists.
41 @param[in] lob_mtr the mini-transaction context.
42 @param[in] hint the hint page number for allocation.
43 @param[in] bulk true if operation is OPCODE_INSERT_BULK,
44 false otherwise.
45 @return the allocated block of the BLOB page or nullptr. */
alloc_lob_page(dict_index_t * index,mtr_t * lob_mtr,page_no_t hint,bool bulk)46 buf_block_t *alloc_lob_page(dict_index_t *index, mtr_t *lob_mtr, page_no_t hint,
47 bool bulk) {
48 ulint r_extents;
49 mtr_t mtr_bulk;
50 mtr_t *alloc_mtr;
51 buf_block_t *block = nullptr;
52
53 space_id_t space_id = dict_index_get_space(index);
54
55 ut_ad(fsp_check_tablespace_size(space_id));
56
57 if (bulk) {
58 mtr_start(&mtr_bulk);
59 alloc_mtr = &mtr_bulk;
60 } else {
61 alloc_mtr = lob_mtr;
62 }
63
64 bool success =
65 fsp_reserve_free_extents(&r_extents, space_id, 1, FSP_BLOB, alloc_mtr, 1);
66
67 DBUG_EXECUTE_IF("innodb_alloc_lob_page_failed", success = false;);
68
69 if (!success) {
70 if (bulk) {
71 ut_ad(alloc_mtr == &mtr_bulk);
72 alloc_mtr->commit();
73 }
74 return (nullptr);
75 }
76
77 block = btr_page_alloc(index, hint, FSP_NO_DIR, 0, alloc_mtr, lob_mtr);
78
79 fil_space_release_free_extents(space_id, r_extents);
80
81 if (bulk) {
82 ut_ad(alloc_mtr == &mtr_bulk);
83 alloc_mtr->commit();
84 }
85
86 return (block);
87 }
88
get_affected_index_entries(const ref_t & ref,dict_index_t * index,const Binary_diff & bdiff,List_iem_t & entries,mtr_t * mtr)89 dberr_t get_affected_index_entries(const ref_t &ref, dict_index_t *index,
90 const Binary_diff &bdiff,
91 List_iem_t &entries, mtr_t *mtr) {
92 page_no_t first_page_no = ref.page_no();
93 space_id_t space_id = ref.space_id();
94 const page_size_t page_size = dict_table_page_size(index->table);
95 const page_id_t first_page_id(space_id, first_page_no);
96 size_t offset = bdiff.offset();
97 ulint data_len = 0;
98
99 if (!dict_table_has_atomic_blobs(index->table)) {
100 /* For compact and redundant row format, remove the local
101 prefix length from the offset. */
102
103 ut_ad(offset >= DICT_ANTELOPE_MAX_INDEX_COL_LEN);
104 offset -= DICT_ANTELOPE_MAX_INDEX_COL_LEN;
105 }
106
107 /* Currently only working with uncompressed LOB */
108 ut_ad(!page_size.is_compressed());
109
110 first_page_t first_page(mtr, index);
111 first_page.load_x(first_page_id, page_size);
112
113 #ifdef UNIV_DEBUG
114 {
115 page_type_t page_type = first_page.get_page_type();
116 ut_ad(page_type == FIL_PAGE_TYPE_LOB_FIRST);
117 }
118 #endif /* UNIV_DEBUG */
119
120 /* Obtain the first index entry. */
121 flst_base_node_t *base_node = first_page.index_list();
122 fil_addr_t node_loc = flst_get_first(base_node, mtr);
123
124 buf_block_t *block = nullptr;
125 index_entry_t entry(mtr, index);
126
127 while (!fil_addr_is_null(node_loc)) {
128 if (block == nullptr) {
129 block = entry.load_x(node_loc);
130 } else if (block->page.id.page_no() != node_loc.page) {
131 block = entry.load_x(node_loc);
132 } else {
133 /* Next entry in the same page. */
134 ut_ad(block == entry.get_block());
135 entry.reset(node_loc);
136 }
137
138 /* Get the amount of data */
139 data_len = entry.get_data_len();
140
141 if (offset < data_len) {
142 index_entry_mem_t entry_mem;
143 entry.read(entry_mem);
144 entries.push_back(entry_mem);
145
146 size_t remain = data_len - offset;
147
148 if (bdiff.length() > remain) {
149 block = entry.next();
150
151 if (block != nullptr) {
152 entry.read(entry_mem);
153 entries.push_back(entry_mem);
154 }
155 }
156
157 break;
158 }
159
160 offset -= data_len;
161
162 /* The next node should not be the same as the current node. */
163 ut_ad(!node_loc.is_equal(entry.get_next()));
164
165 node_loc = entry.get_next();
166 }
167
168 ut_ad(entries.size() == 1 || entries.size() == 2);
169
170 return (DB_SUCCESS);
171 }
172
173 /** Get information about the given LOB.
174 @param[in] ref the LOB reference.
175 @param[in] index the clustered index to which LOB belongs.
176 @param[out] lob_version the lob version number.
177 @param[out] last_trx_id the trx_id that modified the lob last.
178 @param[out] last_undo_no the trx undo no that modified the lob last.
179 @param[out] page_type the page type of first lob page.
180 @param[in] mtr the mini transaction context.
181 @return always returns DB_SUCCESS. */
get_info(ref_t & ref,dict_index_t * index,ulint & lob_version,trx_id_t & last_trx_id,undo_no_t & last_undo_no,page_type_t & page_type,mtr_t * mtr)182 dberr_t get_info(ref_t &ref, dict_index_t *index, ulint &lob_version,
183 trx_id_t &last_trx_id, undo_no_t &last_undo_no,
184 page_type_t &page_type, mtr_t *mtr) {
185 page_no_t first_page_no = ref.page_no();
186 space_id_t space_id = ref.space_id();
187 const page_size_t page_size = dict_table_page_size(index->table);
188 const page_id_t first_page_id(space_id, first_page_no);
189
190 /* Currently only working with uncompressed LOB */
191 ut_ad(!page_size.is_compressed());
192
193 first_page_t first_page(mtr, index);
194 first_page.load_x(first_page_id, page_size);
195
196 page_type = first_page.get_page_type();
197 lob_version = first_page.get_lob_version();
198 last_trx_id = first_page.get_last_trx_id();
199 last_undo_no = first_page.get_last_trx_undo_no();
200
201 return (DB_SUCCESS);
202 }
203
204 } /* namespace lob */
205