MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ha_blackhole.cc
1 /* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 
17 #define MYSQL_SERVER 1
18 #include "sql_priv.h"
19 #include "unireg.h"
20 #include "probes_mysql.h"
21 #include "ha_blackhole.h"
22 #include "sql_class.h" // THD, SYSTEM_THREAD_SLAVE_*
23 
24 static bool is_slave_applier(THD *thd)
25 {
26  return thd->system_thread == SYSTEM_THREAD_SLAVE_SQL ||
27  thd->system_thread == SYSTEM_THREAD_SLAVE_WORKER;
28 }
29 
30 /* Static declarations for handlerton */
31 
32 static handler *blackhole_create_handler(handlerton *hton,
34  MEM_ROOT *mem_root)
35 {
36  return new (mem_root) ha_blackhole(hton, table);
37 }
38 
39 
40 /* Static declarations for shared structures */
41 
42 static mysql_mutex_t blackhole_mutex;
43 static HASH blackhole_open_tables;
44 
45 static st_blackhole_share *get_share(const char *table_name);
46 static void free_share(st_blackhole_share *share);
47 
48 /*****************************************************************************
49 ** BLACKHOLE tables
50 *****************************************************************************/
51 
52 ha_blackhole::ha_blackhole(handlerton *hton,
53  TABLE_SHARE *table_arg)
54  :handler(hton, table_arg)
55 {}
56 
57 
58 static const char *ha_blackhole_exts[] = {
59  NullS
60 };
61 
62 const char **ha_blackhole::bas_ext() const
63 {
64  return ha_blackhole_exts;
65 }
66 
67 int ha_blackhole::open(const char *name, int mode, uint test_if_locked)
68 {
69  DBUG_ENTER("ha_blackhole::open");
70 
71  if (!(share= get_share(name)))
72  DBUG_RETURN(HA_ERR_OUT_OF_MEM);
73 
74  thr_lock_data_init(&share->lock, &lock, NULL);
75  DBUG_RETURN(0);
76 }
77 
78 int ha_blackhole::close(void)
79 {
80  DBUG_ENTER("ha_blackhole::close");
81  free_share(share);
82  DBUG_RETURN(0);
83 }
84 
85 int ha_blackhole::create(const char *name, TABLE *table_arg,
86  HA_CREATE_INFO *create_info)
87 {
88  DBUG_ENTER("ha_blackhole::create");
89  DBUG_RETURN(0);
90 }
91 
92 /*
93  Intended to support partitioning.
94  Allows a particular partition to be truncated.
95 */
97 {
98  DBUG_ENTER("ha_blackhole::truncate");
99  DBUG_RETURN(0);
100 }
101 
102 const char *ha_blackhole::index_type(uint key_number)
103 {
104  DBUG_ENTER("ha_blackhole::index_type");
105  DBUG_RETURN((table_share->key_info[key_number].flags & HA_FULLTEXT) ?
106  "FULLTEXT" :
107  (table_share->key_info[key_number].flags & HA_SPATIAL) ?
108  "SPATIAL" :
109  (table_share->key_info[key_number].algorithm ==
110  HA_KEY_ALG_RTREE) ? "RTREE" : "BTREE");
111 }
112 
113 int ha_blackhole::write_row(uchar * buf)
114 {
115  DBUG_ENTER("ha_blackhole::write_row");
116  DBUG_RETURN(table->next_number_field ? update_auto_increment() : 0);
117 }
118 
119 int ha_blackhole::update_row(const uchar *old_data, uchar *new_data)
120 {
121  DBUG_ENTER("ha_blackhole::update_row");
122  THD *thd= ha_thd();
123  if (is_slave_applier(thd) && thd->query() == NULL)
124  DBUG_RETURN(0);
125  DBUG_RETURN(HA_ERR_WRONG_COMMAND);
126 }
127 
128 int ha_blackhole::delete_row(const uchar *buf)
129 {
130  DBUG_ENTER("ha_blackhole::delete_row");
131  THD *thd= ha_thd();
132  if (is_slave_applier(thd) && thd->query() == NULL)
133  DBUG_RETURN(0);
134  DBUG_RETURN(HA_ERR_WRONG_COMMAND);
135 }
136 
138 {
139  DBUG_ENTER("ha_blackhole::rnd_init");
140  DBUG_RETURN(0);
141 }
142 
143 
144 int ha_blackhole::rnd_next(uchar *buf)
145 {
146  int rc;
147  DBUG_ENTER("ha_blackhole::rnd_next");
148  MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
149  TRUE);
150  THD *thd= ha_thd();
151  if (is_slave_applier(thd) && thd->query() == NULL)
152  rc= 0;
153  else
154  rc= HA_ERR_END_OF_FILE;
155  MYSQL_READ_ROW_DONE(rc);
156  table->status= rc ? STATUS_NOT_FOUND : 0;
157  DBUG_RETURN(rc);
158 }
159 
160 
161 int ha_blackhole::rnd_pos(uchar * buf, uchar *pos)
162 {
163  DBUG_ENTER("ha_blackhole::rnd_pos");
164  MYSQL_READ_ROW_START(table_share->db.str, table_share->table_name.str,
165  FALSE);
166  DBUG_ASSERT(0);
167  MYSQL_READ_ROW_DONE(0);
168  DBUG_RETURN(0);
169 }
170 
171 
172 void ha_blackhole::position(const uchar *record)
173 {
174  DBUG_ENTER("ha_blackhole::position");
175  DBUG_ASSERT(0);
176  DBUG_VOID_RETURN;
177 }
178 
179 
180 int ha_blackhole::info(uint flag)
181 {
182  DBUG_ENTER("ha_blackhole::info");
183 
184  memset(&stats, 0, sizeof(stats));
185  if (flag & HA_STATUS_AUTO)
186  stats.auto_increment_value= 1;
187  DBUG_RETURN(0);
188 }
189 
190 int ha_blackhole::external_lock(THD *thd, int lock_type)
191 {
192  DBUG_ENTER("ha_blackhole::external_lock");
193  DBUG_RETURN(0);
194 }
195 
196 
198  THR_LOCK_DATA **to,
199  enum thr_lock_type lock_type)
200 {
201  DBUG_ENTER("ha_blackhole::store_lock");
202  if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
203  {
204  /*
205  Here is where we get into the guts of a row level lock.
206  If TL_UNLOCK is set
207  If we are not doing a LOCK TABLE or DISCARD/IMPORT
208  TABLESPACE, then allow multiple writers
209  */
210 
211  if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
212  lock_type <= TL_WRITE) && !thd_in_lock_tables(thd)
213  && !thd_tablespace_op(thd))
214  lock_type = TL_WRITE_ALLOW_WRITE;
215 
216  /*
217  In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
218  MySQL would use the lock TL_READ_NO_INSERT on t2, and that
219  would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
220  to t2. Convert the lock to a normal read lock to allow
221  concurrent inserts to t2.
222  */
223 
224  if (lock_type == TL_READ_NO_INSERT && !thd_in_lock_tables(thd))
225  lock_type = TL_READ;
226 
227  lock.type= lock_type;
228  }
229  *to++= &lock;
230  DBUG_RETURN(to);
231 }
232 
233 
234 int ha_blackhole::index_read_map(uchar * buf, const uchar * key,
235  key_part_map keypart_map,
236  enum ha_rkey_function find_flag)
237 {
238  int rc;
239  DBUG_ENTER("ha_blackhole::index_read");
240  MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
241  THD *thd= ha_thd();
242  if (is_slave_applier(thd) && thd->query() == NULL)
243  rc= 0;
244  else
245  rc= HA_ERR_END_OF_FILE;
246  MYSQL_INDEX_READ_ROW_DONE(rc);
247  table->status= rc ? STATUS_NOT_FOUND : 0;
248  DBUG_RETURN(rc);
249 }
250 
251 
252 int ha_blackhole::index_read_idx_map(uchar * buf, uint idx, const uchar * key,
253  key_part_map keypart_map,
254  enum ha_rkey_function find_flag)
255 {
256  int rc;
257  DBUG_ENTER("ha_blackhole::index_read_idx");
258  MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
259  THD *thd= ha_thd();
260  if (is_slave_applier(thd) && thd->query() == NULL)
261  rc= 0;
262  else
263  rc= HA_ERR_END_OF_FILE;
264  MYSQL_INDEX_READ_ROW_DONE(rc);
265  table->status= rc ? STATUS_NOT_FOUND : 0;
266  DBUG_RETURN(rc);
267 }
268 
269 
270 int ha_blackhole::index_read_last_map(uchar * buf, const uchar * key,
271  key_part_map keypart_map)
272 {
273  int rc;
274  DBUG_ENTER("ha_blackhole::index_read_last");
275  MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
276  THD *thd= ha_thd();
277  if (is_slave_applier(thd) && thd->query() == NULL)
278  rc= 0;
279  else
280  rc= HA_ERR_END_OF_FILE;
281  MYSQL_INDEX_READ_ROW_DONE(rc);
282  table->status= rc ? STATUS_NOT_FOUND : 0;
283  DBUG_RETURN(rc);
284 }
285 
286 
287 int ha_blackhole::index_next(uchar * buf)
288 {
289  int rc;
290  DBUG_ENTER("ha_blackhole::index_next");
291  MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
292  rc= HA_ERR_END_OF_FILE;
293  MYSQL_INDEX_READ_ROW_DONE(rc);
294  table->status= STATUS_NOT_FOUND;
295  DBUG_RETURN(rc);
296 }
297 
298 
299 int ha_blackhole::index_prev(uchar * buf)
300 {
301  int rc;
302  DBUG_ENTER("ha_blackhole::index_prev");
303  MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
304  rc= HA_ERR_END_OF_FILE;
305  MYSQL_INDEX_READ_ROW_DONE(rc);
306  table->status= STATUS_NOT_FOUND;
307  DBUG_RETURN(rc);
308 }
309 
310 
312 {
313  int rc;
314  DBUG_ENTER("ha_blackhole::index_first");
315  MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
316  rc= HA_ERR_END_OF_FILE;
317  MYSQL_INDEX_READ_ROW_DONE(rc);
318  table->status= STATUS_NOT_FOUND;
319  DBUG_RETURN(rc);
320 }
321 
322 
323 int ha_blackhole::index_last(uchar * buf)
324 {
325  int rc;
326  DBUG_ENTER("ha_blackhole::index_last");
327  MYSQL_INDEX_READ_ROW_START(table_share->db.str, table_share->table_name.str);
328  rc= HA_ERR_END_OF_FILE;
329  MYSQL_INDEX_READ_ROW_DONE(rc);
330  table->status= STATUS_NOT_FOUND;
331  DBUG_RETURN(rc);
332 }
333 
334 
335 static st_blackhole_share *get_share(const char *table_name)
336 {
337  st_blackhole_share *share;
338  uint length;
339 
340  length= (uint) strlen(table_name);
341  mysql_mutex_lock(&blackhole_mutex);
342 
343  if (!(share= (st_blackhole_share*)
344  my_hash_search(&blackhole_open_tables,
345  (uchar*) table_name, length)))
346  {
347  if (!(share= (st_blackhole_share*) my_malloc(sizeof(st_blackhole_share) +
348  length,
349  MYF(MY_WME | MY_ZEROFILL))))
350  goto error;
351 
352  share->table_name_length= length;
353  strmov(share->table_name, table_name);
354 
355  if (my_hash_insert(&blackhole_open_tables, (uchar*) share))
356  {
357  my_free(share);
358  share= NULL;
359  goto error;
360  }
361 
362  thr_lock_init(&share->lock);
363  }
364  share->use_count++;
365 
366 error:
367  mysql_mutex_unlock(&blackhole_mutex);
368  return share;
369 }
370 
371 static void free_share(st_blackhole_share *share)
372 {
373  mysql_mutex_lock(&blackhole_mutex);
374  if (!--share->use_count)
375  my_hash_delete(&blackhole_open_tables, (uchar*) share);
376  mysql_mutex_unlock(&blackhole_mutex);
377 }
378 
379 static void blackhole_free_key(st_blackhole_share *share)
380 {
381  thr_lock_delete(&share->lock);
382  my_free(share);
383 }
384 
385 static uchar* blackhole_get_key(st_blackhole_share *share, size_t *length,
386  my_bool not_used __attribute__((unused)))
387 {
388  *length= share->table_name_length;
389  return (uchar*) share->table_name;
390 }
391 
392 #ifdef HAVE_PSI_INTERFACE
393 static PSI_mutex_key bh_key_mutex_blackhole;
394 
395 static PSI_mutex_info all_blackhole_mutexes[]=
396 {
397  { &bh_key_mutex_blackhole, "blackhole", PSI_FLAG_GLOBAL}
398 };
399 
400 void init_blackhole_psi_keys()
401 {
402  const char* category= "blackhole";
403  int count;
404 
405  count= array_elements(all_blackhole_mutexes);
406  mysql_mutex_register(category, all_blackhole_mutexes, count);
407 }
408 #endif
409 
410 static int blackhole_init(void *p)
411 {
412  handlerton *blackhole_hton;
413 
414 #ifdef HAVE_PSI_INTERFACE
415  init_blackhole_psi_keys();
416 #endif
417 
418  blackhole_hton= (handlerton *)p;
419  blackhole_hton->state= SHOW_OPTION_YES;
420  blackhole_hton->db_type= DB_TYPE_BLACKHOLE_DB;
421  blackhole_hton->create= blackhole_create_handler;
422  blackhole_hton->flags= HTON_CAN_RECREATE;
423 
424  mysql_mutex_init(bh_key_mutex_blackhole,
425  &blackhole_mutex, MY_MUTEX_INIT_FAST);
426  (void) my_hash_init(&blackhole_open_tables, system_charset_info,32,0,0,
427  (my_hash_get_key) blackhole_get_key,
428  (my_hash_free_key) blackhole_free_key, 0);
429 
430  return 0;
431 }
432 
433 static int blackhole_fini(void *p)
434 {
435  my_hash_free(&blackhole_open_tables);
436  mysql_mutex_destroy(&blackhole_mutex);
437 
438  return 0;
439 }
440 
441 struct st_mysql_storage_engine blackhole_storage_engine=
442 { MYSQL_HANDLERTON_INTERFACE_VERSION };
443 
444 mysql_declare_plugin(blackhole)
445 {
446  MYSQL_STORAGE_ENGINE_PLUGIN,
447  &blackhole_storage_engine,
448  "BLACKHOLE",
449  "MySQL AB",
450  "/dev/null storage engine (anything you write to it disappears)",
451  PLUGIN_LICENSE_GPL,
452  blackhole_init, /* Plugin Init */
453  blackhole_fini, /* Plugin Deinit */
454  0x0100 /* 1.0 */,
455  NULL, /* status variables */
456  NULL, /* system variables */
457  NULL, /* config options */
458  0, /* flags */
459 }
460 mysql_declare_plugin_end;