1/*****************************************************************************
2
3Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2018, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/**************************************************//**
21@file include/read0types.h
22Cursor read
23
24Created 2/16/1997 Heikki Tuuri
25*******************************************************/
26
27#ifndef read0types_h
28#define read0types_h
29
30#include <algorithm>
31#include "dict0mem.h"
32
33#include "trx0types.h"
34
35
36/** View is not visible to purge thread. */
37#define READ_VIEW_STATE_CLOSED 0
38
39/** View is being opened, purge thread must wait for state change. */
40#define READ_VIEW_STATE_SNAPSHOT 1
41
42/** View is visible to purge thread. */
43#define READ_VIEW_STATE_OPEN 2
44
45
46/**
47 Read view lists the trx ids of those transactions for which a consistent read
48 should not see the modifications to the database.
49*/
50class ReadView
51{
52 /**
53 View state.
54
55 It is not defined as enum as it has to be updated using atomic operations.
56 Possible values are READ_VIEW_STATE_CLOSED, READ_VIEW_STATE_SNAPSHOT and
57 READ_VIEW_STATE_OPEN.
58
59 Possible state transfers...
60
61 Start view open:
62 READ_VIEW_STATE_CLOSED -> READ_VIEW_STATE_SNAPSHOT
63
64 Complete view open:
65 READ_VIEW_STATE_SNAPSHOT -> READ_VIEW_STATE_OPEN
66
67 Close view:
68 READ_VIEW_STATE_OPEN -> READ_VIEW_STATE_CLOSED
69 */
70 int32_t m_state;
71
72
73public:
74 ReadView(): m_state(READ_VIEW_STATE_CLOSED), m_low_limit_id(0) {}
75
76
77 /**
78 Copy state from another view.
79
80 This method is used to find min(m_low_limit_no), min(m_low_limit_id) and
81 all transaction ids below min(m_low_limit_id). These values effectively
82 form oldest view.
83
84 @param other view to copy from
85 */
86 void copy(const ReadView &other)
87 {
88 ut_ad(&other != this);
89 if (m_low_limit_no > other.m_low_limit_no)
90 m_low_limit_no= other.m_low_limit_no;
91 if (m_low_limit_id > other.m_low_limit_id)
92 m_low_limit_id= other.m_low_limit_id;
93
94 trx_ids_t::iterator dst= m_ids.begin();
95 for (trx_ids_t::const_iterator src= other.m_ids.begin();
96 src != other.m_ids.end(); src++)
97 {
98 if (*src >= m_low_limit_id)
99 break;
100loop:
101 if (dst == m_ids.end())
102 {
103 m_ids.push_back(*src);
104 dst= m_ids.end();
105 continue;
106 }
107 if (*dst < *src)
108 {
109 dst++;
110 goto loop;
111 }
112 else if (*dst > *src)
113 dst= m_ids.insert(dst, *src) + 1;
114 }
115 m_ids.erase(std::lower_bound(dst, m_ids.end(), m_low_limit_id),
116 m_ids.end());
117
118 m_up_limit_id= m_ids.empty() ? m_low_limit_id : m_ids.front();
119 ut_ad(m_up_limit_id <= m_low_limit_id);
120 }
121
122
123 /**
124 Opens a read view where exactly the transactions serialized before this
125 point in time are seen in the view.
126
127 View becomes visible to purge thread.
128
129 @param[in,out] trx transaction
130 */
131 void open(trx_t *trx);
132
133
134 /**
135 Closes the view.
136
137 View becomes not visible to purge thread.
138 */
139 void close()
140 {
141 ut_ad(m_state == READ_VIEW_STATE_CLOSED ||
142 m_state == READ_VIEW_STATE_OPEN);
143 if (m_state == READ_VIEW_STATE_OPEN)
144 my_atomic_store32_explicit(&m_state, READ_VIEW_STATE_CLOSED,
145 MY_MEMORY_ORDER_RELAXED);
146 }
147
148
149 /** m_state getter for trx_sys::clone_oldest_view() trx_sys::size(). */
150 int32_t get_state() const
151 {
152 return my_atomic_load32_explicit(const_cast<int32*>(&m_state),
153 MY_MEMORY_ORDER_ACQUIRE);
154 }
155
156
157 /**
158 Returns true if view is open.
159
160 Only used by view owner thread, thus we can omit atomic operations.
161 */
162 bool is_open() const
163 {
164 ut_ad(m_state == READ_VIEW_STATE_OPEN ||
165 m_state == READ_VIEW_STATE_CLOSED);
166 return m_state == READ_VIEW_STATE_OPEN;
167 }
168
169
170 /**
171 Creates a snapshot where exactly the transactions serialized before this
172 point in time are seen in the view.
173
174 @param[in,out] trx transaction
175 */
176 inline void snapshot(trx_t *trx);
177
178
179 /**
180 Sets the creator transaction id.
181
182 This should be set only for views created by RW transactions.
183 */
184 void set_creator_trx_id(trx_id_t id)
185 {
186 ut_ad(id > 0);
187 ut_ad(m_creator_trx_id == 0);
188 m_creator_trx_id= id;
189 }
190
191
192 /** Check whether transaction id is valid.
193 @param[in] id transaction id to check
194 @param[in] name table name */
195 static void check_trx_id_sanity(
196 trx_id_t id,
197 const table_name_t& name);
198
199 /** Check whether the changes by id are visible.
200 @param[in] id transaction id to check against the view
201 @param[in] name table name
202 @return whether the view sees the modifications of id. */
203 bool changes_visible(
204 trx_id_t id,
205 const table_name_t& name) const
206 MY_ATTRIBUTE((warn_unused_result))
207 {
208 if (id < m_up_limit_id || id == m_creator_trx_id) {
209
210 return(true);
211 }
212
213 check_trx_id_sanity(id, name);
214
215 if (id >= m_low_limit_id) {
216
217 return(false);
218
219 } else if (m_ids.empty()) {
220
221 return(true);
222 }
223
224 return(!std::binary_search(m_ids.begin(), m_ids.end(), id));
225 }
226
227 /**
228 @param id transaction to check
229 @return true if view sees transaction id */
230 bool sees(trx_id_t id) const
231 {
232 return(id < m_up_limit_id);
233 }
234
235 /**
236 Write the limits to the file.
237 @param file file to write to */
238 void print_limits(FILE* file) const
239 {
240 fprintf(file,
241 "Trx read view will not see trx with"
242 " id >= " TRX_ID_FMT ", sees < " TRX_ID_FMT "\n",
243 m_low_limit_id, m_up_limit_id);
244 }
245
246 /**
247 @return the low limit no */
248 trx_id_t low_limit_no() const
249 {
250 return(m_low_limit_no);
251 }
252
253 /**
254 @return the low limit id */
255 trx_id_t low_limit_id() const
256 {
257 return(m_low_limit_id);
258 }
259
260
261private:
262 /** The read should not see any transaction with trx id >= this
263 value. In other words, this is the "high water mark". */
264 trx_id_t m_low_limit_id;
265
266 /** The read should see all trx ids which are strictly
267 smaller (<) than this value. In other words, this is the
268 low water mark". */
269 trx_id_t m_up_limit_id;
270
271 /** trx id of creating transaction, set to TRX_ID_MAX for free
272 views. */
273 trx_id_t m_creator_trx_id;
274
275 /** Set of RW transactions that was active when this snapshot
276 was taken */
277 trx_ids_t m_ids;
278
279 /** The view does not need to see the undo logs for transactions
280 whose transaction number is strictly smaller (<) than this value:
281 they can be removed in purge if not needed by other views */
282 trx_id_t m_low_limit_no;
283};
284
285#endif
286