Merge lp://staging/~clint-fewbar/drizzle/refactor-lock into lp://staging/~drizzle-trunk/drizzle/development

Proposed by Clint Byrum
Status: Rejected
Rejected by: Jay Pipes
Proposed branch: lp://staging/~clint-fewbar/drizzle/refactor-lock
Merge into: lp://staging/~drizzle-trunk/drizzle/development
Diff against target: 1657 lines
15 files modified
drizzled/cursor.h (+1/-1)
drizzled/join.cc (+4/-4)
drizzled/join.h (+1/-1)
drizzled/lock.cc (+337/-343)
drizzled/lock.h (+181/-12)
drizzled/open_tables_state.h (+3/-2)
drizzled/select_create.h (+3/-2)
drizzled/select_send.h (+1/-5)
drizzled/session.cc (+2/-14)
drizzled/session.h (+64/-8)
drizzled/sql_base.cc (+17/-26)
drizzled/sql_insert.cc (+16/-17)
drizzled/sql_table.cc (+3/-7)
drizzled/statement/alter_table.cc (+1/-5)
drizzled/table.h (+2/-2)
To merge this branch: bzr merge lp://staging/~clint-fewbar/drizzle/refactor-lock
Reviewer Review Type Date Requested Status
Jay Pipes Pending
Monty Taylor Pending
Review via email: mp+13689@code.staging.launchpad.net

This proposal supersedes a proposal from 2009-08-03.

To post a comment you must log in.
Revision history for this message
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal

* Refactors DRIZZLE_LOCK into drizzled::Lock
* Refactors major global locking functions as methods of either Session or drizzled::Lock

Revision history for this message
Monty Taylor (mordred) wrote : Posted in a previous version of this proposal

Looking really good. A few minor issues to work out:

in lock.cc, add a using namespace drizzled; right after using namespace std; Then you can remove the drizzled:: prefix throughout that file.

+drizzled::Lock *Session::lockTables(Table **tables, uint32_t count,
+ uint32_t flags, bool *need_reopen)
+int Session::lockExternal(Table **tables, uint32_t count)
+void Session::unlockSomeTables(Table **table,uint32_t count)
+void Session::abortLock(Table *table, bool upgrade_lock)
+bool Session::abortLockForThread(Table *table)
+int Session::unlockExternal(Table **table,uint32_t count)

This looks like it should actually live in session.cc? Or is there a reason there here?

In:

+void Session::unlockSomeTables(Table **table,uint32_t count)
+void Session::abortLock(Table *table, bool upgrade_lock)
+bool Session::abortLockForThread(Table *table)

Seems like you could replace:

drizzled::Lock *sql_lock= new (nothrow) drizzled::Lock;
with
drizzled::Lock sql_lock;
no?

+ memmove((table+x), (table+x+1),
+ (old_tables - x) * sizeof(Table*));
+ memmove((locks + tbl->lock_data_start),
+ (locks + lock_data_end),
+ (lock_count - lock_data_end) *
+ sizeof(THR_LOCK_DATA*));

The line-continuation style here should be:

+ memmove((table+x), (table+x+1),
+ (old_tables - x) * sizeof(Table*));

Is it possible for this:

drizzled::Lock::Lock(Lock *a, Lock *b)

to be

drizzled::Lock::Lock(const Lock &a, const Lock &b)

I won't die if it isn't. Oh! My! No it's not.

+ delete a;
+ delete b;

I'm not sure how I feel about that- but something tells me there are bigger implications to changing that.

review: Needs Fixing
Revision history for this message
Clint Byrum (clint-fewbar) wrote : Posted in a previous version of this proposal
Download full text (4.6 KiB)

On Aug 6, 2009, at 3:13 PM, Monty Taylor wrote:

> Review: Needs Fixing
> Looking really good. A few minor issues to work out:
>
> in lock.cc, add a using namespace drizzled; right after using
> namespace std; Then you can remove the drizzled:: prefix throughout
> that file.
>
> +drizzled::Lock *Session::lockTables(Table **tables, uint32_t count,
> + uint32_t flags, bool
> *need_reopen)
> +int Session::lockExternal(Table **tables, uint32_t count)
> +void Session::unlockSomeTables(Table **table,uint32_t count)
> +void Session::abortLock(Table *table, bool upgrade_lock)
> +bool Session::abortLockForThread(Table *table)
> +int Session::unlockExternal(Table **table,uint32_t count)
>
> This looks like it should actually live in session.cc? Or is there a
> reason there here?
>

The only reason I didn't do that was to keep the functions where they
originally lived, and some abiguity in the coding standards. The only
place this is mentioned (just checked again to make sure it hasn't
changed recently) is here:

http://drizzle.org/wiki/Coding_Standards#Class.2FStructure_File_Conventions

which states

"All new classes get their own .h and .cc files. We will need to pull
apart the mess that exists today, but that is a long term goal."

So, if that needs to happen now as part of this change, I'll go ahead
and move all of those methods to another file, however, I was thinking
that should be done as part of the larger effort to cleanup all the
rest of the functions in the file that need to be renamed and probably
done as methods of Session or TableList, namely:

TableList *mysql_lock_have_duplicate(Session *session, TableList
*needle,
                                      TableList *haystack);
bool lock_global_read_lock(Session *session);
void unlock_global_read_lock(Session *session);
bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
                               bool is_not_commit);
void start_waiting_global_read_lock(Session *session);
bool make_global_read_lock_block_commit(Session *session);

int lock_and_wait_for_table_name(Session *session, TableList
*table_list);
int lock_table_name(Session *session, TableList *table_list, bool
check_in_use);
void unlock_table_name(TableList *table_list);
bool wait_for_locked_table_names(Session *session, TableList
*table_list);
bool lock_table_names(Session *session, TableList *table_list);
void unlock_table_names(TableList *table_list, TableList *last_table);
bool lock_table_names_exclusively(Session *session, TableList
*table_list);

> In:
>
> +void Session::unlockSomeTables(Table **table,uint32_t count)
> +void Session::abortLock(Table *table, bool upgrade_lock)
> +bool Session::abortLockForThread(Table *table)
>
> Seems like you could replace:
>
> drizzled::Lock *sql_lock= new (nothrow) drizzled::Lock;
> with
> drizzled::Lock sql_lock;
> no?
>

Yes, done and tested.

It raises a question which is actually more obvious with the explicit
new/delete;

If initLockData() were to put 'this' into some other structure on the
heap, that would cause bad things to happen as 'this' will be deleted.
So, is there a way to get ...

Read more...

Revision history for this message
Jay Pipes (jaypipes) wrote :

Going to pull locally and take a good look at this. Clint, it may be that I request we break this patch up into style-only and non-style changes, because there is quite a bit to go through. I'll update you later today.

Cheers!

Jay

Revision history for this message
Jay Pipes (jaypipes) wrote :

Rejected per our conversation online. We'll split this up into smaller blueprints and use this work as a guide.

Unmerged revisions

1107. By Clint Byrum

merging trunk

1106. By Clint Byrum

statically declaring when appropriate and some formatting fixes

1105. By Clint Byrum

_external functions refactored as methods of Session

1104. By Clint Byrum

removing irrelevant comment

1103. By Clint Byrum

moving method to lock.cc

1102. By Clint Byrum

comment fix

1101. By Clint Byrum

formatting and doxygen fixes

1100. By Clint Byrum

merging w/ trunk

1099. By Clint Byrum

cleanups for coding standards

1098. By Clint Byrum

Refactoring DRIZZLE_LOCK into drizzled::Lock

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'drizzled/cursor.h'
2--- drizzled/cursor.h 2009-10-16 10:27:33 +0000
3+++ drizzled/cursor.h 2009-10-21 06:30:26 +0000
4@@ -602,7 +602,7 @@
5 or partitioned.
6
7 @note that one can NOT rely on table->in_use in store_lock(). It may
8- refer to a different thread if called from mysql_lock_abort_for_thread().
9+ refer to a different thread if called from Session::abortLockForThread().
10
11 @note If the table is MERGE, store_lock() can return less locks
12 than lock_count() claimed. This can happen when the MERGE children
13
14=== modified file 'drizzled/join.cc'
15--- drizzled/join.cc 2009-10-06 19:51:49 +0000
16+++ drizzled/join.cc 2009-10-21 06:30:26 +0000
17@@ -569,7 +569,7 @@
18 return 1;
19 }
20 if (const_tables && !(select_options & SELECT_NO_UNLOCK))
21- mysql_unlock_some_tables(session, table, const_tables);
22+ session->unlockSomeTables(table, const_tables);
23 if (!conds && outer_join)
24 {
25 /* Handle the case where we have an OUTER JOIN without a WHERE */
26@@ -1757,8 +1757,8 @@
27 is called after all rows are sent, but before EOF packet is sent.
28
29 For a simple SELECT with no subqueries this function performs a full
30- cleanup of the JOIN and calls mysql_unlock_read_tables to free used base
31- tables.
32+ cleanup of the JOIN and calls drizzled::Lock::unlockReadTables() to
33+ free used base tables.
34
35 If a JOIN is executed for a subquery or if it has a subquery, we can't
36 do the full cleanup and need to do a partial cleanup only.
37@@ -1829,7 +1829,7 @@
38 TODO: unlock tables even if the join isn't top level select in the
39 tree.
40 */
41- mysql_unlock_read_tables(session, lock); // Don't free join->lock
42+ lock->unlockReadTables(session); // Don't free join->lock
43 lock= 0;
44 }
45
46
47=== modified file 'drizzled/join.h'
48--- drizzled/join.h 2009-08-20 21:45:52 +0000
49+++ drizzled/join.h 2009-10-21 06:30:26 +0000
50@@ -174,7 +174,7 @@
51 uint64_t select_options;
52 select_result *result;
53 Tmp_Table_Param tmp_table_param;
54- DRIZZLE_LOCK *lock;
55+ drizzled::Lock *lock;
56
57 JOIN *tmp_join; /**< copy of this JOIN to be used with temporary tables */
58 ROLLUP rollup; /**< Used with rollup */
59
60=== modified file 'drizzled/lock.cc'
61--- drizzled/lock.cc 2009-08-11 03:02:59 +0000
62+++ drizzled/lock.cc 2009-10-21 06:30:26 +0000
63@@ -1,3 +1,4 @@
64+// vim:ts=2 sts=2 sw=2:et ai:
65 /* Copyright (C) 2000-2006 MySQL AB
66
67 This program is free software; you can redistribute it and/or modify
68@@ -27,18 +28,18 @@
69
70 When not using LOCK TABLES:
71
72- - For each SQL statement mysql_lock_tables() is called for all involved
73+ - For each SQL statement Session::lockTables() is called for all involved
74 tables.
75- - mysql_lock_tables() will call
76+ - Session::lockTables() will call
77 table_handler->external_lock(session,locktype) for each table.
78 This is followed by a call to thr_multi_lock() for all tables.
79
80- - When statement is done, we call mysql_unlock_tables().
81+ - When statement is done, we call Session::unlockTables().
82 This will call thr_multi_unlock() followed by
83 table_handler->external_lock(session, F_UNLCK) for each table.
84
85- - Note that mysql_unlock_tables() may be called several times as
86- MySQL in some cases can free some tables earlier than others.
87+ - Note that drizzled::Lock::unlockTables() may be called several times as
88+ Drizzle in some cases can free some tables earlier than others.
89
90 - The above is true both for normal and temporary tables.
91
92@@ -47,8 +48,8 @@
93
94 When using LOCK TABLES:
95
96- - LOCK Table will call mysql_lock_tables() for all tables.
97- mysql_lock_tables() will call
98+ - LOCK Table will call Session::lockTables() for all tables.
99+ Session::lockTables() will call
100 table_handler->external_lock(session,locktype) for each table.
101 This is followed by a call to thr_multi_lock() for all tables.
102
103@@ -60,7 +61,7 @@
104
105 - When statement is done, we will call ha_commit_stmt(session);
106
107- - When calling UNLOCK TABLES we call mysql_unlock_tables() for all
108+ - When calling UNLOCK TABLES we call drizzled::Lock::unlockTables() for all
109 tables used in LOCK TABLES
110
111 If table_handler->external_lock(session, locktype) fails, we call
112@@ -85,224 +86,210 @@
113 @{
114 */
115
116+using namespace std;
117+
118 extern HASH open_cache;
119
120-static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table,
121- uint32_t count,
122- bool should_lock, Table **write_locked);
123-static int lock_external(Session *session, Table **table,uint32_t count);
124-static int unlock_external(Session *session, Table **table,uint32_t count);
125 static void print_lock_error(int error, const char *);
126
127-/*
128- Lock tables.
129-
130- SYNOPSIS
131- mysql_lock_tables()
132- session The current thread.
133- tables An array of pointers to the tables to lock.
134- count The number of tables to lock.
135- flags Options:
136- DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
137- DRIZZLE_LOCK_IGNORE_FLUSH Ignore a flush tables.
138- DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
139- or dropped tables by itself,
140- mysql_lock_tables() should
141- notify upper level and rely
142- on caller doing this.
143- need_reopen Out parameter, TRUE if some tables were altered
144- or deleted and should be reopened by caller.
145-
146- RETURN
147- A lock structure pointer on success.
148- NULL on error or if some tables should be reopen.
149-*/
150
151 /* Map the return value of thr_lock to an error from errmsg.txt */
152 static int thr_lock_errno_to_mysql[]=
153 { 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
154
155
156-/**
157- Reset lock type in lock data and free.
158-
159- @param mysql_lock Lock structures to reset.
160-
161- @note After a locking error we want to quit the locking of the table(s).
162- The test case in the bug report for Bug #18544 has the following
163- cases: 1. Locking error in lock_external() due to InnoDB timeout.
164- 2. Locking error in get_lock_data() due to missing write permission.
165- 3. Locking error in wait_if_global_read_lock() due to lock conflict.
166-
167- @note In all these cases we have already set the lock type into the lock
168- data of the open table(s). If the table(s) are in the open table
169- cache, they could be reused with the non-zero lock type set. This
170- could lead to ignoring a different lock type with the next lock.
171-
172- @note Clear the lock type of all lock data. This ensures that the next
173- lock request will set its lock type properly.
174-*/
175-
176-static void reset_lock_data_and_free(DRIZZLE_LOCK **mysql_lock)
177-{
178- DRIZZLE_LOCK *sql_lock= *mysql_lock;
179+drizzled::Lock::~Lock()
180+{
181+ resetLockData();
182+}
183+
184+void drizzled::Lock::resetLockData()
185+{
186 THR_LOCK_DATA **ldata, **ldata_end;
187
188+
189 /* Clear the lock type of all lock data to avoid reusage. */
190- for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
191- ldata < ldata_end;
192- ldata++)
193+ if (locks)
194 {
195- /* Reset lock type. */
196- (*ldata)->type= TL_UNLOCK;
197+ for (ldata= locks, ldata_end= ldata + lock_count;
198+ ldata < ldata_end;
199+ ldata++)
200+ {
201+ /* Reset lock type. */
202+ (*ldata)->type= TL_UNLOCK;
203+ }
204+ free(locks);
205 }
206- free((unsigned char*) sql_lock);
207- *mysql_lock= 0;
208-}
209-
210-
211-DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **tables, uint32_t count,
212+}
213+
214+drizzled::Lock *Session::lockTables(Table **tables, uint32_t count,
215+ uint32_t flags, bool *need_reopen)
216+{
217+ drizzled::Lock *sql_lock= new (nothrow) drizzled::Lock;
218+
219+ if (sql_lock && sql_lock->lockTables(this, tables, count, flags, need_reopen))
220+ {
221+ return sql_lock;
222+ }
223+
224+ delete sql_lock;
225+
226+ return NULL;
227+}
228+
229+bool drizzled::Lock::lockTables(Session *session, Table **tables, uint32_t count,
230 uint32_t flags, bool *need_reopen)
231 {
232- DRIZZLE_LOCK *sql_lock;
233 Table *write_lock_used;
234 int rc;
235+ bool failed_locks= false;
236
237 *need_reopen= false;
238
239- for (;;)
240+ try
241 {
242- if (! (sql_lock= get_lock_data(session, tables, count, true,
243- &write_lock_used)))
244- break;
245-
246- if (global_read_lock && write_lock_used &&
247- ! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
248- {
249- /*
250- Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
251- Wait until the lock is gone
252- */
253- if (wait_if_global_read_lock(session, 1, 1))
254- {
255- /* Clear the lock type of all lock data to avoid reusage. */
256- reset_lock_data_and_free(&sql_lock);
257- break;
258- }
259- if (session->version != refresh_version)
260- {
261- /* Clear the lock type of all lock data to avoid reusage. */
262- reset_lock_data_and_free(&sql_lock);
263- goto retry;
264- }
265- }
266-
267- session->set_proc_info("System lock");
268- if (sql_lock->table_count && lock_external(session, sql_lock->table,
269- sql_lock->table_count))
270- {
271- /* Clear the lock type of all lock data to avoid reusage. */
272- reset_lock_data_and_free(&sql_lock);
273- break;
274- }
275- session->set_proc_info("Table lock");
276- /* Copy the lock data array. thr_multi_lock() reorders its contens. */
277- memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
278- sql_lock->lock_count * sizeof(*sql_lock->locks));
279- /* Lock on the copied half of the lock data array. */
280- rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks +
281- sql_lock->lock_count,
282- sql_lock->lock_count,
283- session->lock_id)];
284- if (rc > 1) /* a timeout or a deadlock */
285- {
286- if (sql_lock->table_count)
287- unlock_external(session, sql_lock->table, sql_lock->table_count);
288- reset_lock_data_and_free(&sql_lock);
289- my_error(rc, MYF(0));
290- break;
291- }
292- else if (rc == 1) /* aborted */
293- {
294- session->some_tables_deleted=1; // Try again
295- sql_lock->lock_count= 0; // Locks are already freed
296- // Fall through: unlock, reset lock data, free and retry
297- }
298- else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
299- {
300- /*
301- Thread was killed or lock aborted. Let upper level close all
302- used tables and retry or give error.
303- */
304- break;
305- }
306- else if (!session->open_tables)
307- {
308- // Only using temporary tables, no need to unlock
309- session->some_tables_deleted= 0;
310- break;
311- }
312- session->set_proc_info(0);
313-
314- /* going to retry, unlock all tables */
315- if (sql_lock->lock_count)
316- thr_multi_unlock(sql_lock->locks, sql_lock->lock_count);
317-
318- if (sql_lock->table_count)
319- unlock_external(session, sql_lock->table, sql_lock->table_count);
320-
321- /*
322- If thr_multi_lock fails it resets lock type for tables, which
323- were locked before (and including) one that caused error. Lock
324- type for other tables preserved.
325- */
326- reset_lock_data_and_free(&sql_lock);
327+ for (;;)
328+ {
329+ if (! initLockData(session, tables, count, true, &write_lock_used))
330+ {
331+ throw exception();
332+ }
333+
334+ if (global_read_lock && write_lock_used &&
335+ ! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
336+ {
337+ /*
338+ Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
339+ Wait until the lock is gone
340+ */
341+ if (wait_if_global_read_lock(session, 1, 1))
342+ {
343+ /* Clear the lock type of all lock data to avoid reusage. */
344+ throw exception();
345+ }
346+ if (session->version != refresh_version)
347+ {
348+ /* Clear the lock type of all lock data to avoid reusage. */
349+ resetLockData();
350+ goto retry;
351+ }
352+ }
353+
354+ session->set_proc_info("System lock");
355+ if (table_count && session->lockExternal(table, table_count))
356+ {
357+ /* Clear the lock type of all lock data to avoid reusage. */
358+ throw exception();
359+ }
360+ session->set_proc_info("Table lock");
361+ /* Copy the lock data array. thr_multi_lock() reorders its contens. */
362+ memcpy(locks + lock_count, locks,
363+ lock_count * sizeof(*locks));
364+ /* Lock on the copied half of the lock data array. */
365+ rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(locks +
366+ lock_count,
367+ lock_count,
368+ session->lock_id)];
369+ if (rc > 1) /* a timeout or a deadlock */
370+ {
371+ if (table_count)
372+ (void)session->unlockExternal(table, table_count); // return is advisory
373+ my_error(rc, MYF(0));
374+ throw exception();
375+ }
376+ else if (rc == 1) /* aborted */
377+ {
378+ session->some_tables_deleted=1; // Try again
379+ lock_count= 0; // Locks are already freed
380+ // Fall through: unlock, reset lock data, free and retry
381+ }
382+ else if (!session->some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
383+ {
384+ /*
385+ Thread was killed or lock aborted. Let upper level close all
386+ used tables and retry or give error.
387+ */
388+ break;
389+ }
390+ else if (!session->open_tables)
391+ {
392+ // Only using temporary tables, no need to unlock
393+ session->some_tables_deleted= 0;
394+ break;
395+ }
396+ session->set_proc_info(0);
397+
398+ /* going to retry, unlock all tables */
399+ if (lock_count)
400+ thr_multi_unlock(locks, lock_count);
401+
402+ if (table_count)
403+ (void)session->unlockExternal(table, table_count);
404+
405+ /*
406+ If thr_multi_lock fails it resets lock type for tables, which
407+ were locked before (and including) one that caused error. Lock
408+ type for other tables preserved.
409+ */
410+ resetLockData();
411 retry:
412- if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
413- {
414- *need_reopen= true;
415- break;
416+ if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
417+ {
418+ *need_reopen= true;
419+ break;
420+ }
421+ if (wait_for_tables(session))
422+ break; // Couldn't open tables
423 }
424- if (wait_for_tables(session))
425- break; // Couldn't open tables
426+ }
427+ catch (...)
428+ {
429+ failed_locks= true;
430 }
431+
432 session->set_proc_info(0);
433 if (session->killed)
434 {
435 session->send_kill_message();
436- if (sql_lock)
437+ if (! failed_locks)
438 {
439- mysql_unlock_tables(session,sql_lock);
440- sql_lock= NULL;
441+ unlockTables(session);
442 }
443+ return false;
444 }
445
446 session->set_time_after_lock();
447- return (sql_lock);
448+
449+ if (failed_locks)
450+ {
451+ return false;
452+ }
453+
454+ return true;
455 }
456
457
458-static int lock_external(Session *session, Table **tables, uint32_t count)
459+int Session::lockExternal(Table **tables, uint32_t count)
460 {
461- register uint32_t i;
462+ register uint32_t x;
463 int lock_type,error;
464- for (i=1 ; i <= count ; i++, tables++)
465+ for (x= 1; x <= count; x++, tables++)
466 {
467 assert((*tables)->reginfo.lock_type >= TL_READ);
468- lock_type=F_WRLCK; /* Lock exclusive */
469+ lock_type= F_WRLCK; /* Lock exclusive */
470 if ((*tables)->db_stat & HA_READ_ONLY ||
471- ((*tables)->reginfo.lock_type >= TL_READ &&
472- (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
473- lock_type=F_RDLCK;
474+ ((*tables)->reginfo.lock_type >= TL_READ &&
475+ (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT))
476+ lock_type= F_RDLCK;
477
478- if ((error=(*tables)->file->ha_external_lock(session,lock_type)))
479+ if ((error= (*tables)->file->ha_external_lock(this,lock_type)))
480 {
481 print_lock_error(error, (*tables)->file->engine->getName().c_str());
482- while (--i)
483+ while (--x)
484 {
485 tables--;
486- (*tables)->file->ha_external_lock(session, F_UNLCK);
487- (*tables)->current_lock=F_UNLCK;
488+ (*tables)->file->ha_external_lock(this, F_UNLCK);
489+ (*tables)->current_lock= F_UNLCK;
490 }
491 return error;
492 }
493@@ -312,168 +299,192 @@
494 (*tables)->current_lock= lock_type;
495 }
496 }
497+
498 return 0;
499 }
500
501-
502-void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock)
503-{
504- if (sql_lock->lock_count)
505- thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
506- if (sql_lock->table_count)
507- unlock_external(session,sql_lock->table,sql_lock->table_count);
508- free((unsigned char*) sql_lock);
509+void Session::unlockTables()
510+{
511+
512+ if (lock)
513+ {
514+ lock->unlockTables(this);
515+ delete lock;
516+ lock= 0;
517+ }
518+
519+}
520+
521+void drizzled::Lock::unlockTables(Session *session)
522+{
523+ if (lock_count)
524+ thr_multi_unlock(locks,lock_count);
525+ if (table_count)
526+ session->unlockExternal(table, table_count);
527+
528 return;
529 }
530
531-/**
532- Unlock some of the tables locked by mysql_lock_tables.
533-
534- This will work even if get_lock_data fails (next unlock will free all)
535-*/
536-
537-void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count)
538+void Session::unlockSomeTables(Table **table,uint32_t count)
539 {
540- DRIZZLE_LOCK *sql_lock;
541+ drizzled::Lock sql_lock;
542 Table *write_lock_used;
543- if ((sql_lock= get_lock_data(session, table, count, false,
544- &write_lock_used)))
545- mysql_unlock_tables(session, sql_lock);
546+
547+ if (sql_lock.initLockData(this, table, count, false, &write_lock_used))
548+ {
549+ sql_lock.unlockTables(this);
550+ }
551+
552 }
553
554
555-/**
556- unlock all tables locked for read.
557-*/
558-
559-void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock)
560+void drizzled::Lock::unlockReadTables(Session *session)
561 {
562- uint32_t i,found;
563+ uint32_t x,found;
564
565 /* Move all write locks first */
566- THR_LOCK_DATA **lock=sql_lock->locks;
567- for (i=found=0 ; i < sql_lock->lock_count ; i++)
568+ THR_LOCK_DATA **lock= locks;
569+ for (x= found= 0; x < lock_count; x++)
570 {
571- if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
572+ if (locks[x]->type >= TL_WRITE_ALLOW_READ)
573 {
574- std::swap(*lock, sql_lock->locks[i]);
575+ swap(*lock, locks[x]);
576 lock++;
577 found++;
578 }
579 }
580 /* unlock the read locked tables */
581- if (i != found)
582+ if (x != found)
583 {
584- thr_multi_unlock(lock,i-found);
585- sql_lock->lock_count= found;
586+ thr_multi_unlock(lock, x - found);
587+ lock_count= found;
588 }
589
590 /* Then do the same for the external locks */
591 /* Move all write locked tables first */
592- Table **table=sql_lock->table;
593- for (i=found=0 ; i < sql_lock->table_count ; i++)
594+ Table **tbl= table;
595+ for (x= found= 0; x < table_count; x++)
596 {
597- assert(sql_lock->table[i]->lock_position == i);
598- if ((uint32_t) sql_lock->table[i]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
599+ assert(table[x]->lock_position == x);
600+ if ((uint32_t) table[x]->reginfo.lock_type >= TL_WRITE_ALLOW_READ)
601 {
602- std::swap(*table, sql_lock->table[i]);
603- table++;
604+ swap(*tbl, table[x]);
605+ tbl++;
606 found++;
607 }
608 }
609 /* Unlock all read locked tables */
610- if (i != found)
611+ if (x != found)
612 {
613- unlock_external(session,table,i-found);
614- sql_lock->table_count=found;
615+ session->unlockExternal(tbl, x-found);
616+ table_count= found;
617 }
618 /* Fix the lock positions in Table */
619- table= sql_lock->table;
620+ tbl= table;
621 found= 0;
622- for (i= 0; i < sql_lock->table_count; i++)
623+ for (x= 0; x < table_count; x++)
624 {
625- Table *tbl= *table;
626- tbl->lock_position= table - sql_lock->table;
627- tbl->lock_data_start= found;
628- found+= tbl->lock_count;
629- table++;
630+ Table *tbl2= *tbl;
631+ tbl2->lock_position= tbl - table;
632+ tbl2->lock_data_start= found;
633+ found+= tbl2->lock_count;
634+ tbl++;
635 }
636 return;
637 }
638
639-
640-/**
641- Try to find the table in the list of locked tables.
642- In case of success, unlock the table and remove it from this list.
643-
644- @note This function has a legacy side effect: the table is
645- unlocked even if it is not found in the locked list.
646- It's not clear if this side effect is intentional or still
647- desirable. It might lead to unmatched calls to
648- unlock_external(). Moreover, a discrepancy can be left
649- unnoticed by the storage engine, because in
650- unlock_external() we call handler::external_lock(F_UNLCK) only
651- if table->current_lock is not F_UNLCK.
652-
653- @param session thread context
654- @param locked list of locked tables
655- @param table the table to unlock
656- @param always_unlock specify explicitly if the legacy side
657- effect is desired.
658-*/
659-
660-void mysql_lock_remove(Session *session, Table *table)
661-{
662- mysql_unlock_some_tables(session, &table, /* table count */ 1);
663-}
664-
665-
666-/** Abort all other threads waiting to get lock in table. */
667-
668-void mysql_lock_abort(Session *session, Table *table)
669-{
670- DRIZZLE_LOCK *locked;
671+void Session::removeTableLock(Table *table)
672+{
673+ unlockSomeTables(&table, /* table count */ 1);
674+}
675+
676+void drizzled::Lock::removeTable(Session *session, Table *tbl, bool always_unlock)
677+{
678+ register uint32_t x;
679+ for (x= 0; x < table_count; x++)
680+ {
681+ if (table[x] == tbl)
682+ {
683+ uint32_t j, removed_locks, old_tables;
684+ Table *tbl2;
685+ uint32_t lock_data_end;
686+
687+ assert(tbl->lock_position == x);
688+
689+ /* Unlock if not yet unlocked */
690+ if (always_unlock == false)
691+ session->unlockSomeTables(&tbl, /* table count */ 1);
692+
693+ /* Decrement table_count in advance, making below expressions easier */
694+ old_tables= --table_count;
695+
696+ /* The table has 'removed_locks' lock data elements in locks */
697+ removed_locks= tbl->lock_count;
698+
699+ /* Move down all table pointers above 'i'. */
700+ memmove((table+x), (table+x+1),
701+ (old_tables - x) * sizeof(Table*));
702+
703+ lock_data_end= tbl->lock_data_start + tbl->lock_count;
704+ /* Move down all lock data pointers above 'tbl->lock_data_end-1' */
705+ memmove((locks + tbl->lock_data_start),
706+ (locks + lock_data_end),
707+ (lock_count - lock_data_end) *
708+ sizeof(THR_LOCK_DATA*));
709+
710+ /*
711+ Fix moved table elements.
712+ lock_position is the index in the 'table' array,
713+ it must be fixed by one.
714+ table->lock_data_start is pointer to the lock data for this table
715+ in the 'locks' array, they must be fixed by 'removed_locks',
716+ the lock data count of the removed table.
717+ */
718+ for (j= x; j < old_tables; j++)
719+ {
720+ tbl2= table[j];
721+ tbl2->lock_position--;
722+ assert(tbl2->lock_position == j);
723+ tbl2->lock_data_start-= removed_locks;
724+ }
725+
726+ /* Finally adjust lock_count. */
727+ lock_count-= removed_locks;
728+ break;
729+ }
730+ }
731+}
732+
733+
734+void Session::abortLock(Table *table)
735+{
736+ drizzled::Lock locked;
737 Table *write_lock_used;
738
739- if ((locked= get_lock_data(session, &table, 1, false,
740- &write_lock_used)))
741+ if (locked.initLockData(this, &table, 1, false, &write_lock_used))
742 {
743- for (uint32_t x= 0; x < locked->lock_count; x++)
744- thr_abort_locks(locked->locks[x]->lock);
745- free((unsigned char*) locked);
746+ for (uint32_t x= 0; x < locked.getLockCount(); x++)
747+ thr_abort_locks(locked.getLock(x)->lock);
748 }
749 }
750
751
752-/**
753- Abort one thread / table combination.
754-
755- @param session Thread handler
756- @param table Table that should be removed from lock queue
757-
758- @retval
759- 0 Table was not locked by another thread
760- @retval
761- 1 Table was locked by at least one other thread
762-*/
763-
764-bool mysql_lock_abort_for_thread(Session *session, Table *table)
765+bool Session::abortLockForThread(Table *table)
766 {
767- DRIZZLE_LOCK *locked;
768+ drizzled::Lock locked;
769 Table *write_lock_used;
770 bool result= false;
771
772- if ((locked= get_lock_data(session, &table, 1, false,
773- &write_lock_used)))
774+ if (locked.initLockData(this, &table, 1, false, &write_lock_used))
775 {
776- for (uint32_t i=0; i < locked->lock_count; i++)
777+ for (uint32_t x= 0; x < locked.getLockCount(); x++)
778 {
779- if (thr_abort_locks_for_thread(locked->locks[i]->lock,
780+ if (thr_abort_locks_for_thread(locked.getLock(x)->lock,
781 table->in_use->thread_id))
782 result= true;
783 }
784- free((unsigned char*) locked);
785 }
786+
787 return result;
788 }
789
790@@ -504,7 +515,7 @@
791 TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
792 TableList *haystack)
793 {
794- DRIZZLE_LOCK *mylock;
795+ drizzled::Lock *mylock;
796 Table **lock_tables;
797 Table *table;
798 Table *table2;
799@@ -530,14 +541,14 @@
800 goto end;
801
802 /* If we have less than two tables, we cannot have duplicates. */
803- if (mylock->table_count < 2)
804+ if (mylock->getTableCount() < 2)
805 goto end;
806
807- lock_locks= mylock->locks;
808- lock_tables= mylock->table;
809+ lock_locks= mylock->getLocks();
810+ lock_tables= mylock->getTable();
811
812 /* Prepare table related variables that don't change in loop. */
813- assert((table->lock_position < mylock->table_count) &&
814+ assert((table->lock_position < mylock->getTableCount()) &&
815 (table == lock_tables[table->lock_position]));
816 table_lock_data= lock_locks + table->lock_data_start;
817 end_data= table_lock_data + table->lock_count;
818@@ -551,7 +562,7 @@
819 continue;
820
821 /* All tables in list must be in lock. */
822- assert((table2->lock_position < mylock->table_count) &&
823+ assert((table2->lock_position < mylock->getTableCount()) &&
824 (table2 == lock_tables[table2->lock_position]));
825
826 for (lock_data2= lock_locks + table2->lock_data_start,
827@@ -577,58 +588,45 @@
828 }
829
830
831-/** Unlock a set of external. */
832-
833-static int unlock_external(Session *session, Table **table,uint32_t count)
834+int Session::unlockExternal(Table **table,uint32_t count)
835 {
836 int error,error_code;
837
838- error_code=0;
839+ error_code= 0;
840 do
841 {
842 if ((*table)->current_lock != F_UNLCK)
843 {
844- (*table)->current_lock = F_UNLCK;
845- if ((error=(*table)->file->ha_external_lock(session, F_UNLCK)))
846+ (*table)->current_lock= F_UNLCK;
847+ if ((error= (*table)->file->ha_external_lock(this, F_UNLCK)))
848 {
849- error_code=error;
850- print_lock_error(error_code, (*table)->file->engine->getName().c_str());
851+ error_code= error;
852+ print_lock_error(error_code, (*table)->file->engine->getName().c_str());
853 }
854 }
855 table++;
856 } while (--count);
857+
858 return error_code;
859 }
860
861
862-/**
863- Get lock structures from table structs and initialize locks.
864-
865- @param session Thread handler
866- @param table_ptr Pointer to tables that should be locks
867- @param should_lock One of:
868- - false : If we should send TL_IGNORE to store lock
869- - true : Store lock info in Table
870- @param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
871-*/
872-
873-static DRIZZLE_LOCK *get_lock_data(Session *session, Table **table_ptr, uint32_t count,
874- bool should_lock, Table **write_lock_used)
875+bool drizzled::Lock::initLockData(Session *session, Table **table_ptr, uint32_t count,
876+ bool should_lock, Table **write_lock_used)
877 {
878- uint32_t i,tables,lock_count;
879- DRIZZLE_LOCK *sql_lock;
880- THR_LOCK_DATA **locks, **locks_buf, **locks_start;
881+ uint32_t x,tables,tbl_count;
882+ THR_LOCK_DATA **lcks, **locks_buf, **locks_start;
883 Table **to, **table_buf;
884
885- *write_lock_used=0;
886- for (i= tables= lock_count= 0 ; i < count ; i++)
887+ *write_lock_used= 0;
888+ for (x= tables= tbl_count= 0; x < count; x++)
889 {
890- Table *t= table_ptr[i];
891+ Table *t= table_ptr[x];
892
893 if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
894 {
895 tables++;
896- lock_count++;
897+ tbl_count++;
898 }
899 }
900
901@@ -638,47 +636,43 @@
902 update the table values. So the second part of the array is copied
903 from the first part immediately before calling thr_multi_lock().
904 */
905- if (!(sql_lock= (DRIZZLE_LOCK*)
906- malloc(sizeof(*sql_lock) +
907- sizeof(THR_LOCK_DATA*) * tables * 2 +
908- sizeof(table_ptr) * lock_count)))
909- return NULL;
910- locks= locks_buf= sql_lock->locks= (THR_LOCK_DATA**) (sql_lock + 1);
911- to= table_buf= sql_lock->table= (Table**) (locks + tables * 2);
912- sql_lock->table_count= lock_count;
913+ lcks= locks= locks_buf= (THR_LOCK_DATA**) malloc(sizeof(THR_LOCK_DATA*) * tables * 2 + sizeof(table_ptr) * tbl_count);
914+ to= table_buf= table= (Table**) (lcks + tables * 2);
915+ table_count= tbl_count;
916
917- for (i=0 ; i < count ; i++)
918+ for (x= 0; x < count; x++)
919 {
920- Table *table;
921+ Table *tbl;
922 enum thr_lock_type lock_type;
923
924- if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
925+ tbl= table_ptr[x];
926+ if (tbl->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
927 continue;
928- lock_type= table->reginfo.lock_type;
929+ lock_type= tbl->reginfo.lock_type;
930 assert (lock_type != TL_WRITE_DEFAULT);
931 if (lock_type >= TL_WRITE_ALLOW_WRITE)
932 {
933- *write_lock_used=table;
934- if (table->db_stat & HA_READ_ONLY)
935+ *write_lock_used= tbl;
936+ if (tbl->db_stat & HA_READ_ONLY)
937 {
938- my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
939+ my_error(ER_OPEN_AS_READONLY,MYF(0),tbl->alias);
940 /* Clear the lock type of the lock data that are stored already. */
941- sql_lock->lock_count= locks - sql_lock->locks;
942- reset_lock_data_and_free(&sql_lock);
943- return NULL;
944+ lock_count= lcks - locks;
945+ resetLockData();
946+ return false;
947 }
948 }
949- locks_start= locks;
950- locks= table->file->store_lock(session, locks,
951+ locks_start= lcks;
952+ lcks= tbl->file->store_lock(session, lcks,
953 should_lock == false ? TL_IGNORE : lock_type);
954 if (should_lock)
955 {
956- table->lock_position= (uint32_t) (to - table_buf);
957- table->lock_data_start= (uint32_t) (locks_start - locks_buf);
958- table->lock_count= (uint32_t) (locks - locks_start);
959- assert(table->lock_count == 1);
960+ tbl->lock_position= (uint32_t) (to - table_buf);
961+ tbl->lock_data_start= (uint32_t) (locks_start - locks_buf);
962+ tbl->lock_count= (uint32_t) (lcks - locks_start);
963+ assert(tbl->lock_count == 1);
964 }
965- *to++= table;
966+ *to++= tbl;
967 }
968 /*
969 We do not use 'tables', because there are cases where store_lock()
970@@ -694,9 +688,9 @@
971 we may allocate too much, but better safe than memory overrun.
972 And in the FLUSH case, the memory is released quickly anyway.
973 */
974- sql_lock->lock_count= locks - locks_buf;
975+ lock_count= lcks - locks_buf;
976
977- return sql_lock;
978+ return true;
979 }
980
981
982
983=== modified file 'drizzled/lock.h'
984--- drizzled/lock.h 2009-08-11 03:02:59 +0000
985+++ drizzled/lock.h 2009-10-21 06:30:26 +0000
986@@ -16,6 +16,11 @@
987 * along with this program; if not, write to the Free Software
988 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
989 */
990+/**
991+ * @file
992+ * drizzled::Lock class definition and related functions for drizzle
993+ *
994+ */
995
996 #ifndef DRIZZLED_LOCK_H
997 #define DRIZZLED_LOCK_H
998@@ -25,24 +30,188 @@
999 class Session;
1000 class Table;
1001 class TableList;
1002-typedef struct drizzled_lock_st DRIZZLE_LOCK;
1003-
1004-DRIZZLE_LOCK *mysql_lock_tables(Session *session, Table **table, uint32_t count,
1005- uint32_t flags, bool *need_reopen);
1006-/* mysql_lock_tables() and open_table() flags bits */
1007+
1008+namespace drizzled
1009+{
1010+ /**
1011+ @defgroup Locking Locking
1012+ @{
1013+ */
1014+ /**
1015+ * Encapsulates THR_LOCK_DATA structures and Table list
1016+ */
1017+ class Lock
1018+ {
1019+ public:
1020+ /**
1021+ * creates lock object and locks list of tables passed in
1022+ *
1023+ * @notes this used to be mysql_lock_tables
1024+ *
1025+ * @param[in] session thread handler
1026+ * @param[in] tables An array of pointers to the tables to lock.
1027+ * @param[in] count The number of tables to lock.
1028+ *
1029+ * @param[in] flag Options:
1030+ * DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
1031+ * DRIZZLE_LOCK_IGNORE_FLUSH Ignore a flush tables.
1032+ * DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
1033+ * or dropped tables by itself,
1034+ * Session::lock_tables() should
1035+ * notify upper level and rely
1036+ * on caller doing this.
1037+ * @param[out] need_reopen TRUE if some tables were altered
1038+ * or deleted and should be reopened by caller.
1039+ *
1040+ * @return true if locking was successful, false it if was not
1041+ *
1042+ * @notes the meat of this used to be mysql_lock_tables()
1043+ *
1044+ */
1045+ bool lockTables(Session *session,Table **table, uint32_t count,
1046+ uint32_t flags, bool *need_reopen);
1047+
1048+ /**
1049+ * Get lock structures from table structs and initialize locks.
1050+ *
1051+ * @notes used in place of no defunct get_lock_data()
1052+ * @param session Thread handler
1053+ * @param table_ptr Pointer to tables that should be locks
1054+ * @param should_lock One of:
1055+ * - false : If we should send TL_IGNORE to store lock
1056+ * - true : Store lock info in Table
1057+ * @param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
1058+ *
1059+ * @notes was get_lock_data()
1060+ */
1061+ bool initLockData(Session *session, Table **table_ptr, uint32_t count,
1062+ bool should_lock, Table **write_lock_used);
1063+
1064+ /**
1065+ * create a lock structure by merging two others
1066+ */
1067+ Lock(Lock *a, Lock *b);
1068+
1069+ Lock()
1070+ :
1071+ table(NULL),
1072+ table_count(0),
1073+ lock_count(0),
1074+ locks(NULL)
1075+ {}
1076+
1077+ ~Lock();
1078+
1079+ /**
1080+ * calls thr_unlock_multi() on locks, and Session::unlockExternal for table
1081+ *
1082+ * @param[in] session Session object for unlockExternal
1083+ */
1084+ void unlockTables(Session *session);
1085+
1086+ /**
1087+ * unlock all READ-locked tables associated with this Lock object
1088+ *
1089+ * @param[in] session Session object used for unlockExternal
1090+ *
1091+ */
1092+ void unlockReadTables(Session *session);
1093+
1094+ /**
1095+ * remove a single table from from list of tables in this lock
1096+ *
1097+ * @param[in] session thread handler associated
1098+ * @param[in] tbl Table object specifying which table to remove
1099+ * @param[in] always_unlock false to only try to unlock the table using Session::unlockSomeTables
1100+ */
1101+ void removeTable(Session *session, Table *tbl, bool always_unlock);
1102+
1103+ /**
1104+ * @return pointer to list of locks
1105+ * @retval NULL list is empty
1106+ */
1107+ inline THR_LOCK_DATA **getLocks() const
1108+ {
1109+ return locks;
1110+ }
1111+
1112+ /**
1113+ * @return pointer to list of tables
1114+ * @retval NULL list is empty
1115+ */
1116+ inline Table **getTable() const
1117+ {
1118+ return table;
1119+ }
1120+
1121+ /**
1122+ * @return the lock at offset in locks list
1123+ */
1124+ inline const THR_LOCK_DATA *getLock(uint32_t offset) const
1125+ {
1126+ return locks[offset];
1127+ }
1128+
1129+ /**
1130+ * @return the number of THR_LOCK_DATA structures in locks list
1131+ */
1132+ inline const uint32_t getLockCount() const
1133+ {
1134+ return lock_count;
1135+ }
1136+
1137+ /**
1138+ * @return table_count
1139+ */
1140+ inline const uint32_t getTableCount() const
1141+ {
1142+ return table_count;
1143+ }
1144+
1145+ private:
1146+ Table **table; ///< pointer to list of locked tables
1147+ uint32_t table_count; ///< the number of Table objects in table
1148+ uint32_t lock_count; ///< The number of THR_LOCK_DATA structures in locks
1149+ THR_LOCK_DATA **locks; ///< pointer to list of THR_LOCK_DATA structures
1150+
1151+ /**
1152+ * private copy constructor to prevent copying
1153+ */
1154+ Lock(Lock &other);
1155+
1156+ /**
1157+ * Reset lock type in lock data and free.
1158+ *
1159+ * @note After a locking error we want to quit the locking of the table(s).
1160+ * The test case in the bug report for MySQL Bug #18544 has the following
1161+ * cases:
1162+ * 1. Locking error in Session::lockExternal() due to InnoDB timeout.
1163+ * 2. Locking error in drizzled::Lock::initLockData() due to missing write permission.
1164+ * 3. Locking error in wait_if_global_read_lock() due to lock conflict.
1165+ *
1166+ * @note In all these cases we have already set the lock type into the lock
1167+ * data of the open table(s). If the table(s) are in the open table
1168+ * cache, they could be reused with the non-zero lock type set. This
1169+ * could lead to ignoring a different lock type with the next lock.
1170+ *
1171+ * @note Clear the lock type of all lock data. This ensures that the next
1172+ * lock request will set its lock type properly.
1173+ */
1174+ void resetLockData();
1175+ };
1176+}
1177+/**
1178+ @} end of group Locking
1179+ */
1180+
1181+/* Session::lockTables() and open_table() flags bits */
1182 #define DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
1183 #define DRIZZLE_LOCK_IGNORE_FLUSH 0x0002
1184 #define DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004
1185 #define DRIZZLE_OPEN_TEMPORARY_ONLY 0x0008
1186
1187-void mysql_unlock_tables(Session *session, DRIZZLE_LOCK *sql_lock);
1188-void mysql_unlock_read_tables(Session *session, DRIZZLE_LOCK *sql_lock);
1189-void mysql_unlock_some_tables(Session *session, Table **table, uint32_t count);
1190-void mysql_lock_remove(Session *session, Table *table);
1191-void mysql_lock_abort(Session *session, Table *table);
1192-bool mysql_lock_abort_for_thread(Session *session, Table *table);
1193 TableList *mysql_lock_have_duplicate(Session *session, TableList *needle,
1194- TableList *haystack);
1195+ TableList *haystack);
1196 bool lock_global_read_lock(Session *session);
1197 void unlock_global_read_lock(Session *session);
1198 bool wait_if_global_read_lock(Session *session, bool abort_on_refresh,
1199
1200=== modified file 'drizzled/open_tables_state.h'
1201--- drizzled/open_tables_state.h 2009-07-10 06:40:04 +0000
1202+++ drizzled/open_tables_state.h 2009-10-21 06:30:26 +0000
1203@@ -17,6 +17,7 @@
1204 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1205 */
1206
1207+#include <drizzled/lock.h>
1208
1209 #ifndef DRIZZLED_OPEN_TABLES_STATE_H
1210 #define DRIZZLED_OPEN_TABLES_STATE_H
1211@@ -59,14 +60,14 @@
1212 the 'LOCK_TABLES' chapter of the MySQL manual.
1213 See also lock_tables() for details.
1214 */
1215- DRIZZLE_LOCK *lock;
1216+ drizzled::Lock *lock;
1217
1218 /*
1219 CREATE-SELECT keeps an extra lock for the table being
1220 created. This field is used to keep the extra lock available for
1221 lower level routines, which would otherwise miss that lock.
1222 */
1223- DRIZZLE_LOCK *extra_lock;
1224+ drizzled::Lock *extra_lock;
1225
1226 ulong version;
1227 uint32_t current_tablenr;
1228
1229=== modified file 'drizzled/select_create.h'
1230--- drizzled/select_create.h 2009-09-15 21:01:42 +0000
1231+++ drizzled/select_create.h 2009-10-21 06:30:26 +0000
1232@@ -29,9 +29,9 @@
1233 AlterInfo *alter_info;
1234 Field **field;
1235 /* lock data for tmp table */
1236- DRIZZLE_LOCK *m_lock;
1237+ drizzled::Lock *m_lock;
1238 /* m_lock or session->extra_lock */
1239- DRIZZLE_LOCK **m_plock;
1240+ drizzled::Lock **m_plock;
1241 public:
1242 select_create (TableList *table_arg,
1243 HA_CREATE_INFO *create_info_par,
1244@@ -54,6 +54,7 @@
1245 bool send_eof();
1246 void abort();
1247 virtual bool can_rollback_data() { return 1; }
1248+ void unlock_tables();
1249
1250 // Needed for access from local class MY_HOOKS in prepare(), since session is proteted.
1251 const Session *get_session(void) { return session; }
1252
1253=== modified file 'drizzled/select_send.h'
1254--- drizzled/select_send.h 2009-10-01 17:56:07 +0000
1255+++ drizzled/select_send.h 2009-10-21 06:30:26 +0000
1256@@ -42,11 +42,7 @@
1257 drizzled::plugin::StorageEngine::releaseTemporaryLatches(session);
1258
1259 /* Unlock tables before sending packet to gain some speed */
1260- if (session->lock)
1261- {
1262- mysql_unlock_tables(session, session->lock);
1263- session->lock= 0;
1264- }
1265+ session->unlockTables();
1266 session->my_eof();
1267 is_result_set_started= 0;
1268 return false;
1269
1270=== modified file 'drizzled/session.cc'
1271--- drizzled/session.cc 2009-10-12 23:23:18 +0000
1272+++ drizzled/session.cc 2009-10-21 06:30:26 +0000
1273@@ -2075,20 +2075,8 @@
1274 transaction.stmt.reset();
1275 }
1276
1277- if (lock)
1278- {
1279- /*
1280- For RBR we flush the pending event just before we unlock all the
1281- tables. This means that we are at the end of a topmost
1282- statement, so we ensure that the STMT_END_F flag is set on the
1283- pending event. For statements that are *inside* stored
1284- functions, the pending event will not be flushed: that will be
1285- handled either before writing a query log event (inside
1286- binlog_query()) or when preparing a pending event.
1287- */
1288- mysql_unlock_tables(this, lock);
1289- lock= 0;
1290- }
1291+ unlockTables();
1292+
1293 /*
1294 Note that we need to hold LOCK_open while changing the
1295 open_tables list. Another thread may work on it.
1296
1297=== modified file 'drizzled/session.h'
1298--- drizzled/session.h 2009-10-16 00:38:56 +0000
1299+++ drizzled/session.h 2009-10-21 06:30:26 +0000
1300@@ -93,14 +93,6 @@
1301 /* for VIEW ... WITH CHECK OPTION */
1302 } COPY_INFO;
1303
1304-typedef struct drizzled_lock_st
1305-{
1306- Table **table;
1307- uint32_t table_count;
1308- uint32_t lock_count;
1309- THR_LOCK_DATA **locks;
1310-} DRIZZLE_LOCK;
1311-
1312 #include <drizzled/lex_column.h>
1313
1314 class select_result;
1315@@ -1230,6 +1222,70 @@
1316 return connect_microseconds;
1317 }
1318
1319+ /**
1320+ * If there are any locks associated with this session, unlock and destroy
1321+ * the lock object.
1322+ */
1323+ void unlockTables();
1324+ drizzled::Lock *lockTables(Table **tables, uint32_t count,
1325+ uint32_t flags, bool *need_reopen);
1326+
1327+ /**
1328+ * Lock tables in storage engine
1329+ *
1330+ * @param table list of tables to lock
1331+ * @param count number of tables in list
1332+ * @return return code from ha_external_lock if error ocurred
1333+ * @retval 0 No errors ocurred
1334+ */
1335+ int lockExternal(Table **table,uint32_t count);
1336+
1337+ /**
1338+ * Unlock tables in storage engine
1339+ *
1340+ * @param table list of tables to unlock
1341+ * @param count number of tables to unlock
1342+ * @return return code from ha_external_unlock if error ocurred
1343+ * @retval 0 No errors ocurred
1344+ */
1345+ int unlockExternal(Table **table, uint32_t count);
1346+
1347+ /**
1348+ * Unlock some of the tables locked by Session::lockTables.
1349+ *
1350+ * @note This will work even if drizzled::Lock::initLockData fails (next
1351+ * unlock will free all)
1352+ *
1353+ * @note this used to be mysql_unlock_some_tables
1354+ */
1355+ void unlockSomeTables(Table **table, uint32_t count);
1356+
1357+ /**
1358+ * Calls Session::unlockSomeTables with a single table
1359+ *
1360+ * @param table the table to unlock
1361+ */
1362+ void removeTableLock(Table *table);
1363+
1364+ /**
1365+ * Abort all threads waiting on lock
1366+ *
1367+ * @param table[in] table to abort locks for
1368+ */
1369+ void abortLock(Table *table);
1370+
1371+ /**
1372+ * Abort one thread / table combination.
1373+ *
1374+ * @param table Table that should be removed from lock queue
1375+ *
1376+ * @retval
1377+ * false Table was not locked by another thread
1378+ * @retval
1379+ * true Table was locked by at least one other thread
1380+ */
1381+ bool abortLockForThread(Table *table);
1382+
1383 private:
1384 /** Microsecond timestamp of when Session connected */
1385 uint64_t connect_microseconds;
1386
1387=== modified file 'drizzled/sql_base.cc'
1388--- drizzled/sql_base.cc 2009-10-16 10:27:33 +0000
1389+++ drizzled/sql_base.cc 2009-10-21 06:30:26 +0000
1390@@ -1496,7 +1496,6 @@
1391 return(error);
1392 }
1393
1394-
1395 /**
1396 Close all instances of a table open by this thread and replace
1397 them with exclusive name-locks.
1398@@ -1520,15 +1519,11 @@
1399
1400 safe_mutex_assert_owner(&LOCK_open); /* Adjust locks at the end of ALTER TABLEL */
1401
1402- if (lock)
1403- {
1404- /*
1405- If we are not under LOCK TABLES we should have only one table
1406- open and locked so it makes sense to remove the lock at once.
1407- */
1408- mysql_unlock_tables(this, lock);
1409- lock= 0;
1410- }
1411+ /*
1412+ If we are not under LOCK TABLES we should have only one table
1413+ open and locked so it makes sense to remove the lock at once.
1414+ */
1415+ unlockTables();
1416
1417 /*
1418 Note that open table list may contain a name-lock placeholder
1419@@ -1624,7 +1619,7 @@
1420 *prev=0;
1421 if (tables != tables_ptr) // Should we get back old locks
1422 {
1423- DRIZZLE_LOCK *local_lock;
1424+ drizzled::Lock *local_lock= new (nothrow) drizzled::Lock;
1425 /*
1426 We should always get these locks. Anyway, we must not go into
1427 wait_for_tables() as it tries to acquire LOCK_open, which is
1428@@ -1632,12 +1627,8 @@
1429 */
1430 some_tables_deleted= false;
1431
1432- if ((local_lock= mysql_lock_tables(this, tables, (uint32_t) (tables_ptr - tables),
1433- flags, &not_used)))
1434- {
1435- /* unused */
1436- }
1437- else
1438+ if (local_lock && !local_lock->lockTables(this, tables, (uint32_t) (tables_ptr - tables),
1439+ flags, &not_used))
1440 {
1441 /*
1442 This case should only happen if there is a bug in the reopen logic.
1443@@ -1699,8 +1690,8 @@
1444 lock on it. This will also give them a chance to close their
1445 instances of this table.
1446 */
1447- mysql_lock_abort(this, ulcktbl);
1448- mysql_lock_remove(this, ulcktbl);
1449+ abortLock(ulcktbl);
1450+ removeTableLock(ulcktbl);
1451 ulcktbl->lock_count= 0;
1452 }
1453 if ((ulcktbl != table) && ulcktbl->db_stat)
1454@@ -1856,7 +1847,7 @@
1455 if (!strcmp(table->s->table_name.str, table_name) &&
1456 !strcmp(table->s->db.str, db))
1457 {
1458- mysql_lock_remove(session, table);
1459+ session->removeTableLock(table);
1460
1461 if (!found)
1462 {
1463@@ -1903,7 +1894,7 @@
1464 !strcmp(table->s->db.str, db))
1465 {
1466 /* If MERGE child, forward lock handling to parent. */
1467- mysql_lock_abort(session, table);
1468+ session->abortLock(table);
1469 break;
1470 }
1471 }
1472@@ -2254,7 +2245,7 @@
1473
1474 assert(lock == 0); // You must lock everything at once
1475 if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
1476- if (! (lock= mysql_lock_tables(this, &table_list->table, 1, 0, &refresh)))
1477+ if (! (lock= lockTables(&table_list->table, 1, 0, &refresh)))
1478 table= 0;
1479 }
1480
1481@@ -2317,8 +2308,8 @@
1482 *(ptr++)= table->table;
1483 }
1484
1485- if (!(session->lock= mysql_lock_tables(session, start, (uint32_t) (ptr - start),
1486- lock_flag, need_reopen)))
1487+ if (! (session->lock= session->lockTables(start, static_cast<uint32_t>(ptr - start),
1488+ lock_flag, need_reopen)))
1489 {
1490 return -1;
1491 }
1492@@ -4686,7 +4677,7 @@
1493 {
1494 /*
1495 Mark that table is going to be deleted from cache. This will
1496- force threads that are in mysql_lock_tables() (but not yet
1497+ force threads that are in Session::lockTables() (but not yet
1498 in thr_multi_lock()) to abort it's locks, close all tables and retry
1499 */
1500 in_use->some_tables_deleted= true;
1501@@ -4709,7 +4700,7 @@
1502 {
1503 /* Do not handle locks of MERGE children. */
1504 if (session_table->db_stat) // If table is open
1505- signalled|= mysql_lock_abort_for_thread(session, session_table);
1506+ signalled|= session->abortLockForThread(session_table);
1507 }
1508 }
1509 else
1510
1511=== modified file 'drizzled/sql_insert.cc'
1512--- drizzled/sql_insert.cc 2009-10-01 17:56:07 +0000
1513+++ drizzled/sql_insert.cc 2009-10-21 06:30:26 +0000
1514@@ -1458,7 +1458,7 @@
1515 message::Table *table_proto,
1516 AlterInfo *alter_info,
1517 List<Item> *items,
1518- DRIZZLE_LOCK **lock)
1519+ drizzled::Lock **lock)
1520 {
1521 Table tmp_table; // Used during 'CreateField()'
1522 TableShare share;
1523@@ -1581,12 +1581,13 @@
1524 }
1525
1526 table->reginfo.lock_type=TL_WRITE;
1527- if (! ((*lock)= mysql_lock_tables(session, &table, 1,
1528- DRIZZLE_LOCK_IGNORE_FLUSH, &not_used)))
1529+ if (! ((*lock)= session->lockTables(&table, 1,
1530+ DRIZZLE_LOCK_IGNORE_FLUSH, &not_used)))
1531 {
1532 if (*lock)
1533 {
1534- mysql_unlock_tables(session, *lock);
1535+ (*lock)->unlockTables(session);
1536+ delete *lock;
1537 *lock= 0;
1538 }
1539
1540@@ -1602,7 +1603,7 @@
1541 int
1542 select_create::prepare(List<Item> &values, Select_Lex_Unit *u)
1543 {
1544- DRIZZLE_LOCK *extra_lock= NULL;
1545+ drizzled::Lock *extra_lock= NULL;
1546 /*
1547 For row-based replication, the CREATE-SELECT statement is written
1548 in two pieces: the first one contain the CREATE TABLE statement
1549@@ -1729,17 +1730,21 @@
1550
1551 table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1552 table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
1553+ unlock_tables();
1554+ }
1555+ return tmp;
1556+}
1557+
1558+void select_create::unlock_tables()
1559+{
1560 if (m_plock)
1561 {
1562- mysql_unlock_tables(session, *m_plock);
1563- *m_plock= NULL;
1564+ (*m_plock)->unlockTables(session);
1565+ delete *m_plock;
1566 m_plock= NULL;
1567 }
1568- }
1569- return tmp;
1570 }
1571
1572-
1573 void select_create::abort()
1574 {
1575
1576@@ -1762,13 +1767,7 @@
1577 select_insert::abort();
1578 session->transaction.stmt.modified_non_trans_table= false;
1579
1580-
1581- if (m_plock)
1582- {
1583- mysql_unlock_tables(session, *m_plock);
1584- *m_plock= NULL;
1585- m_plock= NULL;
1586- }
1587+ unlock_tables();
1588
1589 if (table)
1590 {
1591
1592=== modified file 'drizzled/sql_table.cc'
1593--- drizzled/sql_table.cc 2009-10-16 10:27:33 +0000
1594+++ drizzled/sql_table.cc 2009-10-21 06:30:26 +0000
1595@@ -1968,7 +1968,7 @@
1596
1597 table->file->extra(function);
1598 /* Mark all tables that are in use as 'old' */
1599- mysql_lock_abort(session, table); /* end threads waiting on lock */
1600+ session->abortLock(table); /* end threads waiting on lock */
1601
1602 /* Wait until all there are no other threads that has this table open */
1603 remove_table_from_cache(session, table->s->db.str,
1604@@ -1998,11 +1998,7 @@
1605
1606 wait_while_table_is_used(this, table, HA_EXTRA_FORCE_REOPEN);
1607 /* Close lock if this is not got with LOCK TABLES */
1608- if (lock)
1609- {
1610- mysql_unlock_tables(this, lock);
1611- lock= NULL; // Start locked threads
1612- }
1613+ unlockTables();
1614 /* Close all copies of 'table'. This also frees all LOCK TABLES lock */
1615 unlink_open_table(table);
1616
1617@@ -2144,7 +2140,7 @@
1618 pthread_mutex_lock(&LOCK_open); /* Lock type is TL_WRITE and we lock to repair the table */
1619 const char *old_message=session->enter_cond(&COND_refresh, &LOCK_open,
1620 "Waiting to get writelock");
1621- mysql_lock_abort(session,table->table);
1622+ session->abortLock(table->table);
1623 remove_table_from_cache(session, table->table->s->db.str,
1624 table->table->s->table_name.str,
1625 RTFC_WAIT_OTHER_THREAD_FLAG |
1626
1627=== modified file 'drizzled/statement/alter_table.cc'
1628--- drizzled/statement/alter_table.cc 2009-10-12 23:23:18 +0000
1629+++ drizzled/statement/alter_table.cc 2009-10-21 06:30:26 +0000
1630@@ -1028,11 +1028,7 @@
1631 goto err1;
1632
1633 /* Close lock if this is a transactional table */
1634- if (session->lock)
1635- {
1636- mysql_unlock_tables(session, session->lock);
1637- session->lock= 0;
1638- }
1639+ session->unlockTables();
1640
1641 /* Remove link to old table and rename the new one */
1642 session->close_temporary_table(table, true, true);
1643
1644=== modified file 'drizzled/table.h'
1645--- drizzled/table.h 2009-10-16 10:27:33 +0000
1646+++ drizzled/table.h 2009-10-21 06:30:26 +0000
1647@@ -95,8 +95,8 @@
1648 const char *alias; /**< alias or table name if no alias */
1649 unsigned char *null_flags;
1650
1651- uint32_t lock_position; /**< Position in DRIZZLE_LOCK.table */
1652- uint32_t lock_data_start; /**< Start pos. in DRIZZLE_LOCK.locks */
1653+ uint32_t lock_position; /**< Position in drizzled::Lock.table */
1654+ uint32_t lock_data_start; /**< Start pos. in drizzled::Lock.locks */
1655 uint32_t lock_count; /**< Number of locks */
1656 uint32_t used_fields;
1657 uint32_t status; /* What's in record[0] */