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 lob0ins_h
27 #define lob0ins_h
28 
29 #include "lob0lob.h"
30 
31 namespace lob {
32 
33 /** This struct can hold BLOB routines/functions, and state variables,
34 that are common for compressed and uncompressed BLOB. */
35 struct BaseInserter {
36   /** Constructor.
37   @param[in]	ctx	blob operation context. */
BaseInserterBaseInserter38   BaseInserter(InsertContext *ctx)
39       : m_ctx(ctx),
40         m_err(DB_SUCCESS),
41         m_prev_page_no(ctx->get_page_no()),
42         m_cur_blob_block(nullptr),
43         m_cur_blob_page_no(FIL_NULL) {}
44 
45   /** Start the BLOB mtr.
46   @return pointer to the BLOB mtr. */
start_blob_mtrBaseInserter47   mtr_t *start_blob_mtr() {
48     mtr_start(&m_blob_mtr);
49     m_blob_mtr.set_log_mode(m_ctx->get_log_mode());
50     m_blob_mtr.set_flush_observer(m_ctx->get_flush_observer());
51     return (&m_blob_mtr);
52   }
53 
54   /** Allocate one BLOB page.
55   @return the allocated block of the BLOB page. */
56   buf_block_t *alloc_blob_page();
57 
58   /** Get the previous BLOB page frame.  This will return a BLOB page.
59   It should not be called for the first BLOB page, because it will not
60   have a previous BLOB page.
61   @return	the previous BLOB page frame. */
62   page_t *get_previous_blob_page();
63 
64   /** Get the previous BLOB page block.  This will return a BLOB block.
65   It should not be called for the first BLOB page, because it will not
66   have a previous BLOB page.
67   @return	the previous BLOB block. */
68   buf_block_t *get_previous_blob_block();
69 
70   /** Check if the index is SDI index
71   @return true if index is SDI index else false */
is_index_sdiBaseInserter72   bool is_index_sdi() { return (dict_index_is_sdi(m_ctx->index())); }
73 
74   /** Get the current BLOB page frame.
75   @return the current BLOB page frame. */
cur_pageBaseInserter76   page_t *cur_page() const { return (buf_block_get_frame(m_cur_blob_block)); }
77 
78  protected:
79   /** The BLOB operation context */
80   InsertContext *m_ctx;
81 
82   /** Success or failure status of the operation so far. */
83   dberr_t m_err;
84 
85   /** The mini trx used to write into blob pages */
86   mtr_t m_blob_mtr;
87 
88   /** The previous BLOB page number.  This is needed to maintain
89   the linked list of BLOB pages. */
90   page_no_t m_prev_page_no;
91 
92   /** The current BLOB buf_block_t object. */
93   buf_block_t *m_cur_blob_block;
94 
95   /** The current BLOB page number. */
96   page_no_t m_cur_blob_page_no;
97 };
98 
99 /** Insert or write an uncompressed BLOB */
100 class Inserter : private BaseInserter {
101  public:
102   /** Constructor.
103   @param[in]	ctx	blob operation context. */
Inserter(InsertContext * ctx)104   Inserter(InsertContext *ctx) : BaseInserter(ctx) {}
105 
106   /** Destructor. */
~Inserter()107   ~Inserter() {}
108 
109   /** Write all the BLOBs of the clustered index record.
110   @return DB_SUCCESS on success, error code on failure. */
111   dberr_t write();
112 
113   /** Write one blob field data.
114   @param[in]	blob_j	the blob field number
115   @return DB_SUCCESS on success, error code on failure. */
116   dberr_t write_one_blob(size_t blob_j);
117 
118   /** Write one blob field data.
119   @param[in]	blob_j	the blob field number
120   @return DB_SUCCESS on success, error code on failure. */
121   dberr_t write_one_small_blob(size_t blob_j);
122 
123   /** Write one blob page.  This function will be repeatedly called
124   with an increasing nth_blob_page to completely write a BLOB.
125   @param[in]	blob_j		the jth blob object of the record.
126   @param[in]	field		the big record field.
127   @param[in]	nth_blob_page	count of the BLOB page (starting from 1).
128   @return DB_SUCCESS or DB_FAIL. */
129   dberr_t write_single_blob_page(size_t blob_j, big_rec_field_t &field,
130                                  ulint nth_blob_page);
131 
132   /** Check if the BLOB operation has reported any errors.
133   @return	true if BLOB operation is successful, false otherwise. */
is_ok()134   bool is_ok() const { return (m_err == DB_SUCCESS); }
135 
136   /** Make the current page as next page of previous page.  In other
137   words, make the page m_cur_blob_page_no as the next page of page
138   m_prev_page_no. */
139   void set_page_next();
140 
141   /** Write the page type of the current BLOB page and also generate the
142   redo log record. */
log_page_type()143   void log_page_type() {
144     page_type_t page_type;
145     page_t *blob_page = cur_page();
146 
147     if (is_index_sdi()) {
148       page_type = FIL_PAGE_SDI_BLOB;
149     } else {
150       page_type = FIL_PAGE_TYPE_BLOB;
151     }
152 
153     mlog_write_ulint(blob_page + FIL_PAGE_TYPE, page_type, MLOG_2BYTES,
154                      &m_blob_mtr);
155   }
156 
157   /** Calculate the payload size of the BLOB page.
158   @return	payload size in bytes. */
payload()159   ulint payload() const {
160     const page_size_t page_size = m_ctx->page_size();
161     const ulint payload_size =
162         page_size.physical() - FIL_PAGE_DATA - LOB_HDR_SIZE - FIL_PAGE_DATA_END;
163     return (payload_size);
164   }
165 
166   /** Write contents into a single BLOB page.
167   @param[in]	field		the big record field. */
168   void write_into_single_page(big_rec_field_t &field);
169 
170   /** Write first blob page.
171   @param[in]	blob_j	the jth blob object of the record.
172   @param[in]	field	the big record field.
173   @return DB_SUCCESS on success. */
174   dberr_t write_first_page(size_t blob_j, big_rec_field_t &field);
175 
176  private:
177   /** The BLOB directory information. */
178   blob_dir_t m_dir;
179 
180   /** Data remaining to be written. */
181   ulint m_remaining;
182 };
183 
184 }  // namespace lob
185 
186 #endif /* lob0ins_h */
187