641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
1 |
/*****************************************************************************
|
2 |
||
1999.6.1
by kalebral at gmail
update Copyright strings to a more common format to help with creating the master debian copyright file |
3 |
Copyright (C) 1997, 2010, Innobase Oy. All Rights Reserved.
|
641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
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 as published by the Free Software
|
|
7 |
Foundation; version 2 of the License.
|
|
8 |
||
9 |
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
10 |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
11 |
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
12 |
||
13 |
You should have received a copy of the GNU General Public License along with
|
|
1802.10.2
by Monty Taylor
Update all of the copyright headers to include the correct address. |
14 |
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
15 |
St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
16 |
|
17 |
*****************************************************************************/
|
|
18 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
19 |
/**************************************************//**
|
20 |
@file row/row0purge.c
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
21 |
Purge obsolete records
|
22 |
||
23 |
Created 3/14/1997 Heikki Tuuri
|
|
24 |
*******************************************************/
|
|
25 |
||
26 |
#include "row0purge.h" |
|
27 |
||
28 |
#ifdef UNIV_NONINL
|
|
29 |
#include "row0purge.ic" |
|
30 |
#endif
|
|
31 |
||
32 |
#include "fsp0fsp.h" |
|
33 |
#include "mach0data.h" |
|
34 |
#include "trx0rseg.h" |
|
35 |
#include "trx0trx.h" |
|
36 |
#include "trx0roll.h" |
|
37 |
#include "trx0undo.h" |
|
38 |
#include "trx0purge.h" |
|
39 |
#include "trx0rec.h" |
|
40 |
#include "que0que.h" |
|
41 |
#include "row0row.h" |
|
42 |
#include "row0upd.h" |
|
43 |
#include "row0vers.h" |
|
44 |
#include "row0mysql.h" |
|
45 |
#include "log0log.h" |
|
46 |
||
1819.9.13
by Inaam Rana
Merge Revision revid:inaam.rana@oracle.com-20100610135811-1jxs81q050wpabyc from MySQL InnoDB |
47 |
/*************************************************************************
|
1819.9.12
by Inaam Rana
Merge Revision revid:inaam.rana@oracle.com-20100608181408-c5xsjlom5olr4mxt from MySQL InnoDB |
48 |
IMPORTANT NOTE: Any operation that generates redo MUST check that there
|
49 |
is enough space in the redo log before for that operation. This is
|
|
50 |
done by calling log_free_check(). The reason for checking the
|
|
51 |
availability of the redo log space before the start of the operation is
|
|
52 |
that we MUST not hold any synchonization objects when performing the
|
|
53 |
check.
|
|
54 |
If you make a change in this module make sure that no codepath is
|
|
55 |
introduced where a call to log_free_check() is bypassed. */
|
|
56 |
||
1819.9.25
by Inaam Rana, Stewart Smith
Merge Revision revid:inaam.rana@oracle.com-20100621155209-1pu7nwq05x7tbfoo from MySQL InnoDB |
57 |
/*************************************************************************
|
58 |
IMPORTANT NOTE: Any operation that generates redo MUST check that there
|
|
59 |
is enough space in the redo log before for that operation. This is
|
|
60 |
done by calling log_free_check(). The reason for checking the
|
|
61 |
availability of the redo log space before the start of the operation is
|
|
62 |
that we MUST not hold any synchonization objects when performing the
|
|
63 |
check.
|
|
64 |
If you make a change in this module make sure that no codepath is
|
|
65 |
introduced where a call to log_free_check() is bypassed. */
|
|
66 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
67 |
/********************************************************************//**
|
68 |
Creates a purge node to a query graph.
|
|
69 |
@return own: purge node */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
70 |
UNIV_INTERN
|
71 |
purge_node_t* |
|
72 |
row_purge_node_create( |
|
73 |
/*==================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
74 |
que_thr_t* parent, /*!< in: parent node, i.e., a thr node */ |
75 |
mem_heap_t* heap) /*!< in: memory heap where created */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
76 |
{
|
77 |
purge_node_t* node; |
|
78 |
||
79 |
ut_ad(parent && heap); |
|
80 |
||
2023.3.14
by Monty Taylor
More casting. |
81 |
node = static_cast<purge_node_t *>(mem_heap_alloc(heap, sizeof(purge_node_t))); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
82 |
|
83 |
node->common.type = QUE_NODE_PURGE; |
|
84 |
node->common.parent = parent; |
|
85 |
||
86 |
node->heap = mem_heap_create(256); |
|
87 |
||
88 |
return(node); |
|
89 |
}
|
|
90 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
91 |
/***********************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
92 |
Repositions the pcur in the purge node on the clustered index record,
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
93 |
if found.
|
94 |
@return TRUE if the record was found */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
95 |
static
|
96 |
ibool
|
|
97 |
row_purge_reposition_pcur( |
|
98 |
/*======================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
99 |
ulint mode, /*!< in: latching mode */ |
100 |
purge_node_t* node, /*!< in: row purge node */ |
|
101 |
mtr_t* mtr) /*!< in: mtr */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
102 |
{
|
103 |
ibool found; |
|
104 |
||
105 |
if (node->found_clust) { |
|
106 |
found = btr_pcur_restore_position(mode, &(node->pcur), mtr); |
|
107 |
||
108 |
return(found); |
|
109 |
}
|
|
110 |
||
111 |
found = row_search_on_row_ref(&(node->pcur), mode, node->table, |
|
112 |
node->ref, mtr); |
|
113 |
node->found_clust = found; |
|
114 |
||
115 |
if (found) { |
|
116 |
btr_pcur_store_position(&(node->pcur), mtr); |
|
117 |
}
|
|
118 |
||
119 |
return(found); |
|
120 |
}
|
|
121 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
122 |
/***********************************************************//**
|
123 |
Removes a delete marked clustered index record if possible.
|
|
124 |
@return TRUE if success, or if not found, or if modified after the
|
|
125 |
delete marking */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
126 |
static
|
127 |
ibool
|
|
128 |
row_purge_remove_clust_if_poss_low( |
|
129 |
/*===============================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
130 |
purge_node_t* node, /*!< in: row purge node */ |
131 |
ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
132 |
{
|
133 |
dict_index_t* index; |
|
134 |
btr_pcur_t* pcur; |
|
135 |
btr_cur_t* btr_cur; |
|
136 |
ibool success; |
|
137 |
ulint err; |
|
138 |
mtr_t mtr; |
|
139 |
rec_t* rec; |
|
140 |
mem_heap_t* heap = NULL; |
|
141 |
ulint offsets_[REC_OFFS_NORMAL_SIZE]; |
|
142 |
rec_offs_init(offsets_); |
|
143 |
||
144 |
index = dict_table_get_first_index(node->table); |
|
145 |
||
146 |
pcur = &(node->pcur); |
|
147 |
btr_cur = btr_pcur_get_btr_cur(pcur); |
|
148 |
||
1819.9.12
by Inaam Rana
Merge Revision revid:inaam.rana@oracle.com-20100608181408-c5xsjlom5olr4mxt from MySQL InnoDB |
149 |
log_free_check(); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
150 |
mtr_start(&mtr); |
151 |
||
152 |
success = row_purge_reposition_pcur(mode, node, &mtr); |
|
153 |
||
154 |
if (!success) { |
|
155 |
/* The record is already removed */
|
|
156 |
||
157 |
btr_pcur_commit_specify_mtr(pcur, &mtr); |
|
158 |
||
159 |
return(TRUE); |
|
160 |
}
|
|
161 |
||
162 |
rec = btr_pcur_get_rec(pcur); |
|
163 |
||
1819.9.31
by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB |
164 |
if (node->roll_ptr != row_get_rec_roll_ptr( |
165 |
rec, index, rec_get_offsets(rec, index, offsets_, |
|
166 |
ULINT_UNDEFINED, &heap))) { |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
167 |
if (UNIV_LIKELY_NULL(heap)) { |
168 |
mem_heap_free(heap); |
|
169 |
}
|
|
170 |
/* Someone else has modified the record later: do not remove */
|
|
171 |
btr_pcur_commit_specify_mtr(pcur, &mtr); |
|
172 |
||
173 |
return(TRUE); |
|
174 |
}
|
|
175 |
||
176 |
if (UNIV_LIKELY_NULL(heap)) { |
|
177 |
mem_heap_free(heap); |
|
178 |
}
|
|
179 |
||
180 |
if (mode == BTR_MODIFY_LEAF) { |
|
181 |
success = btr_cur_optimistic_delete(btr_cur, &mtr); |
|
182 |
} else { |
|
183 |
ut_ad(mode == BTR_MODIFY_TREE); |
|
641.2.1
by Monty Taylor
InnoDB Plugin 1.0.2 |
184 |
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, |
185 |
RB_NONE, &mtr); |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
186 |
|
187 |
if (err == DB_SUCCESS) { |
|
188 |
success = TRUE; |
|
189 |
} else if (err == DB_OUT_OF_FILE_SPACE) { |
|
190 |
success = FALSE; |
|
191 |
} else { |
|
192 |
ut_error; |
|
193 |
}
|
|
194 |
}
|
|
195 |
||
196 |
btr_pcur_commit_specify_mtr(pcur, &mtr); |
|
197 |
||
198 |
return(success); |
|
199 |
}
|
|
200 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
201 |
/***********************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
202 |
Removes a clustered index record if it has not been modified after the delete
|
203 |
marking. */
|
|
204 |
static
|
|
205 |
void
|
|
206 |
row_purge_remove_clust_if_poss( |
|
207 |
/*===========================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
208 |
purge_node_t* node) /*!< in: row purge node */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
209 |
{
|
210 |
ibool success; |
|
211 |
ulint n_tries = 0; |
|
212 |
||
213 |
/* fputs("Purge: Removing clustered record\n", stderr); */
|
|
214 |
||
215 |
success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_LEAF); |
|
216 |
if (success) { |
|
217 |
||
218 |
return; |
|
219 |
}
|
|
220 |
retry: |
|
221 |
success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_TREE); |
|
222 |
/* The delete operation may fail if we have little
|
|
223 |
file space left: TODO: easiest to crash the database
|
|
224 |
and restart with more file space */
|
|
225 |
||
226 |
if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) { |
|
227 |
n_tries++; |
|
228 |
||
229 |
os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME); |
|
230 |
||
231 |
goto retry; |
|
232 |
}
|
|
233 |
||
234 |
ut_a(success); |
|
235 |
}
|
|
236 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
237 |
/***********************************************************//**
|
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
238 |
Determines if it is possible to remove a secondary index entry.
|
239 |
Removal is possible if the secondary index entry does not refer to any
|
|
240 |
not delete marked version of a clustered index record where DB_TRX_ID
|
|
241 |
is newer than the purge view.
|
|
242 |
||
243 |
NOTE: This function should only be called by the purge thread, only
|
|
244 |
while holding a latch on the leaf page of the secondary index entry
|
|
245 |
(or keeping the buffer pool watch on the page). It is possible that
|
|
246 |
this function first returns TRUE and then FALSE, if a user transaction
|
|
247 |
inserts a record that the secondary index entry would refer to.
|
|
248 |
However, in that case, the user transaction would also re-insert the
|
|
249 |
secondary index entry after purge has removed it and released the leaf
|
|
250 |
page latch.
|
|
251 |
@return TRUE if the secondary index record can be purged */
|
|
252 |
UNIV_INTERN
|
|
253 |
ibool
|
|
254 |
row_purge_poss_sec( |
|
255 |
/*===============*/
|
|
256 |
purge_node_t* node, /*!< in/out: row purge node */ |
|
257 |
dict_index_t* index, /*!< in: secondary index */ |
|
258 |
const dtuple_t* entry) /*!< in: secondary index entry */ |
|
259 |
{
|
|
260 |
ibool can_delete; |
|
261 |
mtr_t mtr; |
|
262 |
||
263 |
ut_ad(!dict_index_is_clust(index)); |
|
264 |
mtr_start(&mtr); |
|
265 |
||
266 |
can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr) |
|
267 |
|| !row_vers_old_has_index_entry(TRUE, |
|
268 |
btr_pcur_get_rec(&node->pcur), |
|
269 |
&mtr, index, entry); |
|
270 |
||
271 |
btr_pcur_commit_specify_mtr(&node->pcur, &mtr); |
|
272 |
||
273 |
return(can_delete); |
|
274 |
}
|
|
275 |
||
276 |
/***************************************************************
|
|
277 |
Removes a secondary index entry if possible, by modifying the
|
|
278 |
index tree. Does not try to buffer the delete.
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
279 |
@return TRUE if success or if not found */
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
280 |
static
|
281 |
ibool
|
|
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
282 |
row_purge_remove_sec_if_poss_tree( |
283 |
/*==============================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
284 |
purge_node_t* node, /*!< in: row purge node */ |
285 |
dict_index_t* index, /*!< in: index */ |
|
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
286 |
const dtuple_t* entry) /*!< in: index entry */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
287 |
{
|
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
288 |
btr_pcur_t pcur; |
289 |
btr_cur_t* btr_cur; |
|
290 |
ibool success = TRUE; |
|
291 |
ulint err; |
|
292 |
mtr_t mtr; |
|
293 |
enum row_search_result search_result; |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
294 |
|
295 |
log_free_check(); |
|
296 |
mtr_start(&mtr); |
|
297 |
||
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
298 |
search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE, |
299 |
&pcur, &mtr); |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
300 |
|
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
301 |
switch (search_result) { |
302 |
case ROW_NOT_FOUND: |
|
641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
303 |
/* Not found. This is a legitimate condition. In a
|
304 |
rollback, InnoDB will remove secondary recs that would
|
|
305 |
be purged anyway. Then the actual purge will not find
|
|
306 |
the secondary index record. Also, the purge itself is
|
|
307 |
eager: if it comes to consider a secondary index
|
|
308 |
record, and notices it does not need to exist in the
|
|
309 |
index, it will remove it. Then if/when the purge
|
|
310 |
comes to consider the secondary index record a second
|
|
311 |
time, it will not exist any more in the index. */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
312 |
|
313 |
/* fputs("PURGE:........sec entry not found\n", stderr); */
|
|
314 |
/* dtuple_print(stderr, entry); */
|
|
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
315 |
goto func_exit; |
316 |
case ROW_FOUND: |
|
317 |
break; |
|
318 |
case ROW_BUFFERED: |
|
319 |
case ROW_NOT_DELETED_REF: |
|
320 |
/* These are invalid outcomes, because the mode passed
|
|
321 |
to row_search_index_entry() did not include any of the
|
|
322 |
flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
|
|
323 |
ut_error; |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
324 |
}
|
325 |
||
326 |
btr_cur = btr_pcur_get_btr_cur(&pcur); |
|
327 |
||
328 |
/* We should remove the index record if no later version of the row,
|
|
329 |
which cannot be purged yet, requires its existence. If some requires,
|
|
330 |
we should do nothing. */
|
|
331 |
||
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
332 |
if (row_purge_poss_sec(node, index, entry)) { |
333 |
/* Remove the index record, which should have been
|
|
334 |
marked for deletion. */
|
|
335 |
ut_ad(REC_INFO_DELETED_FLAG |
|
336 |
& rec_get_info_bits(btr_cur_get_rec(btr_cur), |
|
337 |
dict_table_is_comp(index->table))); |
|
338 |
||
339 |
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, |
|
340 |
RB_NONE, &mtr); |
|
341 |
switch (UNIV_EXPECT(err, DB_SUCCESS)) { |
|
342 |
case DB_SUCCESS: |
|
343 |
break; |
|
344 |
case DB_OUT_OF_FILE_SPACE: |
|
345 |
success = FALSE; |
|
346 |
break; |
|
347 |
default: |
|
348 |
ut_error; |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
349 |
}
|
350 |
}
|
|
351 |
||
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
352 |
func_exit: |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
353 |
btr_pcur_close(&pcur); |
354 |
mtr_commit(&mtr); |
|
355 |
||
356 |
return(success); |
|
357 |
}
|
|
358 |
||
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
359 |
/***************************************************************
|
360 |
Removes a secondary index entry without modifying the index tree,
|
|
361 |
if possible.
|
|
362 |
@return TRUE if success or if not found */
|
|
363 |
static
|
|
364 |
ibool
|
|
365 |
row_purge_remove_sec_if_poss_leaf( |
|
366 |
/*==============================*/
|
|
367 |
purge_node_t* node, /*!< in: row purge node */ |
|
368 |
dict_index_t* index, /*!< in: index */ |
|
369 |
const dtuple_t* entry) /*!< in: index entry */ |
|
370 |
{
|
|
371 |
mtr_t mtr; |
|
372 |
btr_pcur_t pcur; |
|
373 |
enum row_search_result search_result; |
|
374 |
||
375 |
log_free_check(); |
|
376 |
||
377 |
mtr_start(&mtr); |
|
378 |
||
379 |
/* Set the purge node for the call to row_purge_poss_sec(). */
|
|
380 |
pcur.btr_cur.purge_node = node; |
|
381 |
/* Set the query thread, so that ibuf_insert_low() will be
|
|
382 |
able to invoke thd_get_trx(). */
|
|
2023.3.14
by Monty Taylor
More casting. |
383 |
pcur.btr_cur.thr = static_cast<que_thr_t *>(que_node_get_parent(node)); |
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
384 |
|
385 |
search_result = row_search_index_entry( |
|
386 |
index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr); |
|
387 |
||
388 |
switch (search_result) { |
|
389 |
ibool success; |
|
390 |
case ROW_FOUND: |
|
391 |
/* Before attempting to purge a record, check
|
|
392 |
if it is safe to do so. */
|
|
393 |
if (row_purge_poss_sec(node, index, entry)) { |
|
394 |
btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); |
|
395 |
||
396 |
/* Only delete-marked records should be purged. */
|
|
397 |
ut_ad(REC_INFO_DELETED_FLAG |
|
398 |
& rec_get_info_bits( |
|
399 |
btr_cur_get_rec(btr_cur), |
|
400 |
dict_table_is_comp(index->table))); |
|
401 |
||
402 |
if (!btr_cur_optimistic_delete(btr_cur, &mtr)) { |
|
403 |
||
404 |
/* The index entry could not be deleted. */
|
|
405 |
success = FALSE; |
|
406 |
goto func_exit; |
|
407 |
}
|
|
408 |
}
|
|
409 |
/* fall through (the index entry is still needed,
|
|
410 |
or the deletion succeeded) */
|
|
411 |
case ROW_NOT_DELETED_REF: |
|
412 |
/* The index entry is still needed. */
|
|
413 |
case ROW_BUFFERED: |
|
414 |
/* The deletion was buffered. */
|
|
415 |
case ROW_NOT_FOUND: |
|
416 |
/* The index entry does not exist, nothing to do. */
|
|
417 |
success = TRUE; |
|
418 |
func_exit: |
|
419 |
btr_pcur_close(&pcur); |
|
420 |
mtr_commit(&mtr); |
|
421 |
return(success); |
|
422 |
}
|
|
423 |
||
424 |
ut_error; |
|
425 |
return(FALSE); |
|
426 |
}
|
|
427 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
428 |
/***********************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
429 |
Removes a secondary index entry if possible. */
|
430 |
UNIV_INLINE
|
|
431 |
void
|
|
432 |
row_purge_remove_sec_if_poss( |
|
433 |
/*=========================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
434 |
purge_node_t* node, /*!< in: row purge node */ |
435 |
dict_index_t* index, /*!< in: index */ |
|
436 |
dtuple_t* entry) /*!< in: index entry */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
437 |
{
|
438 |
ibool success; |
|
439 |
ulint n_tries = 0; |
|
440 |
||
441 |
/* fputs("Purge: Removing secondary record\n", stderr); */
|
|
442 |
||
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
443 |
if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) { |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
444 |
|
445 |
return; |
|
446 |
}
|
|
447 |
retry: |
|
1819.7.68
by Stewart Smith
Merge initial InnoDB+ import. |
448 |
success = row_purge_remove_sec_if_poss_tree(node, index, entry); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
449 |
/* The delete operation may fail if we have little
|
450 |
file space left: TODO: easiest to crash the database
|
|
451 |
and restart with more file space */
|
|
452 |
||
453 |
if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) { |
|
454 |
||
455 |
n_tries++; |
|
456 |
||
457 |
os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME); |
|
458 |
||
459 |
goto retry; |
|
460 |
}
|
|
461 |
||
462 |
ut_a(success); |
|
463 |
}
|
|
464 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
465 |
/***********************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
466 |
Purges a delete marking of a record. */
|
467 |
static
|
|
468 |
void
|
|
469 |
row_purge_del_mark( |
|
470 |
/*===============*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
471 |
purge_node_t* node) /*!< in: row purge node */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
472 |
{
|
473 |
mem_heap_t* heap; |
|
474 |
dtuple_t* entry; |
|
475 |
dict_index_t* index; |
|
476 |
||
477 |
ut_ad(node); |
|
478 |
||
479 |
heap = mem_heap_create(1024); |
|
480 |
||
481 |
while (node->index != NULL) { |
|
482 |
index = node->index; |
|
483 |
||
484 |
/* Build the index entry */
|
|
485 |
entry = row_build_index_entry(node->row, NULL, index, heap); |
|
486 |
ut_a(entry); |
|
487 |
row_purge_remove_sec_if_poss(node, index, entry); |
|
488 |
||
489 |
node->index = dict_table_get_next_index(node->index); |
|
490 |
}
|
|
491 |
||
492 |
mem_heap_free(heap); |
|
493 |
||
494 |
row_purge_remove_clust_if_poss(node); |
|
495 |
}
|
|
496 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
497 |
/***********************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
498 |
Purges an update of an existing record. Also purges an update of a delete
|
499 |
marked record if that record contained an externally stored field. */
|
|
500 |
static
|
|
501 |
void
|
|
502 |
row_purge_upd_exist_or_extern( |
|
503 |
/*==========================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
504 |
purge_node_t* node) /*!< in: row purge node */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
505 |
{
|
506 |
mem_heap_t* heap; |
|
507 |
dtuple_t* entry; |
|
508 |
dict_index_t* index; |
|
509 |
ibool is_insert; |
|
510 |
ulint rseg_id; |
|
511 |
ulint page_no; |
|
512 |
ulint offset; |
|
513 |
ulint i; |
|
514 |
mtr_t mtr; |
|
515 |
||
516 |
ut_ad(node); |
|
517 |
||
518 |
if (node->rec_type == TRX_UNDO_UPD_DEL_REC) { |
|
519 |
||
520 |
goto skip_secondaries; |
|
521 |
}
|
|
522 |
||
523 |
heap = mem_heap_create(1024); |
|
524 |
||
525 |
while (node->index != NULL) { |
|
526 |
index = node->index; |
|
527 |
||
528 |
if (row_upd_changes_ord_field_binary(NULL, node->index, |
|
529 |
node->update)) { |
|
530 |
/* Build the older version of the index entry */
|
|
531 |
entry = row_build_index_entry(node->row, NULL, |
|
532 |
index, heap); |
|
533 |
ut_a(entry); |
|
534 |
row_purge_remove_sec_if_poss(node, index, entry); |
|
535 |
}
|
|
536 |
||
537 |
node->index = dict_table_get_next_index(node->index); |
|
538 |
}
|
|
539 |
||
540 |
mem_heap_free(heap); |
|
541 |
||
542 |
skip_secondaries: |
|
543 |
/* Free possible externally stored fields */
|
|
544 |
for (i = 0; i < upd_get_n_fields(node->update); i++) { |
|
545 |
||
546 |
const upd_field_t* ufield |
|
547 |
= upd_get_nth_field(node->update, i); |
|
548 |
||
549 |
if (dfield_is_ext(&ufield->new_val)) { |
|
550 |
buf_block_t* block; |
|
551 |
ulint internal_offset; |
|
552 |
byte* data_field; |
|
553 |
||
554 |
/* We use the fact that new_val points to
|
|
555 |
node->undo_rec and get thus the offset of
|
|
556 |
dfield data inside the undo record. Then we
|
|
557 |
can calculate from node->roll_ptr the file
|
|
558 |
address of the new_val data */
|
|
559 |
||
560 |
internal_offset
|
|
561 |
= ((const byte*) |
|
562 |
dfield_get_data(&ufield->new_val)) |
|
563 |
- node->undo_rec; |
|
564 |
||
565 |
ut_a(internal_offset < UNIV_PAGE_SIZE); |
|
566 |
||
567 |
trx_undo_decode_roll_ptr(node->roll_ptr, |
|
568 |
&is_insert, &rseg_id, |
|
569 |
&page_no, &offset); |
|
570 |
mtr_start(&mtr); |
|
571 |
||
572 |
/* We have to acquire an X-latch to the clustered
|
|
573 |
index tree */
|
|
574 |
||
575 |
index = dict_table_get_first_index(node->table); |
|
576 |
||
577 |
mtr_x_lock(dict_index_get_lock(index), &mtr); |
|
578 |
||
579 |
/* NOTE: we must also acquire an X-latch to the
|
|
580 |
root page of the tree. We will need it when we
|
|
581 |
free pages from the tree. If the tree is of height 1,
|
|
582 |
the tree X-latch does NOT protect the root page,
|
|
583 |
because it is also a leaf page. Since we will have a
|
|
584 |
latch on an undo log page, we would break the
|
|
585 |
latching order if we would only later latch the
|
|
586 |
root page of such a tree! */
|
|
587 |
||
588 |
btr_root_get(index, &mtr); |
|
589 |
||
590 |
/* We assume in purge of externally stored fields
|
|
591 |
that the space id of the undo log record is 0! */
|
|
592 |
||
593 |
block = buf_page_get(0, 0, page_no, RW_X_LATCH, &mtr); |
|
594 |
buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE); |
|
641.2.1
by Monty Taylor
InnoDB Plugin 1.0.2 |
595 |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
596 |
data_field = buf_block_get_frame(block) |
597 |
+ offset + internal_offset; |
|
598 |
||
599 |
ut_a(dfield_get_len(&ufield->new_val) |
|
600 |
>= BTR_EXTERN_FIELD_REF_SIZE); |
|
601 |
btr_free_externally_stored_field( |
|
602 |
index, |
|
603 |
data_field + dfield_get_len(&ufield->new_val) |
|
604 |
- BTR_EXTERN_FIELD_REF_SIZE, |
|
641.2.1
by Monty Taylor
InnoDB Plugin 1.0.2 |
605 |
NULL, NULL, NULL, 0, RB_NONE, &mtr); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
606 |
mtr_commit(&mtr); |
607 |
}
|
|
608 |
}
|
|
609 |
}
|
|
610 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
611 |
/***********************************************************//**
|
612 |
Parses the row reference and other info in a modify undo log record.
|
|
613 |
@return TRUE if purge operation required: NOTE that then the CALLER
|
|
614 |
must unfreeze data dictionary! */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
615 |
static
|
616 |
ibool
|
|
617 |
row_purge_parse_undo_rec( |
|
618 |
/*=====================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
619 |
purge_node_t* node, /*!< in: row undo node */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
620 |
ibool* updated_extern, |
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
621 |
/*!< out: TRUE if an externally stored field
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
622 |
was updated */
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
623 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
624 |
{
|
625 |
dict_index_t* clust_index; |
|
626 |
byte* ptr; |
|
627 |
trx_t* trx; |
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
628 |
undo_no_t undo_no; |
1819.9.31
by Marko Mäkelä, Stewart Smith
Merge Revision revid:marko.makela@oracle.com-20100623110659-pk5bqnmo0j7hj6md from MySQL InnoDB |
629 |
table_id_t table_id; |
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
630 |
trx_id_t trx_id; |
631 |
roll_ptr_t roll_ptr; |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
632 |
ulint info_bits; |
633 |
ulint type; |
|
634 |
ulint cmpl_info; |
|
635 |
||
636 |
ut_ad(node && thr); |
|
637 |
||
638 |
trx = thr_get_trx(thr); |
|
639 |
||
640 |
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info, |
|
641 |
updated_extern, &undo_no, &table_id); |
|
642 |
node->rec_type = type; |
|
643 |
||
644 |
if (type == TRX_UNDO_UPD_DEL_REC && !(*updated_extern)) { |
|
645 |
||
646 |
return(FALSE); |
|
647 |
}
|
|
648 |
||
649 |
ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr, |
|
650 |
&info_bits); |
|
651 |
node->table = NULL; |
|
652 |
||
653 |
if (type == TRX_UNDO_UPD_EXIST_REC |
|
654 |
&& cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) { |
|
655 |
||
656 |
/* Purge requires no changes to indexes: we may return */
|
|
657 |
||
658 |
return(FALSE); |
|
659 |
}
|
|
660 |
||
661 |
/* Prevent DROP TABLE etc. from running when we are doing the purge
|
|
662 |
for this row */
|
|
663 |
||
664 |
row_mysql_freeze_data_dictionary(trx); |
|
665 |
||
666 |
mutex_enter(&(dict_sys->mutex)); |
|
667 |
||
668 |
node->table = dict_table_get_on_id_low(table_id); |
|
669 |
||
670 |
mutex_exit(&(dict_sys->mutex)); |
|
671 |
||
672 |
if (node->table == NULL) { |
|
673 |
/* The table has been dropped: no need to do purge */
|
|
674 |
err_exit: |
|
675 |
row_mysql_unfreeze_data_dictionary(trx); |
|
676 |
return(FALSE); |
|
677 |
}
|
|
678 |
||
679 |
if (node->table->ibd_file_missing) { |
|
680 |
/* We skip purge of missing .ibd files */
|
|
681 |
||
682 |
node->table = NULL; |
|
683 |
||
684 |
goto err_exit; |
|
685 |
}
|
|
686 |
||
687 |
clust_index = dict_table_get_first_index(node->table); |
|
688 |
||
689 |
if (clust_index == NULL) { |
|
690 |
/* The table was corrupt in the data dictionary */
|
|
691 |
||
692 |
goto err_exit; |
|
693 |
}
|
|
694 |
||
695 |
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref), |
|
696 |
node->heap); |
|
697 |
||
698 |
ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id, |
|
699 |
roll_ptr, info_bits, trx, |
|
700 |
node->heap, &(node->update)); |
|
701 |
||
702 |
/* Read to the partial row the fields that occur in indexes */
|
|
703 |
||
704 |
if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { |
|
641.2.1
by Monty Taylor
InnoDB Plugin 1.0.2 |
705 |
ptr = trx_undo_rec_get_partial_row( |
706 |
ptr, clust_index, &node->row, |
|
707 |
type == TRX_UNDO_UPD_DEL_REC, |
|
708 |
node->heap); |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
709 |
}
|
710 |
||
711 |
return(TRUE); |
|
712 |
}
|
|
713 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
714 |
/***********************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
715 |
Fetches an undo log record and does the purge for the recorded operation.
|
716 |
If none left, or the current purge completed, returns the control to the
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
717 |
parent node, which is always a query thread node.
|
718 |
@return DB_SUCCESS if operation successfully completed, else error code */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
719 |
static
|
720 |
ulint
|
|
721 |
row_purge( |
|
722 |
/*======*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
723 |
purge_node_t* node, /*!< in: row purge node */ |
724 |
que_thr_t* thr) /*!< in: query thread */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
725 |
{
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
726 |
roll_ptr_t roll_ptr; |
727 |
ibool purge_needed; |
|
728 |
ibool updated_extern; |
|
729 |
trx_t* trx; |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
730 |
|
731 |
ut_ad(node && thr); |
|
732 |
||
733 |
trx = thr_get_trx(thr); |
|
734 |
||
735 |
node->undo_rec = trx_purge_fetch_next_rec(&roll_ptr, |
|
736 |
&(node->reservation), |
|
737 |
node->heap); |
|
738 |
if (!node->undo_rec) { |
|
739 |
/* Purge completed for this query thread */
|
|
740 |
||
741 |
thr->run_node = que_node_get_parent(node); |
|
742 |
||
743 |
return(DB_SUCCESS); |
|
744 |
}
|
|
745 |
||
746 |
node->roll_ptr = roll_ptr; |
|
747 |
||
748 |
if (node->undo_rec == &trx_purge_dummy_rec) { |
|
749 |
purge_needed = FALSE; |
|
750 |
} else { |
|
751 |
purge_needed = row_purge_parse_undo_rec(node, &updated_extern, |
|
752 |
thr); |
|
753 |
/* If purge_needed == TRUE, we must also remember to unfreeze
|
|
754 |
data dictionary! */
|
|
755 |
}
|
|
756 |
||
757 |
if (purge_needed) { |
|
758 |
node->found_clust = FALSE; |
|
759 |
||
760 |
node->index = dict_table_get_next_index( |
|
761 |
dict_table_get_first_index(node->table)); |
|
762 |
||
763 |
if (node->rec_type == TRX_UNDO_DEL_MARK_REC) { |
|
764 |
row_purge_del_mark(node); |
|
765 |
||
766 |
} else if (updated_extern |
|
767 |
|| node->rec_type == TRX_UNDO_UPD_EXIST_REC) { |
|
768 |
||
769 |
row_purge_upd_exist_or_extern(node); |
|
770 |
}
|
|
771 |
||
772 |
if (node->found_clust) { |
|
773 |
btr_pcur_close(&(node->pcur)); |
|
774 |
}
|
|
775 |
||
776 |
row_mysql_unfreeze_data_dictionary(trx); |
|
777 |
}
|
|
778 |
||
779 |
/* Do some cleanup */
|
|
780 |
trx_purge_rec_release(node->reservation); |
|
781 |
mem_heap_empty(node->heap); |
|
782 |
||
783 |
thr->run_node = node; |
|
784 |
||
785 |
return(DB_SUCCESS); |
|
786 |
}
|
|
787 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
788 |
/***********************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
789 |
Does the purge operation for a single undo log record. This is a high-level
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
790 |
function used in an SQL execution graph.
|
791 |
@return query thread to run next or NULL */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
792 |
UNIV_INTERN
|
793 |
que_thr_t* |
|
794 |
row_purge_step( |
|
795 |
/*===========*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
796 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
797 |
{
|
798 |
purge_node_t* node; |
|
1819.9.141
by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100920160930-wqevqvxlnto1dh24 from MySQL InnoDB |
799 |
#ifdef UNIV_DEBUG
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
800 |
ulint err; |
1819.9.141
by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100920160930-wqevqvxlnto1dh24 from MySQL InnoDB |
801 |
#endif /* UNIV_DEBUG */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
802 |
|
803 |
ut_ad(thr); |
|
804 |
||
2023.3.14
by Monty Taylor
More casting. |
805 |
node = static_cast<purge_node_t *>(thr->run_node); |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
806 |
|
807 |
ut_ad(que_node_get_type(node) == QUE_NODE_PURGE); |
|
808 |
||
1819.9.141
by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100920160930-wqevqvxlnto1dh24 from MySQL InnoDB |
809 |
#ifdef UNIV_DEBUG
|
810 |
err = |
|
811 |
#endif /* UNIV_DEBUG */ |
|
812 |
row_purge(node, thr); |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
813 |
|
1819.9.142
by Stewart Smith
fix build problem in moving some error checking to debug only in row0purge.c |
814 |
#ifdef UNIV_DEBUG
|
1819.9.104
by Vasil Dimov
Merge Revision revid:vasil.dimov@oracle.com-20100914105629-mh9i2j3y953qwt8h from MySQL InnoDB |
815 |
ut_a(err == DB_SUCCESS); |
1819.9.142
by Stewart Smith
fix build problem in moving some error checking to debug only in row0purge.c |
816 |
#endif /* UNIV_DEBUG */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
817 |
|
818 |
return(thr); |
|
819 |
}
|