21
21
the most natural (easiest, fastest) way to do it is to
22
22
compute List<Item> field_list not in mysql_ha_read
23
but in mysql_ha_open, and then store it in Table structure.
23
but in mysql_ha_open, and then store it in TABLE structure.
25
25
The problem here is that mysql_parse calls free_item to free all the
26
26
items allocated at the end of every query. The workaround would to
27
keep two item lists per Session - normal free_list and handler_items.
27
keep two item lists per THD - normal free_list and handler_items.
28
28
The second is to be freeed only on thread end. mysql_ha_open should
29
29
then do { handler_items=concat(handler_items, free_list); free_list=0; }
36
36
There are two containers holding information about open handler tables.
37
The first is 'session->handler_tables'. It is a linked list of Table objects.
38
It is used like 'session->open_tables' in the table cache. The trick is to
37
The first is 'thd->handler_tables'. It is a linked list of TABLE objects.
38
It is used like 'thd->open_tables' in the table cache. The trick is to
39
39
exchange these two lists during open and lock of tables. Thus the normal
40
40
table cache code can be used.
41
The second container is a HASH. It holds objects of the type TableList.
41
The second container is a HASH. It holds objects of the type TABLE_LIST.
42
42
Despite its name, no lists of tables but only single structs are hashed
43
43
(the 'next' pointer is always NULL). The reason for theis second container
44
is, that we want handler tables to survive FLUSH Table commands. A table
45
affected by FLUSH Table must be closed so that other threads are not
44
is, that we want handler tables to survive FLUSH TABLE commands. A table
45
affected by FLUSH TABLE must be closed so that other threads are not
46
46
blocked by handler tables still in use. Since we use the normal table cache
47
functions with 'session->handler_tables', the closed tables are removed from
47
functions with 'thd->handler_tables', the closed tables are removed from
48
48
this list. Hence we need the original open information for the handler
49
49
table in the case that it is used again. This information is handed over
50
to mysql_ha_open() as a TableList. So we store this information in the
51
second container, where it is not affected by FLUSH Table. The second
50
to mysql_ha_open() as a TABLE_LIST. So we store this information in the
51
second container, where it is not affected by FLUSH TABLE. The second
52
52
container is implemented as a hash for performance reasons. Consequently,
53
53
we use it not only for re-opening a handler table, but also for the
54
54
HANDLER ... READ commands. For this purpose, we store a pointer to the
55
Table structure (in the first container) in the TBALE_LIST object in the
55
TABLE structure (in the first container) in the TBALE_LIST object in the
56
56
second container. When the table is flushed, the pointer is cleared.
59
#include <drizzled/server_includes.h>
60
#include <drizzled/sql_select.h>
59
#include "mysql_priv.h"
60
#include "sql_select.h"
63
#define HANDLER_TABLES_HASH_SIZE 120
64
66
Close a HANDLER table.
66
@param session Thread identifier.
68
@param thd Thread identifier.
67
69
@param tables A list of tables with the first entry to close.
68
70
@param is_locked If LOCK_open is locked.
72
74
@note Broadcasts refresh if it closed a table with old version.
75
static void mysql_ha_close_table(Session *session, TableList *tables,
77
static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
81
83
Though we could take the table pointer from hash_tables->table,
82
we must follow the session->handler_tables chain anyway, as we need the
84
we must follow the thd->handler_tables chain anyway, as we need the
83
85
address of the 'next' pointer referencing this table
84
86
for close_thread_table().
86
for (table_ptr= &(session->handler_tables);
88
for (table_ptr= &(thd->handler_tables);
87
89
*table_ptr && (*table_ptr != tables->table);
88
90
table_ptr= &(*table_ptr)->next)
93
95
(*table_ptr)->file->ha_index_or_rnd_end();
95
pthread_mutex_lock(&LOCK_open);
96
if (close_thread_table(session, table_ptr))
97
VOID(pthread_mutex_lock(&LOCK_open));
98
if (close_thread_table(thd, table_ptr))
98
100
/* Tell threads waiting for refresh that something has happened */
99
101
broadcast_refresh();
102
pthread_mutex_unlock(&LOCK_open);
104
VOID(pthread_mutex_unlock(&LOCK_open));
104
106
else if (tables->table)
106
108
/* Must be a temporary table */
107
Table *table= tables->table;
109
TABLE *table= tables->table;
108
110
table->file->ha_index_or_rnd_end();
109
table->query_id= session->query_id;
111
table->query_id= thd->query_id;
110
112
table->open_by_handler= 0;
125
127
name (table->alias) of the specified table.
132
bool mysql_ha_close(Session *session, TableList *tables)
134
bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
134
TableList *hash_tables;
136
TABLE_LIST *hash_tables;
137
DBUG_ENTER("mysql_ha_close");
138
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
139
tables->db, tables->table_name, tables->alias));
136
if ((hash_tables= (TableList*) hash_search(&session->handler_tables_hash,
137
(unsigned char*) tables->alias,
141
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
142
(uchar*) tables->alias,
138
143
strlen(tables->alias) + 1)))
140
mysql_ha_close_table(session, hash_tables, false);
141
hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
145
mysql_ha_close_table(thd, hash_tables, FALSE);
146
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
145
150
my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
151
DBUG_PRINT("exit",("ERROR"));
156
DBUG_PRINT("exit", ("OK"));
155
162
Scan the handler tables hash for matching tables.
157
@param session Thread identifier.
164
@param thd Thread identifier.
158
165
@param tables The list of tables to remove.
160
@return Pointer to head of linked list (TableList::next_local) of matching
161
TableList elements from handler_tables_hash. Otherwise, NULL if no
167
@return Pointer to head of linked list (TABLE_LIST::next_local) of matching
168
TABLE_LIST elements from handler_tables_hash. Otherwise, NULL if no
162
169
table was matched.
165
static TableList *mysql_ha_find(Session *session, TableList *tables)
172
static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
167
TableList *hash_tables, *head= NULL, *first= tables;
174
TABLE_LIST *hash_tables, *head= NULL, *first= tables;
175
DBUG_ENTER("mysql_ha_find");
169
177
/* search for all handlers with matching table names */
170
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
178
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
172
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
180
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
173
181
for (tables= first; tables; tables= tables->next_local)
175
183
if ((! *tables->db ||
176
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->db, tables->db)) &&
177
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->table_name,
184
! my_strcasecmp(&my_charset_latin1, hash_tables->db, tables->db)) &&
185
! my_strcasecmp(&my_charset_latin1, hash_tables->table_name,
178
186
tables->table_name))
193
201
Remove matching tables from the HANDLER's hash table.
195
@param session Thread identifier.
203
@param thd Thread identifier.
196
204
@param tables The list of tables to remove.
197
205
@param is_locked If LOCK_open is locked.
199
207
@note Broadcasts refresh if it closed a table with old version.
202
void mysql_ha_rm_tables(Session *session, TableList *tables, bool is_locked)
210
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked)
204
TableList *hash_tables, *next;
208
hash_tables= mysql_ha_find(session, tables);
212
TABLE_LIST *hash_tables, *next;
213
DBUG_ENTER("mysql_ha_rm_tables");
217
hash_tables= mysql_ha_find(thd, tables);
210
219
while (hash_tables)
212
221
next= hash_tables->next_local;
213
222
if (hash_tables->table)
214
mysql_ha_close_table(session, hash_tables, is_locked);
215
hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
223
mysql_ha_close_table(thd, hash_tables, is_locked);
224
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
216
225
hash_tables= next;
224
233
Flush (close and mark for re-open) all tables that should be should
227
@param session Thread identifier.
236
@param thd Thread identifier.
229
238
@note Broadcasts refresh if it closed a table with old version.
232
void mysql_ha_flush(Session *session)
241
void mysql_ha_flush(THD *thd)
234
TableList *hash_tables;
243
TABLE_LIST *hash_tables;
244
DBUG_ENTER("mysql_ha_flush");
236
246
safe_mutex_assert_owner(&LOCK_open);
238
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
248
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
240
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
250
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
241
251
if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock())
243
mysql_ha_close_table(session, hash_tables, true);
253
mysql_ha_close_table(thd, hash_tables, TRUE);
244
254
/* Mark table as closed, ready for re-open. */
245
255
hash_tables->table= NULL;
254
264
Close all HANDLER's tables.
256
@param session Thread identifier.
266
@param thd Thread identifier.
258
268
@note Broadcasts refresh if it closed a table with old version.
261
void mysql_ha_cleanup(Session *session)
271
void mysql_ha_cleanup(THD *thd)
263
TableList *hash_tables;
273
TABLE_LIST *hash_tables;
274
DBUG_ENTER("mysql_ha_cleanup");
265
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
276
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
267
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
278
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
268
279
if (hash_tables->table)
269
mysql_ha_close_table(session, hash_tables, false);
280
mysql_ha_close_table(thd, hash_tables, FALSE);
272
hash_free(&session->handler_tables_hash);
283
hash_free(&thd->handler_tables_hash);