~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_handler.cc

  • Committer: Brian Aker
  • Date: 2008-12-16 07:07:50 UTC
  • Revision ID: brian@tangent.org-20081216070750-o5ykltxxqvn2awrx
Fixed errors test.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
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.
24
24
 
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; }
30
30
 
34
34
 
35
35
/*
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.
57
57
*/
58
58
 
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>
61
64
 
62
 
#define HANDLER_TABLES_HASH_SIZE 120
63
65
 
64
66
/**
65
67
  Close a HANDLER table.
66
68
 
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.
70
72
 
73
75
  @note Broadcasts refresh if it closed a table with old version.
74
76
*/
75
77
 
76
 
static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
 
78
static void mysql_ha_close_table(Session *session, TableList *tables,
77
79
                                 bool is_locked)
78
80
{
79
 
  TABLE **table_ptr;
 
81
  Table **table_ptr;
80
82
 
81
83
  /*
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().
86
88
  */
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)
90
92
    ;
93
95
  {
94
96
    (*table_ptr)->file->ha_index_or_rnd_end();
95
97
    if (! is_locked)
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))
98
100
    {
99
101
      /* Tell threads waiting for refresh that something has happened */
100
102
      broadcast_refresh();
101
103
    }
102
104
    if (! is_locked)
103
 
      VOID(pthread_mutex_unlock(&LOCK_open));
 
105
      pthread_mutex_unlock(&LOCK_open);
104
106
  }
105
107
  else if (tables->table)
106
108
  {
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;
112
114
  }
113
115
}
118
120
 
119
121
  SYNOPSIS
120
122
    mysql_ha_close()
121
 
    thd                         Thread identifier.
 
123
    session                         Thread identifier.
122
124
    tables                      A list of tables with the first entry to close.
123
125
 
124
126
  DESCRIPTION
130
132
    true  error
131
133
*/
132
134
 
133
 
bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
 
135
bool mysql_ha_close(Session *session, TableList *tables)
134
136
{
135
 
  TABLE_LIST    *hash_tables;
 
137
  TableList    *hash_tables;
136
138
 
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)))
140
142
  {
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);
143
145
  }
144
146
  else
145
147
  {
147
149
    return(true);
148
150
  }
149
151
 
150
 
  my_ok(thd);
 
152
  my_ok(session);
151
153
  return(false);
152
154
}
153
155
 
155
157
/**
156
158
  Scan the handler tables hash for matching tables.
157
159
 
158
 
  @param thd Thread identifier.
 
160
  @param session Thread identifier.
159
161
  @param tables The list of tables to remove.
160
162
 
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.
164
166
*/
165
167
 
166
 
static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
 
168
static TableList *mysql_ha_find(Session *session, TableList *tables)
167
169
{
168
 
  TABLE_LIST *hash_tables, *head= NULL, *first= tables;
 
170
  TableList *hash_tables, *head= NULL, *first= tables;
169
171
 
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++)
172
174
  {
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)
175
177
    {
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))
180
182
        break;
181
183
    }
193
195
/**
194
196
  Remove matching tables from the HANDLER's hash table.
195
197
 
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.
199
201
 
200
202
  @note Broadcasts refresh if it closed a table with old version.
201
203
*/
202
204
 
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)
204
206
{
205
 
  TABLE_LIST *hash_tables, *next;
 
207
  TableList *hash_tables, *next;
206
208
 
207
209
  assert(tables);
208
210
 
209
 
  hash_tables= mysql_ha_find(thd, tables);
 
211
  hash_tables= mysql_ha_find(session, tables);
210
212
 
211
213
  while (hash_tables)
212
214
  {
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;
218
220
  }
219
221
 
225
227
  Flush (close and mark for re-open) all tables that should be should
226
228
  be reopen.
227
229
 
228
 
  @param thd Thread identifier.
 
230
  @param session Thread identifier.
229
231
 
230
232
  @note Broadcasts refresh if it closed a table with old version.
231
233
*/
232
234
 
233
 
void mysql_ha_flush(THD *thd)
 
235
void mysql_ha_flush(Session *session)
234
236
{
235
 
  TABLE_LIST *hash_tables;
 
237
  TableList *hash_tables;
236
238
 
237
239
  safe_mutex_assert_owner(&LOCK_open);
238
240
 
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++)
240
242
  {
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())
243
245
    {
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;
247
249
    }
254
256
/**
255
257
  Close all HANDLER's tables.
256
258
 
257
 
  @param thd Thread identifier.
 
259
  @param session Thread identifier.
258
260
 
259
261
  @note Broadcasts refresh if it closed a table with old version.
260
262
*/
261
263
 
262
 
void mysql_ha_cleanup(THD *thd)
 
264
void mysql_ha_cleanup(Session *session)
263
265
{
264
 
  TABLE_LIST *hash_tables;
 
266
  TableList *hash_tables;
265
267
 
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++)
267
269
  {
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);
271
273
   }
272
274
 
273
 
  hash_free(&thd->handler_tables_hash);
 
275
  hash_free(&session->handler_tables_hash);
274
276
 
275
277
  return;
276
278
}