1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2018, MariaDB Corporation. |
5 | |
6 | This program is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free Software |
8 | Foundation; version 2 of the License. |
9 | |
10 | This program is distributed in the hope that it will be useful, but WITHOUT |
11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU General Public License along with |
15 | this program; if not, write to the Free Software Foundation, Inc., |
16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
17 | |
18 | *****************************************************************************/ |
19 | |
20 | /**************************************************//** |
21 | @file include/read0types.h |
22 | Cursor read |
23 | |
24 | Created 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 | */ |
50 | class 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 | |
73 | public: |
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; |
100 | loop: |
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 | |
261 | private: |
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 | |