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 lob0zip_h
27 #define lob0zip_h
28
29 #include "lob0ins.h"
30
31 namespace lob {
32
33 /** Insert or write the compressed BLOB as a single zlib stream. */
34 class zInserter : private BaseInserter {
35 public:
36 /** Constructor.
37 @param[in] ctx blob operation context. */
zInserter(InsertContext * ctx)38 zInserter(InsertContext *ctx) : BaseInserter(ctx), m_heap(nullptr) {}
39
40 /** Destructor. */
41 ~zInserter();
42
43 /** Prepare to write a compressed BLOB. Setup the zlib
44 compression stream.
45 @return DB_SUCCESS on success, error code on failure. */
46 dberr_t prepare();
47
48 /** Write all the BLOBs of the clustered index record.
49 @return DB_SUCCESS on success, error code on failure. */
50 dberr_t write();
51
52 /** Write one blob field data.
53 @param[in] blob_j the blob field number
54 @return DB_SUCCESS on success, error code on failure. */
55 dberr_t write_one_blob(size_t blob_j);
56
57 /** Cleanup after completing the write of compressed BLOB.
58 @param[in] validate if true, validate all the
59 lob references. if false,
60 skip this validation.
61 @return DB_SUCCESS on success, error code on failure. */
62 dberr_t finish(bool validate = true) {
63 int ret = deflateEnd(&m_stream);
64 ut_ad(ret == Z_OK);
65 ut_ad(!validate || validate_blobrefs());
66
67 if (ret != Z_OK) {
68 m_err = DB_FAIL;
69 }
70 return (m_err);
71 }
72
73 /** Write the page type of the BLOB page and also generate the
74 redo log record.
75 @param[in] blob_page the BLOB page
76 @param[in] nth_blob_page the count of BLOB page from
77 the beginning of the BLOB. */
log_page_type(page_t * blob_page,ulint nth_blob_page)78 void log_page_type(page_t *blob_page, ulint nth_blob_page) {
79 page_type_t page_type;
80
81 if (is_index_sdi()) {
82 page_type = FIL_PAGE_SDI_ZBLOB;
83 } else if (nth_blob_page == 0) {
84 page_type = FIL_PAGE_TYPE_ZBLOB;
85 } else {
86 page_type = FIL_PAGE_TYPE_ZBLOB2;
87 }
88
89 mlog_write_ulint(blob_page + FIL_PAGE_TYPE, page_type, MLOG_2BYTES,
90 &m_blob_mtr);
91 }
92
93 /** Calculate the total number of pages needed to store
94 the given blobs */
calc_total_pages()95 ulint calc_total_pages() {
96 const page_size_t page_size = m_ctx->page_size();
97
98 /* Space available in compressed page to carry blob data */
99 const ulint payload_size_zip = page_size.physical() - FIL_PAGE_DATA;
100
101 const big_rec_t *vec = m_ctx->get_big_rec_vec();
102
103 ulint total_blob_pages = 0;
104 for (ulint i = 0; i < vec->n_fields; i++) {
105 total_blob_pages +=
106 static_cast<ulint>(
107 deflateBound(&m_stream, static_cast<uLong>(vec->fields[i].len)) +
108 payload_size_zip - 1) /
109 payload_size_zip;
110 }
111
112 return (total_blob_pages);
113 }
114
115 /** Write contents into a single BLOB page.
116 @return code as returned by zlib. */
117 int write_into_single_page();
118
119 /** Commit the BLOB mtr. */
commit_blob_mtr()120 void commit_blob_mtr() { mtr_commit(&m_blob_mtr); }
121
122 /** Write one blob page. This function will be repeatedly called
123 with an increasing nth_blob_page to completely write a BLOB.
124 @param[in] blob_j the jth blob object of the record.
125 @param[in] field the big record field.
126 @param[in] nth_blob_page count of the BLOB page (starting from 1).
127 @return code as returned by the zlib. */
128 int write_single_blob_page(size_t blob_j, big_rec_field_t &field,
129 ulint nth_blob_page);
130
131 /** Write first blob page.
132 @param[in] blob_j the jth blob object of the record.
133 @param[in] field the big record field.
134 @return code as returned by the zlib. */
135 int write_first_page(size_t blob_j, big_rec_field_t &field);
136
137 /** Verify that all pointers to externally stored columns in the record
138 is be valid. If validation fails, this function doesn't return.
139 @return true if valid. */
validate_blobrefs()140 bool validate_blobrefs() const {
141 const ulint *offsets = m_ctx->get_offsets();
142
143 for (ulint i = 0; i < rec_offs_n_fields(offsets); i++) {
144 if (!rec_offs_nth_extern(offsets, i)) {
145 continue;
146 }
147
148 byte *field_ref = btr_rec_get_field_ref(m_ctx->rec(), offsets, i);
149
150 ref_t blobref(field_ref);
151
152 /* The pointer must not be zero if the operation
153 succeeded. */
154 ut_a(!blobref.is_null() || m_err != DB_SUCCESS);
155
156 /* The column must not be disowned by this record. */
157 ut_a(blobref.is_owner());
158 }
159 return (true);
160 }
161
162 /** For the given blob field, update its length in the blob reference
163 which is available in the clustered index record.
164 @param[in] field the concerned blob field. */
165 void update_length_in_blobref(big_rec_field_t &field);
166
167 /** Make the current page as next page of previous page. In other
168 words, make the page m_cur_blob_page_no as the next page
169 (FIL_PAGE_NEXT) of page m_prev_page_no.
170 @return DB_SUCCESS on success, or error code on failure. */
171 dberr_t set_page_next();
172
173 /** Write one small blob field data. Refer to ref_t to determine
174 the definition of small blob.
175 @param[in] blob_j the blob field number
176 @return DB_SUCCESS on success, error code on failure. */
177 dberr_t write_one_small_blob(size_t blob_j);
178
179 private:
180 /** Add the BLOB page information to the directory
181 @param[in] page_info BLOB page information. */
add_to_blob_dir(const blob_page_info_t & page_info)182 void add_to_blob_dir(const blob_page_info_t &page_info) {
183 m_dir.add(page_info);
184 }
185
186 mem_heap_t *m_heap;
187 z_stream m_stream;
188
189 /** The BLOB directory information. */
190 blob_dir_t m_dir;
191 };
192
~zInserter()193 inline zInserter::~zInserter() {
194 if (m_heap != nullptr) {
195 mem_heap_free(m_heap);
196 }
197 }
198
199 } // namespace lob
200
201 #endif // lob0zip_h
202