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 THD - normal free_list and handler_items.
27
keep two item lists per Session - 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 '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
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
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 TABLE_LIST.
41
The second container is a HASH. It holds objects of the type TableList.
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 'thd->handler_tables', the closed tables are removed from
47
functions with 'session->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 TABLE_LIST. 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 TableList. 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
59
#include <drizzled/server_includes.h>
60
60
#include <drizzled/sql_select.h>
61
#include <drizzled/error.h>
62
#include <drizzled/sql_base.h>
63
#include <drizzled/lock.h>
62
#define HANDLER_TABLES_HASH_SIZE 120
65
67
Close a HANDLER table.
67
@param thd Thread identifier.
69
@param session Thread identifier.
68
70
@param tables A list of tables with the first entry to close.
69
71
@param is_locked If LOCK_open is locked.
73
75
@note Broadcasts refresh if it closed a table with old version.
76
static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
78
static void mysql_ha_close_table(Session *session, TableList *tables,
82
84
Though we could take the table pointer from hash_tables->table,
83
we must follow the thd->handler_tables chain anyway, as we need the
85
we must follow the session->handler_tables chain anyway, as we need the
84
86
address of the 'next' pointer referencing this table
85
87
for close_thread_table().
87
for (table_ptr= &(thd->handler_tables);
89
for (table_ptr= &(session->handler_tables);
88
90
*table_ptr && (*table_ptr != tables->table);
89
91
table_ptr= &(*table_ptr)->next)
94
96
(*table_ptr)->file->ha_index_or_rnd_end();
96
VOID(pthread_mutex_lock(&LOCK_open));
97
if (close_thread_table(thd, table_ptr))
98
pthread_mutex_lock(&LOCK_open);
99
if (close_thread_table(session, table_ptr))
99
101
/* Tell threads waiting for refresh that something has happened */
100
102
broadcast_refresh();
103
VOID(pthread_mutex_unlock(&LOCK_open));
105
pthread_mutex_unlock(&LOCK_open);
105
107
else if (tables->table)
107
109
/* Must be a temporary table */
108
TABLE *table= tables->table;
110
Table *table= tables->table;
109
111
table->file->ha_index_or_rnd_end();
110
table->query_id= thd->query_id;
112
table->query_id= session->query_id;
111
113
table->open_by_handler= 0;
133
bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
135
bool mysql_ha_close(Session *session, TableList *tables)
135
TABLE_LIST *hash_tables;
137
TableList *hash_tables;
137
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
138
(uchar*) tables->alias,
139
if ((hash_tables= (TableList*) hash_search(&session->handler_tables_hash,
140
(unsigned char*) tables->alias,
139
141
strlen(tables->alias) + 1)))
141
mysql_ha_close_table(thd, hash_tables, false);
142
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
143
mysql_ha_close_table(session, hash_tables, false);
144
hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
156
158
Scan the handler tables hash for matching tables.
158
@param thd Thread identifier.
160
@param session Thread identifier.
159
161
@param tables The list of tables to remove.
161
@return Pointer to head of linked list (TABLE_LIST::next_local) of matching
162
TABLE_LIST elements from handler_tables_hash. Otherwise, NULL if no
163
@return Pointer to head of linked list (TableList::next_local) of matching
164
TableList elements from handler_tables_hash. Otherwise, NULL if no
163
165
table was matched.
166
static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
168
static TableList *mysql_ha_find(Session *session, TableList *tables)
168
TABLE_LIST *hash_tables, *head= NULL, *first= tables;
170
TableList *hash_tables, *head= NULL, *first= tables;
170
172
/* search for all handlers with matching table names */
171
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
173
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
173
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
175
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
174
176
for (tables= first; tables; tables= tables->next_local)
176
178
if ((! *tables->db ||
177
! my_strcasecmp(&my_charset_latin1, hash_tables->db, tables->db)) &&
178
! my_strcasecmp(&my_charset_latin1, hash_tables->table_name,
179
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->db, tables->db)) &&
180
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->table_name,
179
181
tables->table_name))
194
196
Remove matching tables from the HANDLER's hash table.
196
@param thd Thread identifier.
198
@param session Thread identifier.
197
199
@param tables The list of tables to remove.
198
200
@param is_locked If LOCK_open is locked.
200
202
@note Broadcasts refresh if it closed a table with old version.
203
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked)
205
void mysql_ha_rm_tables(Session *session, TableList *tables, bool is_locked)
205
TABLE_LIST *hash_tables, *next;
207
TableList *hash_tables, *next;
209
hash_tables= mysql_ha_find(thd, tables);
211
hash_tables= mysql_ha_find(session, tables);
211
213
while (hash_tables)
213
215
next= hash_tables->next_local;
214
216
if (hash_tables->table)
215
mysql_ha_close_table(thd, hash_tables, is_locked);
216
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
217
mysql_ha_close_table(session, hash_tables, is_locked);
218
hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
217
219
hash_tables= next;
225
227
Flush (close and mark for re-open) all tables that should be should
228
@param thd Thread identifier.
230
@param session Thread identifier.
230
232
@note Broadcasts refresh if it closed a table with old version.
233
void mysql_ha_flush(THD *thd)
235
void mysql_ha_flush(Session *session)
235
TABLE_LIST *hash_tables;
237
TableList *hash_tables;
237
239
safe_mutex_assert_owner(&LOCK_open);
239
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
241
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
241
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
243
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
242
244
if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock())
244
mysql_ha_close_table(thd, hash_tables, true);
246
mysql_ha_close_table(session, hash_tables, true);
245
247
/* Mark table as closed, ready for re-open. */
246
248
hash_tables->table= NULL;
255
257
Close all HANDLER's tables.
257
@param thd Thread identifier.
259
@param session Thread identifier.
259
261
@note Broadcasts refresh if it closed a table with old version.
262
void mysql_ha_cleanup(THD *thd)
264
void mysql_ha_cleanup(Session *session)
264
TABLE_LIST *hash_tables;
266
TableList *hash_tables;
266
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
268
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
268
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
270
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
269
271
if (hash_tables->table)
270
mysql_ha_close_table(thd, hash_tables, false);
272
mysql_ha_close_table(session, hash_tables, false);
273
hash_free(&thd->handler_tables_hash);
275
hash_free(&session->handler_tables_hash);