1 /***************************************************************************** 2 3 Copyright (c) 2017, 2018, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License, version 2.0, 7 as published by the Free Software Foundation. 8 9 This program is also distributed with certain software (including 10 but not limited to OpenSSL) that is licensed under separate terms, 11 as designated in a particular file or component or in included license 12 documentation. The authors of MySQL hereby grant you an additional 13 permission to link the program and your derivative works with the 14 separately licensed software that they have included with MySQL. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License, version 2.0, for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 *****************************************************************************/ 26 27 /** @file include/lob0undo.h 28 Undo logging small changes to BLOBs. */ 29 30 #ifndef lob0undo_h 31 #define lob0undo_h 32 33 #include <list> 34 #include "dict0mem.h" 35 #include "mem0mem.h" 36 #include "univ.i" 37 38 namespace lob { 39 40 /** Undo information about LOB data alone without including LOB index. */ 41 struct undo_data_t { 42 /** Apply the undo information to the given LOB. 43 @param[in] index clustered index containing the LOB. 44 @param[in] lob_mem LOB on which the given undo will be 45 applied. 46 @param[in] len length of LOB. 47 @param[in] lob_version lob version number 48 @param[in] first_page_no the first page number of lob */ 49 void apply(dict_index_t *index, byte *lob_mem, size_t len, size_t lob_version, 50 page_no_t first_page_no); 51 52 /** The LOB first page number. */ 53 page_no_t m_page_no = FIL_NULL; 54 55 /** The LOB version number on which this undo should be applied. */ 56 ulint m_version = 0; 57 58 /** The offset within LOB where partial update happened. */ 59 ulint m_offset = 0; 60 61 /** The length of the modification. */ 62 ulint m_length = 0; 63 64 /** Changes to the LOB data. */ 65 byte *m_old_data = nullptr; 66 67 /** Copy the old data from the undo page into this object. 68 @param[in] undo_ptr the pointer into the undo log record. 69 @param[in] len length of the old data. 70 @return pointer past the old data. */ 71 const byte *copy_old_data(const byte *undo_ptr, ulint len); 72 73 /** Free allocated memory for old data. */ 74 void destroy(); 75 76 std::ostream &print(std::ostream &out) const; 77 }; 78 79 inline std::ostream &operator<<(std::ostream &out, const undo_data_t &obj) { 80 return (obj.print(out)); 81 } 82 83 /** Container to hold a sequence of undo log records containing modification 84 of BLOBs. */ 85 struct undo_seq_t { 86 /** Constructor. 87 @param[in] field_no the field number of LOB.*/ undo_seq_tundo_seq_t88 undo_seq_t(ulint field_no) : m_field_no(field_no), m_undo_list(nullptr) {} 89 90 /** Apply the undo log records on the given LOB in memory. 91 @param[in] index the clustered index to which LOB belongs. 92 @param[in] lob the BLOB in memory. 93 @param[in] len the length of BLOB in memory. 94 @param[in] lob_version the LOB version number. 95 @param[in] first_page_no the first page number of BLOB.*/ applyundo_seq_t96 void apply(dict_index_t *index, byte *lob, size_t len, size_t lob_version, 97 page_no_t first_page_no) { 98 if (m_undo_list != nullptr) { 99 for (auto iter = m_undo_list->begin(); iter != m_undo_list->end(); 100 ++iter) { 101 iter->apply(index, lob, len, lob_version, first_page_no); 102 } 103 } 104 } 105 106 /** Get the field number of BLOB. 107 @return the field number of BLOB. */ get_field_noundo_seq_t108 ulint get_field_no() const { return (m_field_no); } 109 110 /** Append the given undo log record to the end of container. 111 @param[in] u1 the undo log record information. */ push_backundo_seq_t112 void push_back(undo_data_t &u1) { 113 if (m_undo_list == nullptr) { 114 m_undo_list = UT_NEW_NOKEY(std::list<undo_data_t>()); 115 } 116 m_undo_list->push_back(u1); 117 } 118 119 /** Destroy the contents of this undo sequence list. */ destroyundo_seq_t120 void destroy() { 121 if (m_undo_list != nullptr) { 122 std::for_each(m_undo_list->begin(), m_undo_list->end(), 123 [](undo_data_t &obj) { obj.destroy(); }); 124 m_undo_list->clear(); 125 UT_DELETE(m_undo_list); 126 m_undo_list = nullptr; 127 } 128 } 129 130 /** Check if any undo log exists to apply. */ existsundo_seq_t131 bool exists() const { 132 return (m_undo_list == nullptr ? false : !m_undo_list->empty()); 133 } 134 135 ulint m_field_no; 136 137 private: 138 std::list<undo_data_t> *m_undo_list = nullptr; 139 }; 140 141 /** The list of modifications to be applied on LOBs to get older versions. 142 Given a field number, it should be able to obtain the list of undo 143 information. */ 144 struct undo_vers_t { 145 public: 146 /** Get the undo log sequence object for the given field number, which 147 represents one blob. 148 @param[in] field_no the field number of the blob. 149 @return the undo sequence object or nullptr. */ get_undo_sequence_if_existsundo_vers_t150 undo_seq_t *get_undo_sequence_if_exists(ulint field_no) { 151 if (m_versions == nullptr) { 152 return (nullptr); 153 } else { 154 for (auto iter = m_versions->begin(); iter != m_versions->end(); ++iter) { 155 if ((*iter)->get_field_no() == field_no) { 156 return (*iter); 157 } 158 } 159 } 160 return (nullptr); 161 } 162 163 /** Get the undo log sequence object for the given field number, which 164 represents one blob. The undo sequence object is allocated if it does 165 not exist. 166 @param[in] field_no the field number of the blob. 167 @return the undo sequence object. */ get_undo_sequenceundo_vers_t168 undo_seq_t *get_undo_sequence(ulint field_no) { 169 if (m_versions == nullptr) { 170 m_versions = UT_NEW_NOKEY(std::list<undo_seq_t *>()); 171 } else { 172 for (auto iter = m_versions->begin(); iter != m_versions->end(); ++iter) { 173 if ((*iter)->get_field_no() == field_no) { 174 return (*iter); 175 } 176 } 177 } 178 179 undo_seq_t *seq = UT_NEW_NOKEY(undo_seq_t(field_no)); 180 m_versions->push_back(seq); 181 182 return (seq); 183 } 184 185 /** Empty the collected LOB undo information from cache. */ resetundo_vers_t186 void reset() { 187 if (m_versions != nullptr) { 188 for (auto iter = m_versions->begin(); iter != m_versions->end(); ++iter) { 189 (*iter)->destroy(); 190 UT_DELETE(*iter); 191 } 192 m_versions->clear(); 193 } 194 } 195 196 /** Apply the undo log record on the given LOB in memory. 197 @param[in] clust_index the clust index to which LOB belongs. 198 @param[in] field_no the field number of the LOB. 199 @param[in] lob the LOB data. 200 @param[in] len the length of LOB. 201 @param[in] lob_version LOB version number. 202 @param[in] first_page the first page number of LOB.*/ applyundo_vers_t203 void apply(dict_index_t *clust_index, ulint field_no, byte *lob, size_t len, 204 size_t lob_version, page_no_t first_page) { 205 undo_seq_t *seq = get_undo_sequence_if_exists(field_no); 206 207 if (seq != nullptr) { 208 seq->apply(clust_index, lob, len, lob_version, first_page); 209 } 210 } 211 212 /** Destroy the accumulated undo_seq_t objects. */ destroyundo_vers_t213 void destroy() { 214 if (m_versions != nullptr) { 215 reset(); 216 UT_DELETE(m_versions); 217 m_versions = nullptr; 218 } 219 } 220 221 /** Check if the undo contained older versions. 222 @return true if there are no older versions, false otherwise. */ is_emptyundo_vers_t223 bool is_empty() const { return (m_versions->empty()); } 224 225 /** Destructor to free the resources. */ ~undo_vers_tundo_vers_t226 ~undo_vers_t() { destroy(); } 227 228 private: 229 /** Maintain a list of undo_seq_t objects. */ 230 std::list<undo_seq_t *> *m_versions = nullptr; 231 }; 232 233 } /* namespace lob */ 234 235 #endif /* lob0undo_h */ 236