641.2.2
by Monty Taylor
InnoDB Plugin 1.0.3 |
1 |
/*****************************************************************************
|
2 |
||
3 |
Copyright (c) 1996, 2009, Innobase Oy. 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 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 que/que0que.c
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
21 |
Query graph
|
22 |
||
23 |
Created 5/27/1996 Heikki Tuuri
|
|
24 |
*******************************************************/
|
|
25 |
||
26 |
#include "que0que.h" |
|
27 |
||
28 |
#ifdef UNIV_NONINL
|
|
29 |
#include "que0que.ic" |
|
30 |
#endif
|
|
31 |
||
32 |
#include "srv0que.h" |
|
33 |
#include "usr0sess.h" |
|
34 |
#include "trx0trx.h" |
|
35 |
#include "trx0roll.h" |
|
36 |
#include "row0undo.h" |
|
37 |
#include "row0ins.h" |
|
38 |
#include "row0upd.h" |
|
39 |
#include "row0sel.h" |
|
40 |
#include "row0purge.h" |
|
41 |
#include "dict0crea.h" |
|
42 |
#include "log0log.h" |
|
43 |
#include "eval0proc.h" |
|
44 |
#include "eval0eval.h" |
|
45 |
#include "pars0types.h" |
|
46 |
||
47 |
#define QUE_PARALLELIZE_LIMIT (64 * 256 * 256 * 256)
|
|
48 |
#define QUE_ROUND_ROBIN_LIMIT (64 * 256 * 256 * 256)
|
|
49 |
#define QUE_MAX_LOOPS_WITHOUT_CHECK 16
|
|
50 |
||
51 |
#ifdef UNIV_DEBUG
|
|
52 |
/* If the following flag is set TRUE, the module will print trace info
|
|
53 |
of SQL execution in the UNIV_SQL_DEBUG version */
|
|
54 |
UNIV_INTERN ibool que_trace_on = FALSE; |
|
55 |
#endif /* UNIV_DEBUG */ |
|
56 |
||
57 |
/* Short introduction to query graphs
|
|
58 |
==================================
|
|
59 |
||
60 |
A query graph consists of nodes linked to each other in various ways. The
|
|
61 |
execution starts at que_run_threads() which takes a que_thr_t parameter.
|
|
62 |
que_thr_t contains two fields that control query graph execution: run_node
|
|
63 |
and prev_node. run_node is the next node to execute and prev_node is the
|
|
64 |
last node executed.
|
|
65 |
||
66 |
Each node has a pointer to a 'next' statement, i.e., its brother, and a
|
|
67 |
pointer to its parent node. The next pointer is NULL in the last statement
|
|
68 |
of a block.
|
|
69 |
||
70 |
Loop nodes contain a link to the first statement of the enclosed statement
|
|
71 |
list. While the loop runs, que_thr_step() checks if execution to the loop
|
|
72 |
node came from its parent or from one of the statement nodes in the loop. If
|
|
73 |
it came from the parent of the loop node it starts executing the first
|
|
74 |
statement node in the loop. If it came from one of the statement nodes in
|
|
75 |
the loop, then it checks if the statement node has another statement node
|
|
76 |
following it, and runs it if so.
|
|
77 |
||
78 |
To signify loop ending, the loop statements (see e.g. while_step()) set
|
|
79 |
que_thr_t->run_node to the loop node's parent node. This is noticed on the
|
|
80 |
next call of que_thr_step() and execution proceeds to the node pointed to by
|
|
81 |
the loop node's 'next' pointer.
|
|
82 |
||
83 |
For example, the code:
|
|
84 |
||
85 |
X := 1;
|
|
86 |
WHILE X < 5 LOOP
|
|
87 |
X := X + 1;
|
|
88 |
X := X + 1;
|
|
89 |
X := 5
|
|
90 |
||
91 |
will result in the following node hierarchy, with the X-axis indicating
|
|
92 |
'next' links and the Y-axis indicating parent/child links:
|
|
93 |
||
94 |
A - W - A
|
|
95 |
|
|
|
96 |
|
|
|
97 |
A - A
|
|
98 |
||
99 |
A = assign_node_t, W = while_node_t. */
|
|
100 |
||
101 |
/* How a stored procedure containing COMMIT or ROLLBACK commands
|
|
102 |
is executed?
|
|
103 |
||
104 |
The commit or rollback can be seen as a subprocedure call.
|
|
105 |
The problem is that if there are several query threads
|
|
106 |
currently running within the transaction, their action could
|
|
107 |
mess the commit or rollback operation. Or, at the least, the
|
|
108 |
operation would be difficult to visualize and keep in control.
|
|
109 |
||
110 |
Therefore the query thread requesting a commit or a rollback
|
|
111 |
sends to the transaction a signal, which moves the transaction
|
|
112 |
to TRX_QUE_SIGNALED state. All running query threads of the
|
|
113 |
transaction will eventually notice that the transaction is now in
|
|
114 |
this state and voluntarily suspend themselves. Only the last
|
|
115 |
query thread which suspends itself will trigger handling of
|
|
116 |
the signal.
|
|
117 |
||
118 |
When the transaction starts to handle a rollback or commit
|
|
119 |
signal, it builds a query graph which, when executed, will
|
|
120 |
roll back or commit the incomplete transaction. The transaction
|
|
121 |
is moved to the TRX_QUE_ROLLING_BACK or TRX_QUE_COMMITTING state.
|
|
122 |
If specified, the SQL cursors opened by the transaction are closed.
|
|
123 |
When the execution of the graph completes, it is like returning
|
|
124 |
from a subprocedure: the query thread which requested the operation
|
|
125 |
starts running again. */
|
|
126 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
127 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
128 |
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
|
129 |
the n_active_thrs counters of the query graph and transaction.
|
|
130 |
***NOTE***: This is the only function in which such a transition is allowed
|
|
131 |
to happen! */
|
|
132 |
static
|
|
133 |
void
|
|
134 |
que_thr_move_to_run_state( |
|
135 |
/*======================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
136 |
que_thr_t* thr); /*!< in: an query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
137 |
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
138 |
/***********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
139 |
Adds a query graph to the session's list of graphs. */
|
140 |
UNIV_INTERN
|
|
141 |
void
|
|
142 |
que_graph_publish( |
|
143 |
/*==============*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
144 |
que_t* graph, /*!< in: graph */ |
145 |
sess_t* sess) /*!< in: session */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
146 |
{
|
147 |
ut_ad(mutex_own(&kernel_mutex)); |
|
148 |
||
149 |
UT_LIST_ADD_LAST(graphs, sess->graphs, graph); |
|
150 |
}
|
|
151 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
152 |
/***********************************************************************//**
|
153 |
Creates a query graph fork node.
|
|
154 |
@return own: fork node */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
155 |
UNIV_INTERN
|
156 |
que_fork_t* |
|
157 |
que_fork_create( |
|
158 |
/*============*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
159 |
que_t* graph, /*!< in: graph, if NULL then this |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
160 |
fork node is assumed to be the
|
161 |
graph root */
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
162 |
que_node_t* parent, /*!< in: parent node */ |
163 |
ulint fork_type, /*!< in: fork type */ |
|
164 |
mem_heap_t* heap) /*!< in: memory heap where created */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
165 |
{
|
166 |
que_fork_t* fork; |
|
167 |
||
168 |
ut_ad(heap); |
|
169 |
||
170 |
fork = mem_heap_alloc(heap, sizeof(que_fork_t)); |
|
171 |
||
172 |
fork->common.type = QUE_NODE_FORK; |
|
173 |
fork->n_active_thrs = 0; |
|
174 |
||
175 |
fork->state = QUE_FORK_COMMAND_WAIT; |
|
176 |
||
177 |
if (graph != NULL) { |
|
178 |
fork->graph = graph; |
|
179 |
} else { |
|
180 |
fork->graph = fork; |
|
181 |
}
|
|
182 |
||
183 |
fork->common.parent = parent; |
|
184 |
fork->fork_type = fork_type; |
|
185 |
||
186 |
fork->caller = NULL; |
|
187 |
||
188 |
UT_LIST_INIT(fork->thrs); |
|
189 |
||
190 |
fork->sym_tab = NULL; |
|
191 |
fork->info = NULL; |
|
192 |
||
193 |
fork->heap = heap; |
|
194 |
||
195 |
return(fork); |
|
196 |
}
|
|
197 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
198 |
/***********************************************************************//**
|
199 |
Creates a query graph thread node.
|
|
200 |
@return own: query thread node */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
201 |
UNIV_INTERN
|
202 |
que_thr_t* |
|
203 |
que_thr_create( |
|
204 |
/*===========*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
205 |
que_fork_t* parent, /*!< in: parent node, i.e., a fork node */ |
206 |
mem_heap_t* heap) /*!< in: memory heap where created */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
207 |
{
|
208 |
que_thr_t* thr; |
|
209 |
||
210 |
ut_ad(parent && heap); |
|
211 |
||
212 |
thr = mem_heap_alloc(heap, sizeof(que_thr_t)); |
|
213 |
||
214 |
thr->common.type = QUE_NODE_THR; |
|
215 |
thr->common.parent = parent; |
|
216 |
||
217 |
thr->magic_n = QUE_THR_MAGIC_N; |
|
218 |
||
219 |
thr->graph = parent->graph; |
|
220 |
||
221 |
thr->state = QUE_THR_COMMAND_WAIT; |
|
222 |
||
223 |
thr->is_active = FALSE; |
|
224 |
||
225 |
thr->run_node = NULL; |
|
226 |
thr->resource = 0; |
|
227 |
thr->lock_state = QUE_THR_LOCK_NOLOCK; |
|
228 |
||
229 |
UT_LIST_ADD_LAST(thrs, parent->thrs, thr); |
|
230 |
||
231 |
return(thr); |
|
232 |
}
|
|
233 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
234 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
235 |
Moves a suspended query thread to the QUE_THR_RUNNING state and may release
|
236 |
a single worker thread to execute it. This function should be used to end
|
|
237 |
the wait state of a query thread waiting for a lock or a stored procedure
|
|
238 |
completion. */
|
|
239 |
UNIV_INTERN
|
|
240 |
void
|
|
241 |
que_thr_end_wait( |
|
242 |
/*=============*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
243 |
que_thr_t* thr, /*!< in: query thread in the |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
244 |
QUE_THR_LOCK_WAIT,
|
245 |
or QUE_THR_PROCEDURE_WAIT, or
|
|
246 |
QUE_THR_SIG_REPLY_WAIT state */
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
247 |
que_thr_t** next_thr) /*!< in/out: next query thread to run; |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
248 |
if the value which is passed in is
|
249 |
a pointer to a NULL pointer, then the
|
|
250 |
calling function can start running
|
|
251 |
a new query thread; if NULL is passed
|
|
252 |
as the parameter, it is ignored */
|
|
253 |
{
|
|
254 |
ibool was_active; |
|
255 |
||
256 |
ut_ad(mutex_own(&kernel_mutex)); |
|
257 |
ut_ad(thr); |
|
258 |
ut_ad((thr->state == QUE_THR_LOCK_WAIT) |
|
259 |
|| (thr->state == QUE_THR_PROCEDURE_WAIT) |
|
260 |
|| (thr->state == QUE_THR_SIG_REPLY_WAIT)); |
|
261 |
ut_ad(thr->run_node); |
|
262 |
||
263 |
thr->prev_node = thr->run_node; |
|
264 |
||
265 |
was_active = thr->is_active; |
|
266 |
||
267 |
que_thr_move_to_run_state(thr); |
|
268 |
||
269 |
if (was_active) { |
|
270 |
||
271 |
return; |
|
272 |
}
|
|
273 |
||
274 |
if (next_thr && *next_thr == NULL) { |
|
275 |
*next_thr = thr; |
|
276 |
} else { |
|
277 |
ut_a(0); |
|
278 |
srv_que_task_enqueue_low(thr); |
|
279 |
}
|
|
280 |
}
|
|
281 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
282 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
283 |
Same as que_thr_end_wait, but no parameter next_thr available. */
|
284 |
UNIV_INTERN
|
|
285 |
void
|
|
286 |
que_thr_end_wait_no_next_thr( |
|
287 |
/*=========================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
288 |
que_thr_t* thr) /*!< in: query thread in the QUE_THR_LOCK_WAIT, |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
289 |
or QUE_THR_PROCEDURE_WAIT, or
|
290 |
QUE_THR_SIG_REPLY_WAIT state */
|
|
291 |
{
|
|
292 |
ibool was_active; |
|
293 |
||
294 |
ut_a(thr->state == QUE_THR_LOCK_WAIT); /* In MySQL this is the |
|
295 |
only possible state here */
|
|
296 |
ut_ad(mutex_own(&kernel_mutex)); |
|
297 |
ut_ad(thr); |
|
298 |
ut_ad((thr->state == QUE_THR_LOCK_WAIT) |
|
299 |
|| (thr->state == QUE_THR_PROCEDURE_WAIT) |
|
300 |
|| (thr->state == QUE_THR_SIG_REPLY_WAIT)); |
|
301 |
||
302 |
was_active = thr->is_active; |
|
303 |
||
304 |
que_thr_move_to_run_state(thr); |
|
305 |
||
306 |
if (was_active) { |
|
307 |
||
308 |
return; |
|
309 |
}
|
|
310 |
||
311 |
/* In MySQL we let the OS thread (not just the query thread) to wait
|
|
312 |
for the lock to be released: */
|
|
313 |
||
314 |
srv_release_mysql_thread_if_suspended(thr); |
|
315 |
||
316 |
/* srv_que_task_enqueue_low(thr); */
|
|
317 |
}
|
|
318 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
319 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
320 |
Inits a query thread for a command. */
|
321 |
UNIV_INLINE
|
|
322 |
void
|
|
323 |
que_thr_init_command( |
|
324 |
/*=================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
325 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
326 |
{
|
327 |
thr->run_node = thr; |
|
328 |
thr->prev_node = thr->common.parent; |
|
329 |
||
330 |
que_thr_move_to_run_state(thr); |
|
331 |
}
|
|
332 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
333 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
334 |
Starts execution of a command in a query fork. Picks a query thread which
|
335 |
is not in the QUE_THR_RUNNING state and moves it to that state. If none
|
|
336 |
can be chosen, a situation which may arise in parallelized fetches, NULL
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
337 |
is returned.
|
338 |
@return a query thread of the graph moved to QUE_THR_RUNNING state, or
|
|
339 |
NULL; the query thread should be executed by que_run_threads by the
|
|
340 |
caller */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
341 |
UNIV_INTERN
|
342 |
que_thr_t* |
|
343 |
que_fork_start_command( |
|
344 |
/*===================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
345 |
que_fork_t* fork) /*!< in: a query fork */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
346 |
{
|
347 |
que_thr_t* thr; |
|
348 |
que_thr_t* suspended_thr = NULL; |
|
349 |
que_thr_t* completed_thr = NULL; |
|
350 |
||
351 |
fork->state = QUE_FORK_ACTIVE; |
|
352 |
||
353 |
fork->last_sel_node = NULL; |
|
354 |
||
355 |
suspended_thr = NULL; |
|
356 |
completed_thr = NULL; |
|
357 |
||
358 |
/* Choose the query thread to run: usually there is just one thread,
|
|
359 |
but in a parallelized select, which necessarily is non-scrollable,
|
|
360 |
there may be several to choose from */
|
|
361 |
||
362 |
/* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
|
|
363 |
state. Then we try to find a query thread in the QUE_THR_SUSPENDED
|
|
364 |
state, finally we try to find a query thread in the QUE_THR_COMPLETED
|
|
365 |
state */
|
|
366 |
||
367 |
thr = UT_LIST_GET_FIRST(fork->thrs); |
|
368 |
||
369 |
/* We make a single pass over the thr list within which we note which
|
|
370 |
threads are ready to run. */
|
|
371 |
while (thr) { |
|
372 |
switch (thr->state) { |
|
373 |
case QUE_THR_COMMAND_WAIT: |
|
374 |
||
375 |
/* We have to send the initial message to query thread
|
|
376 |
to start it */
|
|
377 |
||
378 |
que_thr_init_command(thr); |
|
379 |
||
380 |
return(thr); |
|
381 |
||
382 |
case QUE_THR_SUSPENDED: |
|
383 |
/* In this case the execution of the thread was
|
|
384 |
suspended: no initial message is needed because
|
|
385 |
execution can continue from where it was left */
|
|
386 |
if (!suspended_thr) { |
|
387 |
suspended_thr = thr; |
|
388 |
}
|
|
389 |
||
390 |
break; |
|
391 |
||
392 |
case QUE_THR_COMPLETED: |
|
393 |
if (!completed_thr) { |
|
394 |
completed_thr = thr; |
|
395 |
}
|
|
396 |
||
397 |
break; |
|
398 |
||
399 |
case QUE_THR_LOCK_WAIT: |
|
400 |
ut_error; |
|
401 |
||
402 |
}
|
|
403 |
||
404 |
thr = UT_LIST_GET_NEXT(thrs, thr); |
|
405 |
}
|
|
406 |
||
407 |
if (suspended_thr) { |
|
408 |
||
409 |
thr = suspended_thr; |
|
410 |
que_thr_move_to_run_state(thr); |
|
411 |
||
412 |
} else if (completed_thr) { |
|
413 |
||
414 |
thr = completed_thr; |
|
415 |
que_thr_init_command(thr); |
|
416 |
}
|
|
417 |
||
418 |
return(thr); |
|
419 |
}
|
|
420 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
421 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
422 |
After signal handling is finished, returns control to a query graph error
|
423 |
handling routine. (Currently, just returns the control to the root of the
|
|
424 |
graph so that the graph can communicate an error message to the client.) */
|
|
425 |
UNIV_INTERN
|
|
426 |
void
|
|
427 |
que_fork_error_handle( |
|
428 |
/*==================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
429 |
trx_t* trx __attribute__((unused)), /*!< in: trx */ |
430 |
que_t* fork) /*!< in: query graph which was run before signal |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
431 |
handling started, NULL not allowed */
|
432 |
{
|
|
433 |
que_thr_t* thr; |
|
434 |
||
435 |
ut_ad(mutex_own(&kernel_mutex)); |
|
436 |
ut_ad(trx->sess->state == SESS_ERROR); |
|
437 |
ut_ad(UT_LIST_GET_LEN(trx->reply_signals) == 0); |
|
438 |
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0); |
|
439 |
||
440 |
thr = UT_LIST_GET_FIRST(fork->thrs); |
|
441 |
||
442 |
while (thr != NULL) { |
|
443 |
ut_ad(!thr->is_active); |
|
444 |
ut_ad(thr->state != QUE_THR_SIG_REPLY_WAIT); |
|
445 |
ut_ad(thr->state != QUE_THR_LOCK_WAIT); |
|
446 |
||
447 |
thr->run_node = thr; |
|
448 |
thr->prev_node = thr->child; |
|
449 |
thr->state = QUE_THR_COMPLETED; |
|
450 |
||
451 |
thr = UT_LIST_GET_NEXT(thrs, thr); |
|
452 |
}
|
|
453 |
||
454 |
thr = UT_LIST_GET_FIRST(fork->thrs); |
|
455 |
||
456 |
que_thr_move_to_run_state(thr); |
|
457 |
||
458 |
ut_a(0); |
|
459 |
srv_que_task_enqueue_low(thr); |
|
460 |
}
|
|
461 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
462 |
/****************************************************************//**
|
463 |
Tests if all the query threads in the same fork have a given state.
|
|
464 |
@return TRUE if all the query threads in the same fork were in the
|
|
465 |
given state */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
466 |
UNIV_INLINE
|
467 |
ibool
|
|
468 |
que_fork_all_thrs_in_state( |
|
469 |
/*=======================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
470 |
que_fork_t* fork, /*!< in: query fork */ |
471 |
ulint state) /*!< in: state */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
472 |
{
|
473 |
que_thr_t* thr_node; |
|
474 |
||
475 |
thr_node = UT_LIST_GET_FIRST(fork->thrs); |
|
476 |
||
477 |
while (thr_node != NULL) { |
|
478 |
if (thr_node->state != state) { |
|
479 |
||
480 |
return(FALSE); |
|
481 |
}
|
|
482 |
||
483 |
thr_node = UT_LIST_GET_NEXT(thrs, thr_node); |
|
484 |
}
|
|
485 |
||
486 |
return(TRUE); |
|
487 |
}
|
|
488 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
489 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
490 |
Calls que_graph_free_recursive for statements in a statement list. */
|
491 |
static
|
|
492 |
void
|
|
493 |
que_graph_free_stat_list( |
|
494 |
/*=====================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
495 |
que_node_t* node) /*!< in: first query graph node in the list */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
496 |
{
|
497 |
while (node) { |
|
498 |
que_graph_free_recursive(node); |
|
499 |
||
500 |
node = que_node_get_next(node); |
|
501 |
}
|
|
502 |
}
|
|
503 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
504 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
505 |
Frees a query graph, but not the heap where it was created. Does not free
|
506 |
explicit cursor declarations, they are freed in que_graph_free. */
|
|
507 |
UNIV_INTERN
|
|
508 |
void
|
|
509 |
que_graph_free_recursive( |
|
510 |
/*=====================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
511 |
que_node_t* node) /*!< in: query graph node */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
512 |
{
|
513 |
que_fork_t* fork; |
|
514 |
que_thr_t* thr; |
|
515 |
undo_node_t* undo; |
|
516 |
sel_node_t* sel; |
|
517 |
ins_node_t* ins; |
|
518 |
upd_node_t* upd; |
|
519 |
tab_node_t* cre_tab; |
|
520 |
ind_node_t* cre_ind; |
|
1819.5.106
by stewart at flamingspork
[patch 106/129] Merge patch for revision 1915 from InnoDB SVN: |
521 |
purge_node_t* purge; |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
522 |
|
523 |
if (node == NULL) { |
|
524 |
||
525 |
return; |
|
526 |
}
|
|
527 |
||
528 |
switch (que_node_get_type(node)) { |
|
529 |
||
530 |
case QUE_NODE_FORK: |
|
531 |
fork = node; |
|
532 |
||
533 |
thr = UT_LIST_GET_FIRST(fork->thrs); |
|
534 |
||
535 |
while (thr) { |
|
536 |
que_graph_free_recursive(thr); |
|
537 |
||
538 |
thr = UT_LIST_GET_NEXT(thrs, thr); |
|
539 |
}
|
|
540 |
||
541 |
break; |
|
542 |
case QUE_NODE_THR: |
|
543 |
||
544 |
thr = node; |
|
545 |
||
546 |
if (thr->magic_n != QUE_THR_MAGIC_N) { |
|
547 |
fprintf(stderr, |
|
548 |
"que_thr struct appears corrupt;"
|
|
549 |
" magic n %lu\n", |
|
550 |
(unsigned long) thr->magic_n); |
|
551 |
mem_analyze_corruption(thr); |
|
552 |
ut_error; |
|
553 |
}
|
|
554 |
||
555 |
thr->magic_n = QUE_THR_MAGIC_FREED; |
|
556 |
||
557 |
que_graph_free_recursive(thr->child); |
|
558 |
||
559 |
break; |
|
560 |
case QUE_NODE_UNDO: |
|
561 |
||
562 |
undo = node; |
|
563 |
||
564 |
mem_heap_free(undo->heap); |
|
565 |
||
566 |
break; |
|
567 |
case QUE_NODE_SELECT: |
|
568 |
||
569 |
sel = node; |
|
570 |
||
571 |
sel_node_free_private(sel); |
|
572 |
||
573 |
break; |
|
574 |
case QUE_NODE_INSERT: |
|
575 |
||
576 |
ins = node; |
|
577 |
||
578 |
que_graph_free_recursive(ins->select); |
|
579 |
||
580 |
mem_heap_free(ins->entry_sys_heap); |
|
581 |
||
582 |
break; |
|
1819.5.106
by stewart at flamingspork
[patch 106/129] Merge patch for revision 1915 from InnoDB SVN: |
583 |
case QUE_NODE_PURGE: |
584 |
purge = node; |
|
585 |
||
586 |
mem_heap_free(purge->heap); |
|
587 |
||
588 |
break; |
|
589 |
||
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
590 |
case QUE_NODE_UPDATE: |
591 |
||
592 |
upd = node; |
|
593 |
||
594 |
if (upd->in_mysql_interface) { |
|
595 |
||
596 |
btr_pcur_free_for_mysql(upd->pcur); |
|
597 |
}
|
|
598 |
||
599 |
que_graph_free_recursive(upd->cascade_node); |
|
600 |
||
601 |
if (upd->cascade_heap) { |
|
602 |
mem_heap_free(upd->cascade_heap); |
|
603 |
}
|
|
604 |
||
605 |
que_graph_free_recursive(upd->select); |
|
606 |
||
607 |
mem_heap_free(upd->heap); |
|
608 |
||
609 |
break; |
|
610 |
case QUE_NODE_CREATE_TABLE: |
|
611 |
cre_tab = node; |
|
612 |
||
613 |
que_graph_free_recursive(cre_tab->tab_def); |
|
614 |
que_graph_free_recursive(cre_tab->col_def); |
|
615 |
que_graph_free_recursive(cre_tab->commit_node); |
|
616 |
||
617 |
mem_heap_free(cre_tab->heap); |
|
618 |
||
619 |
break; |
|
620 |
case QUE_NODE_CREATE_INDEX: |
|
621 |
cre_ind = node; |
|
622 |
||
623 |
que_graph_free_recursive(cre_ind->ind_def); |
|
624 |
que_graph_free_recursive(cre_ind->field_def); |
|
625 |
que_graph_free_recursive(cre_ind->commit_node); |
|
626 |
||
627 |
mem_heap_free(cre_ind->heap); |
|
628 |
||
629 |
break; |
|
630 |
case QUE_NODE_PROC: |
|
631 |
que_graph_free_stat_list(((proc_node_t*)node)->stat_list); |
|
632 |
||
633 |
break; |
|
634 |
case QUE_NODE_IF: |
|
635 |
que_graph_free_stat_list(((if_node_t*)node)->stat_list); |
|
636 |
que_graph_free_stat_list(((if_node_t*)node)->else_part); |
|
637 |
que_graph_free_stat_list(((if_node_t*)node)->elsif_list); |
|
638 |
||
639 |
break; |
|
640 |
case QUE_NODE_ELSIF: |
|
641 |
que_graph_free_stat_list(((elsif_node_t*)node)->stat_list); |
|
642 |
||
643 |
break; |
|
644 |
case QUE_NODE_WHILE: |
|
645 |
que_graph_free_stat_list(((while_node_t*)node)->stat_list); |
|
646 |
||
647 |
break; |
|
648 |
case QUE_NODE_FOR: |
|
649 |
que_graph_free_stat_list(((for_node_t*)node)->stat_list); |
|
650 |
||
651 |
break; |
|
652 |
||
653 |
case QUE_NODE_ASSIGNMENT: |
|
654 |
case QUE_NODE_EXIT: |
|
655 |
case QUE_NODE_RETURN: |
|
656 |
case QUE_NODE_COMMIT: |
|
657 |
case QUE_NODE_ROLLBACK: |
|
658 |
case QUE_NODE_LOCK: |
|
659 |
case QUE_NODE_FUNC: |
|
660 |
case QUE_NODE_ORDER: |
|
661 |
case QUE_NODE_ROW_PRINTF: |
|
662 |
case QUE_NODE_OPEN: |
|
663 |
case QUE_NODE_FETCH: |
|
664 |
/* No need to do anything */
|
|
665 |
||
666 |
break; |
|
667 |
default: |
|
668 |
fprintf(stderr, |
|
669 |
"que_node struct appears corrupt; type %lu\n", |
|
670 |
(unsigned long) que_node_get_type(node)); |
|
671 |
mem_analyze_corruption(node); |
|
672 |
ut_error; |
|
673 |
}
|
|
674 |
}
|
|
675 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
676 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
677 |
Frees a query graph. */
|
678 |
UNIV_INTERN
|
|
679 |
void
|
|
680 |
que_graph_free( |
|
681 |
/*===========*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
682 |
que_t* graph) /*!< in: query graph; we assume that the memory |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
683 |
heap where this graph was created is private
|
684 |
to this graph: if not, then use
|
|
685 |
que_graph_free_recursive and free the heap
|
|
686 |
afterwards! */
|
|
687 |
{
|
|
688 |
ut_ad(graph); |
|
689 |
||
690 |
if (graph->sym_tab) { |
|
691 |
/* The following call frees dynamic memory allocated
|
|
692 |
for variables etc. during execution. Frees also explicit
|
|
693 |
cursor definitions. */
|
|
694 |
||
695 |
sym_tab_free_private(graph->sym_tab); |
|
696 |
}
|
|
697 |
||
698 |
if (graph->info && graph->info->graph_owns_us) { |
|
699 |
pars_info_free(graph->info); |
|
700 |
}
|
|
701 |
||
702 |
que_graph_free_recursive(graph); |
|
703 |
||
704 |
mem_heap_free(graph->heap); |
|
705 |
}
|
|
706 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
707 |
/****************************************************************//**
|
708 |
Performs an execution step on a thr node.
|
|
709 |
@return query thread to run next, or NULL if none */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
710 |
static
|
711 |
que_thr_t* |
|
712 |
que_thr_node_step( |
|
713 |
/*==============*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
714 |
que_thr_t* thr) /*!< in: query thread where run_node must |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
715 |
be the thread node itself */
|
716 |
{
|
|
717 |
ut_ad(thr->run_node == thr); |
|
718 |
||
719 |
if (thr->prev_node == thr->common.parent) { |
|
720 |
/* If control to the node came from above, it is just passed
|
|
721 |
on */
|
|
722 |
||
723 |
thr->run_node = thr->child; |
|
724 |
||
725 |
return(thr); |
|
726 |
}
|
|
727 |
||
728 |
mutex_enter(&kernel_mutex); |
|
729 |
||
730 |
if (que_thr_peek_stop(thr)) { |
|
731 |
||
732 |
mutex_exit(&kernel_mutex); |
|
733 |
||
734 |
return(thr); |
|
735 |
}
|
|
736 |
||
737 |
/* Thread execution completed */
|
|
738 |
||
739 |
thr->state = QUE_THR_COMPLETED; |
|
740 |
||
741 |
mutex_exit(&kernel_mutex); |
|
742 |
||
743 |
return(NULL); |
|
744 |
}
|
|
745 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
746 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
747 |
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
|
748 |
the n_active_thrs counters of the query graph and transaction if thr was
|
|
749 |
not active.
|
|
750 |
***NOTE***: This and ..._mysql are the only functions in which such a
|
|
751 |
transition is allowed to happen! */
|
|
752 |
static
|
|
753 |
void
|
|
754 |
que_thr_move_to_run_state( |
|
755 |
/*======================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
756 |
que_thr_t* thr) /*!< in: an query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
757 |
{
|
758 |
trx_t* trx; |
|
759 |
||
760 |
ut_ad(thr->state != QUE_THR_RUNNING); |
|
761 |
||
762 |
trx = thr_get_trx(thr); |
|
763 |
||
764 |
if (!thr->is_active) { |
|
765 |
||
766 |
(thr->graph)->n_active_thrs++; |
|
767 |
||
768 |
trx->n_active_thrs++; |
|
769 |
||
770 |
thr->is_active = TRUE; |
|
771 |
||
772 |
ut_ad((thr->graph)->n_active_thrs == 1); |
|
773 |
ut_ad(trx->n_active_thrs == 1); |
|
774 |
}
|
|
775 |
||
776 |
thr->state = QUE_THR_RUNNING; |
|
777 |
}
|
|
778 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
779 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
780 |
Decrements the query thread reference counts in the query graph and the
|
781 |
transaction. May start signal handling, e.g., a rollback.
|
|
782 |
*** NOTE ***:
|
|
783 |
This and que_thr_stop_for_mysql are the only functions where the reference
|
|
784 |
count can be decremented and this function may only be called from inside
|
|
785 |
que_run_threads or que_thr_check_if_switch! These restrictions exist to make
|
|
786 |
the rollback code easier to maintain. */
|
|
787 |
static
|
|
788 |
void
|
|
789 |
que_thr_dec_refer_count( |
|
790 |
/*====================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
791 |
que_thr_t* thr, /*!< in: query thread */ |
792 |
que_thr_t** next_thr) /*!< in/out: next query thread to run; |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
793 |
if the value which is passed in is
|
794 |
a pointer to a NULL pointer, then the
|
|
795 |
calling function can start running
|
|
796 |
a new query thread */
|
|
797 |
{
|
|
798 |
que_fork_t* fork; |
|
799 |
trx_t* trx; |
|
800 |
ulint fork_type; |
|
801 |
ibool stopped; |
|
802 |
||
803 |
fork = thr->common.parent; |
|
804 |
trx = thr_get_trx(thr); |
|
805 |
||
806 |
mutex_enter(&kernel_mutex); |
|
807 |
||
808 |
ut_a(thr->is_active); |
|
809 |
||
810 |
if (thr->state == QUE_THR_RUNNING) { |
|
811 |
||
812 |
stopped = que_thr_stop(thr); |
|
813 |
||
814 |
if (!stopped) { |
|
815 |
/* The reason for the thr suspension or wait was
|
|
816 |
already canceled before we came here: continue
|
|
817 |
running the thread */
|
|
818 |
||
819 |
/* fputs("!!!!!!!! Wait already ended: continue thr\n",
|
|
820 |
stderr); */
|
|
821 |
||
822 |
if (next_thr && *next_thr == NULL) { |
|
823 |
/* Normally srv_suspend_mysql_thread resets
|
|
824 |
the state to DB_SUCCESS before waiting, but
|
|
825 |
in this case we have to do it here,
|
|
826 |
otherwise nobody does it. */
|
|
827 |
trx->error_state = DB_SUCCESS; |
|
828 |
||
829 |
*next_thr = thr; |
|
830 |
} else { |
|
831 |
ut_error; |
|
832 |
srv_que_task_enqueue_low(thr); |
|
833 |
}
|
|
834 |
||
835 |
mutex_exit(&kernel_mutex); |
|
836 |
||
837 |
return; |
|
838 |
}
|
|
839 |
}
|
|
840 |
||
841 |
ut_ad(fork->n_active_thrs == 1); |
|
842 |
ut_ad(trx->n_active_thrs == 1); |
|
843 |
||
844 |
fork->n_active_thrs--; |
|
845 |
trx->n_active_thrs--; |
|
846 |
||
847 |
thr->is_active = FALSE; |
|
848 |
||
849 |
if (trx->n_active_thrs > 0) { |
|
850 |
||
851 |
mutex_exit(&kernel_mutex); |
|
852 |
||
853 |
return; |
|
854 |
}
|
|
855 |
||
856 |
fork_type = fork->fork_type; |
|
857 |
||
858 |
/* Check if all query threads in the same fork are completed */
|
|
859 |
||
860 |
if (que_fork_all_thrs_in_state(fork, QUE_THR_COMPLETED)) { |
|
861 |
||
862 |
switch (fork_type) { |
|
863 |
case QUE_FORK_ROLLBACK: |
|
864 |
/* This is really the undo graph used in rollback,
|
|
865 |
no roll_node in this graph */
|
|
866 |
||
867 |
ut_ad(UT_LIST_GET_LEN(trx->signals) > 0); |
|
868 |
ut_ad(trx->handling_signals == TRUE); |
|
869 |
||
870 |
trx_finish_rollback_off_kernel(fork, trx, next_thr); |
|
871 |
break; |
|
872 |
||
873 |
case QUE_FORK_PURGE: |
|
874 |
case QUE_FORK_RECOVERY: |
|
875 |
case QUE_FORK_MYSQL_INTERFACE: |
|
876 |
||
877 |
/* Do nothing */
|
|
878 |
break; |
|
879 |
||
880 |
default: |
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
881 |
ut_error; /*!< not used in MySQL */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
882 |
}
|
883 |
}
|
|
884 |
||
885 |
if (UT_LIST_GET_LEN(trx->signals) > 0 && trx->n_active_thrs == 0) { |
|
886 |
||
887 |
/* If the trx is signaled and its query thread count drops to
|
|
888 |
zero, then we start processing a signal; from it we may get
|
|
889 |
a new query thread to run */
|
|
890 |
||
891 |
trx_sig_start_handle(trx, next_thr); |
|
892 |
}
|
|
893 |
||
894 |
if (trx->handling_signals && UT_LIST_GET_LEN(trx->signals) == 0) { |
|
895 |
||
896 |
trx_end_signal_handling(trx); |
|
897 |
}
|
|
898 |
||
899 |
mutex_exit(&kernel_mutex); |
|
900 |
}
|
|
901 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
902 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
903 |
Stops a query thread if graph or trx is in a state requiring it. The
|
904 |
conditions are tested in the order (1) graph, (2) trx. The kernel mutex has
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
905 |
to be reserved.
|
906 |
@return TRUE if stopped */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
907 |
UNIV_INTERN
|
908 |
ibool
|
|
909 |
que_thr_stop( |
|
910 |
/*=========*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
911 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
912 |
{
|
913 |
trx_t* trx; |
|
914 |
que_t* graph; |
|
915 |
ibool ret = TRUE; |
|
916 |
||
917 |
ut_ad(mutex_own(&kernel_mutex)); |
|
918 |
||
919 |
graph = thr->graph; |
|
920 |
trx = graph->trx; |
|
921 |
||
922 |
if (graph->state == QUE_FORK_COMMAND_WAIT) { |
|
923 |
thr->state = QUE_THR_SUSPENDED; |
|
924 |
||
925 |
} else if (trx->que_state == TRX_QUE_LOCK_WAIT) { |
|
926 |
||
927 |
UT_LIST_ADD_FIRST(trx_thrs, trx->wait_thrs, thr); |
|
928 |
thr->state = QUE_THR_LOCK_WAIT; |
|
929 |
||
930 |
} else if (trx->error_state != DB_SUCCESS |
|
931 |
&& trx->error_state != DB_LOCK_WAIT) { |
|
932 |
||
933 |
/* Error handling built for the MySQL interface */
|
|
934 |
thr->state = QUE_THR_COMPLETED; |
|
935 |
||
936 |
} else if (UT_LIST_GET_LEN(trx->signals) > 0 |
|
937 |
&& graph->fork_type != QUE_FORK_ROLLBACK) { |
|
938 |
||
939 |
thr->state = QUE_THR_SUSPENDED; |
|
940 |
} else { |
|
941 |
ut_ad(graph->state == QUE_FORK_ACTIVE); |
|
942 |
||
943 |
ret = FALSE; |
|
944 |
}
|
|
945 |
||
946 |
return(ret); |
|
947 |
}
|
|
948 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
949 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
950 |
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
|
951 |
query thread is stopped and made inactive, except in the case where
|
|
952 |
it was put to the lock wait state in lock0lock.c, but the lock has already
|
|
953 |
been granted or the transaction chosen as a victim in deadlock resolution. */
|
|
954 |
UNIV_INTERN
|
|
955 |
void
|
|
956 |
que_thr_stop_for_mysql( |
|
957 |
/*===================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
958 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
959 |
{
|
960 |
trx_t* trx; |
|
961 |
||
962 |
trx = thr_get_trx(thr); |
|
963 |
||
964 |
mutex_enter(&kernel_mutex); |
|
965 |
||
966 |
if (thr->state == QUE_THR_RUNNING) { |
|
967 |
||
968 |
if (trx->error_state != DB_SUCCESS |
|
969 |
&& trx->error_state != DB_LOCK_WAIT) { |
|
970 |
||
971 |
/* Error handling built for the MySQL interface */
|
|
972 |
thr->state = QUE_THR_COMPLETED; |
|
973 |
} else { |
|
974 |
/* It must have been a lock wait but the lock was
|
|
975 |
already released, or this transaction was chosen
|
|
976 |
as a victim in selective deadlock resolution */
|
|
977 |
||
978 |
mutex_exit(&kernel_mutex); |
|
979 |
||
980 |
return; |
|
981 |
}
|
|
982 |
}
|
|
983 |
||
984 |
ut_ad(thr->is_active == TRUE); |
|
985 |
ut_ad(trx->n_active_thrs == 1); |
|
986 |
ut_ad(thr->graph->n_active_thrs == 1); |
|
987 |
||
988 |
thr->is_active = FALSE; |
|
989 |
(thr->graph)->n_active_thrs--; |
|
990 |
||
991 |
trx->n_active_thrs--; |
|
992 |
||
993 |
mutex_exit(&kernel_mutex); |
|
994 |
}
|
|
995 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
996 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
997 |
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
|
998 |
the n_active_thrs counters of the query graph and transaction if thr was
|
|
999 |
not active. */
|
|
1000 |
UNIV_INTERN
|
|
1001 |
void
|
|
1002 |
que_thr_move_to_run_state_for_mysql( |
|
1003 |
/*================================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1004 |
que_thr_t* thr, /*!< in: an query thread */ |
1005 |
trx_t* trx) /*!< in: transaction */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1006 |
{
|
1007 |
if (thr->magic_n != QUE_THR_MAGIC_N) { |
|
1008 |
fprintf(stderr, |
|
1009 |
"que_thr struct appears corrupt; magic n %lu\n", |
|
1010 |
(unsigned long) thr->magic_n); |
|
1011 |
||
1012 |
mem_analyze_corruption(thr); |
|
1013 |
||
1014 |
ut_error; |
|
1015 |
}
|
|
1016 |
||
1017 |
if (!thr->is_active) { |
|
1018 |
||
1019 |
thr->graph->n_active_thrs++; |
|
1020 |
||
1021 |
trx->n_active_thrs++; |
|
1022 |
||
1023 |
thr->is_active = TRUE; |
|
1024 |
}
|
|
1025 |
||
1026 |
thr->state = QUE_THR_RUNNING; |
|
1027 |
}
|
|
1028 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1029 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1030 |
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
|
1031 |
select, when there is no error or lock wait. */
|
|
1032 |
UNIV_INTERN
|
|
1033 |
void
|
|
1034 |
que_thr_stop_for_mysql_no_error( |
|
1035 |
/*============================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1036 |
que_thr_t* thr, /*!< in: query thread */ |
1037 |
trx_t* trx) /*!< in: transaction */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1038 |
{
|
1039 |
ut_ad(thr->state == QUE_THR_RUNNING); |
|
1040 |
ut_ad(thr->is_active == TRUE); |
|
1041 |
ut_ad(trx->n_active_thrs == 1); |
|
1042 |
ut_ad(thr->graph->n_active_thrs == 1); |
|
1043 |
||
1044 |
if (thr->magic_n != QUE_THR_MAGIC_N) { |
|
1045 |
fprintf(stderr, |
|
1046 |
"que_thr struct appears corrupt; magic n %lu\n", |
|
1047 |
(unsigned long) thr->magic_n); |
|
1048 |
||
1049 |
mem_analyze_corruption(thr); |
|
1050 |
||
1051 |
ut_error; |
|
1052 |
}
|
|
1053 |
||
1054 |
thr->state = QUE_THR_COMPLETED; |
|
1055 |
||
1056 |
thr->is_active = FALSE; |
|
1057 |
(thr->graph)->n_active_thrs--; |
|
1058 |
||
1059 |
trx->n_active_thrs--; |
|
1060 |
}
|
|
1061 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1062 |
/****************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1063 |
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1064 |
given node, or NULL if the node is not within a loop.
|
1065 |
@return containing loop node, or NULL. */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1066 |
UNIV_INTERN
|
1067 |
que_node_t* |
|
1068 |
que_node_get_containing_loop_node( |
|
1069 |
/*==============================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1070 |
que_node_t* node) /*!< in: node */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1071 |
{
|
1072 |
ut_ad(node); |
|
1073 |
||
1074 |
for (;;) { |
|
1075 |
ulint type; |
|
1076 |
||
1077 |
node = que_node_get_parent(node); |
|
1078 |
||
1079 |
if (!node) { |
|
1080 |
break; |
|
1081 |
}
|
|
1082 |
||
1083 |
type = que_node_get_type(node); |
|
1084 |
||
1085 |
if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) { |
|
1086 |
break; |
|
1087 |
}
|
|
1088 |
}
|
|
1089 |
||
1090 |
return(node); |
|
1091 |
}
|
|
1092 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1093 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1094 |
Prints info of an SQL query graph node. */
|
1095 |
UNIV_INTERN
|
|
1096 |
void
|
|
1097 |
que_node_print_info( |
|
1098 |
/*================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1099 |
que_node_t* node) /*!< in: query graph node */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1100 |
{
|
1101 |
ulint type; |
|
1102 |
const char* str; |
|
1103 |
||
1104 |
type = que_node_get_type(node); |
|
1105 |
||
1106 |
if (type == QUE_NODE_SELECT) { |
|
1107 |
str = "SELECT"; |
|
1108 |
} else if (type == QUE_NODE_INSERT) { |
|
1109 |
str = "INSERT"; |
|
1110 |
} else if (type == QUE_NODE_UPDATE) { |
|
1111 |
str = "UPDATE"; |
|
1112 |
} else if (type == QUE_NODE_WHILE) { |
|
1113 |
str = "WHILE"; |
|
1114 |
} else if (type == QUE_NODE_ASSIGNMENT) { |
|
1115 |
str = "ASSIGNMENT"; |
|
1116 |
} else if (type == QUE_NODE_IF) { |
|
1117 |
str = "IF"; |
|
1118 |
} else if (type == QUE_NODE_FETCH) { |
|
1119 |
str = "FETCH"; |
|
1120 |
} else if (type == QUE_NODE_OPEN) { |
|
1121 |
str = "OPEN"; |
|
1122 |
} else if (type == QUE_NODE_PROC) { |
|
1123 |
str = "STORED PROCEDURE"; |
|
1124 |
} else if (type == QUE_NODE_FUNC) { |
|
1125 |
str = "FUNCTION"; |
|
1126 |
} else if (type == QUE_NODE_LOCK) { |
|
1127 |
str = "LOCK"; |
|
1128 |
} else if (type == QUE_NODE_THR) { |
|
1129 |
str = "QUERY THREAD"; |
|
1130 |
} else if (type == QUE_NODE_COMMIT) { |
|
1131 |
str = "COMMIT"; |
|
1132 |
} else if (type == QUE_NODE_UNDO) { |
|
1133 |
str = "UNDO ROW"; |
|
1134 |
} else if (type == QUE_NODE_PURGE) { |
|
1135 |
str = "PURGE ROW"; |
|
1136 |
} else if (type == QUE_NODE_ROLLBACK) { |
|
1137 |
str = "ROLLBACK"; |
|
1138 |
} else if (type == QUE_NODE_CREATE_TABLE) { |
|
1139 |
str = "CREATE TABLE"; |
|
1140 |
} else if (type == QUE_NODE_CREATE_INDEX) { |
|
1141 |
str = "CREATE INDEX"; |
|
1142 |
} else if (type == QUE_NODE_FOR) { |
|
1143 |
str = "FOR LOOP"; |
|
1144 |
} else if (type == QUE_NODE_RETURN) { |
|
1145 |
str = "RETURN"; |
|
1146 |
} else if (type == QUE_NODE_EXIT) { |
|
1147 |
str = "EXIT"; |
|
1148 |
} else { |
|
1149 |
str = "UNKNOWN NODE TYPE"; |
|
1150 |
}
|
|
1151 |
||
1152 |
fprintf(stderr, "Node type %lu: %s, address %p\n", |
|
1153 |
(ulong) type, str, (void*) node); |
|
1154 |
}
|
|
1155 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1156 |
/**********************************************************************//**
|
1157 |
Performs an execution step on a query thread.
|
|
1158 |
@return query thread to run next: it may differ from the input
|
|
1159 |
parameter if, e.g., a subprocedure call is made */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1160 |
UNIV_INLINE
|
1161 |
que_thr_t* |
|
1162 |
que_thr_step( |
|
1163 |
/*=========*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1164 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1165 |
{
|
1166 |
que_node_t* node; |
|
1167 |
que_thr_t* old_thr; |
|
1168 |
trx_t* trx; |
|
1169 |
ulint type; |
|
1170 |
||
1171 |
trx = thr_get_trx(thr); |
|
1172 |
||
1173 |
ut_ad(thr->state == QUE_THR_RUNNING); |
|
1174 |
ut_a(trx->error_state == DB_SUCCESS); |
|
1175 |
||
1176 |
thr->resource++; |
|
1177 |
||
1178 |
node = thr->run_node; |
|
1179 |
type = que_node_get_type(node); |
|
1180 |
||
1181 |
old_thr = thr; |
|
1182 |
||
1183 |
#ifdef UNIV_DEBUG
|
|
1184 |
if (que_trace_on) { |
|
1185 |
fputs("To execute: ", stderr); |
|
1186 |
que_node_print_info(node); |
|
1187 |
}
|
|
1188 |
#endif
|
|
1189 |
if (type & QUE_NODE_CONTROL_STAT) { |
|
1190 |
if ((thr->prev_node != que_node_get_parent(node)) |
|
1191 |
&& que_node_get_next(thr->prev_node)) { |
|
1192 |
||
1193 |
/* The control statements, like WHILE, always pass the
|
|
1194 |
control to the next child statement if there is any
|
|
1195 |
child left */
|
|
1196 |
||
1197 |
thr->run_node = que_node_get_next(thr->prev_node); |
|
1198 |
||
1199 |
} else if (type == QUE_NODE_IF) { |
|
1200 |
if_step(thr); |
|
1201 |
} else if (type == QUE_NODE_FOR) { |
|
1202 |
for_step(thr); |
|
1203 |
} else if (type == QUE_NODE_PROC) { |
|
1204 |
||
1205 |
/* We can access trx->undo_no without reserving
|
|
1206 |
trx->undo_mutex, because there cannot be active query
|
|
1207 |
threads doing updating or inserting at the moment! */
|
|
1208 |
||
1209 |
if (thr->prev_node == que_node_get_parent(node)) { |
|
1210 |
trx->last_sql_stat_start.least_undo_no |
|
1211 |
= trx->undo_no; |
|
1212 |
}
|
|
1213 |
||
1214 |
proc_step(thr); |
|
1215 |
} else if (type == QUE_NODE_WHILE) { |
|
1216 |
while_step(thr); |
|
1217 |
} else { |
|
1218 |
ut_error; |
|
1219 |
}
|
|
1220 |
} else if (type == QUE_NODE_ASSIGNMENT) { |
|
1221 |
assign_step(thr); |
|
1222 |
} else if (type == QUE_NODE_SELECT) { |
|
1223 |
thr = row_sel_step(thr); |
|
1224 |
} else if (type == QUE_NODE_INSERT) { |
|
1225 |
thr = row_ins_step(thr); |
|
1226 |
} else if (type == QUE_NODE_UPDATE) { |
|
1227 |
thr = row_upd_step(thr); |
|
1228 |
} else if (type == QUE_NODE_FETCH) { |
|
1229 |
thr = fetch_step(thr); |
|
1230 |
} else if (type == QUE_NODE_OPEN) { |
|
1231 |
thr = open_step(thr); |
|
1232 |
} else if (type == QUE_NODE_FUNC) { |
|
1233 |
proc_eval_step(thr); |
|
1234 |
||
1235 |
} else if (type == QUE_NODE_LOCK) { |
|
1236 |
||
1237 |
ut_error; |
|
1238 |
/*
|
|
1239 |
thr = que_lock_step(thr);
|
|
1240 |
*/
|
|
1241 |
} else if (type == QUE_NODE_THR) { |
|
1242 |
thr = que_thr_node_step(thr); |
|
1243 |
} else if (type == QUE_NODE_COMMIT) { |
|
1244 |
thr = trx_commit_step(thr); |
|
1245 |
} else if (type == QUE_NODE_UNDO) { |
|
1246 |
thr = row_undo_step(thr); |
|
1247 |
} else if (type == QUE_NODE_PURGE) { |
|
1248 |
thr = row_purge_step(thr); |
|
1249 |
} else if (type == QUE_NODE_RETURN) { |
|
1250 |
thr = return_step(thr); |
|
1251 |
} else if (type == QUE_NODE_EXIT) { |
|
1252 |
thr = exit_step(thr); |
|
1253 |
} else if (type == QUE_NODE_ROLLBACK) { |
|
1254 |
thr = trx_rollback_step(thr); |
|
1255 |
} else if (type == QUE_NODE_CREATE_TABLE) { |
|
1256 |
thr = dict_create_table_step(thr); |
|
1257 |
} else if (type == QUE_NODE_CREATE_INDEX) { |
|
1258 |
thr = dict_create_index_step(thr); |
|
1259 |
} else if (type == QUE_NODE_ROW_PRINTF) { |
|
1260 |
thr = row_printf_step(thr); |
|
1261 |
} else { |
|
1262 |
ut_error; |
|
1263 |
}
|
|
1264 |
||
1265 |
if (type == QUE_NODE_EXIT) { |
|
1266 |
old_thr->prev_node = que_node_get_containing_loop_node(node); |
|
1267 |
} else { |
|
1268 |
old_thr->prev_node = node; |
|
1269 |
}
|
|
1270 |
||
1271 |
if (thr) { |
|
1272 |
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS); |
|
1273 |
}
|
|
1274 |
||
1275 |
return(thr); |
|
1276 |
}
|
|
1277 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1278 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1279 |
Run a query thread until it finishes or encounters e.g. a lock wait. */
|
1280 |
static
|
|
1281 |
void
|
|
1282 |
que_run_threads_low( |
|
1283 |
/*================*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1284 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1285 |
{
|
1286 |
que_thr_t* next_thr; |
|
1287 |
ulint cumul_resource; |
|
1288 |
ulint loop_count; |
|
1289 |
||
1290 |
ut_ad(thr->state == QUE_THR_RUNNING); |
|
1291 |
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS); |
|
1292 |
ut_ad(!mutex_own(&kernel_mutex)); |
|
1293 |
||
1294 |
/* cumul_resource counts how much resources the OS thread (NOT the
|
|
1295 |
query thread) has spent in this function */
|
|
1296 |
||
1297 |
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK; |
|
1298 |
cumul_resource = 0; |
|
1299 |
loop: |
|
1300 |
/* Check that there is enough space in the log to accommodate
|
|
1301 |
possible log entries by this query step; if the operation can touch
|
|
1302 |
more than about 4 pages, checks must be made also within the query
|
|
1303 |
step! */
|
|
1304 |
||
1305 |
log_free_check(); |
|
1306 |
||
1307 |
/* Perform the actual query step: note that the query thread
|
|
1308 |
may change if, e.g., a subprocedure call is made */
|
|
1309 |
||
1310 |
/*-------------------------*/
|
|
1311 |
next_thr = que_thr_step(thr); |
|
1312 |
/*-------------------------*/
|
|
1313 |
||
1314 |
ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS)); |
|
1315 |
||
1316 |
loop_count++; |
|
1317 |
||
1318 |
if (next_thr != thr) { |
|
1319 |
ut_a(next_thr == NULL); |
|
1320 |
||
1321 |
/* This can change next_thr to a non-NULL value if there was
|
|
1322 |
a lock wait that already completed. */
|
|
1323 |
que_thr_dec_refer_count(thr, &next_thr); |
|
1324 |
||
1325 |
if (next_thr == NULL) { |
|
1326 |
||
1327 |
return; |
|
1328 |
}
|
|
1329 |
||
1330 |
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK; |
|
1331 |
||
1332 |
thr = next_thr; |
|
1333 |
}
|
|
1334 |
||
1335 |
goto loop; |
|
1336 |
}
|
|
1337 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1338 |
/**********************************************************************//**
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1339 |
Run a query thread. Handles lock waits. */
|
1340 |
UNIV_INTERN
|
|
1341 |
void
|
|
1342 |
que_run_threads( |
|
1343 |
/*============*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1344 |
que_thr_t* thr) /*!< in: query thread */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1345 |
{
|
1346 |
loop: |
|
1347 |
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS); |
|
1348 |
que_run_threads_low(thr); |
|
1349 |
||
1350 |
mutex_enter(&kernel_mutex); |
|
1351 |
||
1352 |
switch (thr->state) { |
|
1353 |
||
1354 |
case QUE_THR_RUNNING: |
|
1355 |
/* There probably was a lock wait, but it already ended
|
|
1356 |
before we came here: continue running thr */
|
|
1357 |
||
1358 |
mutex_exit(&kernel_mutex); |
|
1359 |
||
1360 |
goto loop; |
|
1361 |
||
1362 |
case QUE_THR_LOCK_WAIT: |
|
1363 |
mutex_exit(&kernel_mutex); |
|
1364 |
||
1365 |
/* The ..._mysql_... function works also for InnoDB's
|
|
1366 |
internal threads. Let us wait that the lock wait ends. */
|
|
1367 |
||
1368 |
srv_suspend_mysql_thread(thr); |
|
1369 |
||
1370 |
if (thr_get_trx(thr)->error_state != DB_SUCCESS) { |
|
1371 |
/* thr was chosen as a deadlock victim or there was
|
|
1372 |
a lock wait timeout */
|
|
1373 |
||
1374 |
que_thr_dec_refer_count(thr, NULL); |
|
1375 |
||
1376 |
return; |
|
1377 |
}
|
|
1378 |
||
1379 |
goto loop; |
|
1380 |
||
1381 |
case QUE_THR_COMPLETED: |
|
1382 |
case QUE_THR_COMMAND_WAIT: |
|
1383 |
/* Do nothing */
|
|
1384 |
break; |
|
1385 |
||
1386 |
default: |
|
1387 |
ut_error; |
|
1388 |
}
|
|
1389 |
||
1390 |
mutex_exit(&kernel_mutex); |
|
1391 |
}
|
|
1392 |
||
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1393 |
/*********************************************************************//**
|
1394 |
Evaluate the given SQL.
|
|
1395 |
@return error code or DB_SUCCESS */
|
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1396 |
UNIV_INTERN
|
1397 |
ulint
|
|
1398 |
que_eval_sql( |
|
1399 |
/*=========*/
|
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1400 |
pars_info_t* info, /*!< in: info struct, or NULL */ |
1401 |
const char* sql, /*!< in: SQL string */ |
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1402 |
ibool reserve_dict_mutex, |
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1403 |
/*!< in: if TRUE, acquire/release
|
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1404 |
dict_sys->mutex around call to pars_sql. */
|
641.2.3
by Monty Taylor
InnoDB Plugin 1.0.4 |
1405 |
trx_t* trx) /*!< in: trx */ |
641.1.2
by Monty Taylor
Imported 1.0.1 with clean - with no changes. |
1406 |
{
|
1407 |
que_thr_t* thr; |
|
1408 |
que_t* graph; |
|
1409 |
||
1410 |
ut_a(trx->error_state == DB_SUCCESS); |
|
1411 |
||
1412 |
if (reserve_dict_mutex) { |
|
1413 |
mutex_enter(&dict_sys->mutex); |
|
1414 |
}
|
|
1415 |
||
1416 |
graph = pars_sql(info, sql); |
|
1417 |
||
1418 |
if (reserve_dict_mutex) { |
|
1419 |
mutex_exit(&dict_sys->mutex); |
|
1420 |
}
|
|
1421 |
||
1422 |
ut_a(graph); |
|
1423 |
||
1424 |
graph->trx = trx; |
|
1425 |
trx->graph = NULL; |
|
1426 |
||
1427 |
graph->fork_type = QUE_FORK_MYSQL_INTERFACE; |
|
1428 |
||
1429 |
ut_a(thr = que_fork_start_command(graph)); |
|
1430 |
||
1431 |
que_run_threads(thr); |
|
1432 |
||
1433 |
que_graph_free(graph); |
|
1434 |
||
1435 |
return(trx->error_state); |
|
1436 |
}
|