mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
459 lines
12 KiB
C++
459 lines
12 KiB
C++
/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
|
|
|
|
|
#ifdef USE_PRAGMA_IMPLEMENTATION
|
|
#pragma implementation // gcc: Class implementation
|
|
#endif
|
|
|
|
#define MYSQL_SERVER 1
|
|
#include <my_global.h>
|
|
#include "sql_priv.h"
|
|
#include "unireg.h"
|
|
#include "ha_blackhole.h"
|
|
#include "sql_class.h" // THD, SYSTEM_THREAD_SLAVE_SQL
|
|
|
|
/**
|
|
Checks if the param 'thd' is pointing to slave applier thread and row based
|
|
replication is in use.
|
|
|
|
A row event will have its thd->query() == NULL except in cases where
|
|
replicate_annotate_row_events is enabled. In the later case the thd->query()
|
|
will be pointing to the query, received through replicated annotate event
|
|
from master.
|
|
|
|
@param thd pointer to a THD instance
|
|
|
|
@return TRUE if thread is slave applier and row based replication is in use
|
|
*/
|
|
static bool is_row_based_replication(THD *thd)
|
|
{
|
|
return thd->system_thread == SYSTEM_THREAD_SLAVE_SQL &&
|
|
(thd->query() == NULL || thd->variables.binlog_annotate_row_events);
|
|
}
|
|
/* Static declarations for handlerton */
|
|
|
|
static handler *blackhole_create_handler(handlerton *hton,
|
|
TABLE_SHARE *table,
|
|
MEM_ROOT *mem_root)
|
|
{
|
|
return new (mem_root) ha_blackhole(hton, table);
|
|
}
|
|
|
|
|
|
/* Static declarations for shared structures */
|
|
|
|
static mysql_mutex_t blackhole_mutex;
|
|
static HASH blackhole_open_tables;
|
|
|
|
static st_blackhole_share *get_share(const char *table_name);
|
|
static void free_share(st_blackhole_share *share);
|
|
|
|
/*****************************************************************************
|
|
** BLACKHOLE tables
|
|
*****************************************************************************/
|
|
|
|
ha_blackhole::ha_blackhole(handlerton *hton,
|
|
TABLE_SHARE *table_arg)
|
|
:handler(hton, table_arg)
|
|
{}
|
|
|
|
|
|
int ha_blackhole::open(const char *name, int mode, uint test_if_locked)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::open");
|
|
|
|
if (!(share= get_share(name)))
|
|
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
|
|
|
|
thr_lock_data_init(&share->lock, &lock, NULL);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int ha_blackhole::close(void)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::close");
|
|
free_share(share);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int ha_blackhole::create(const char *name, TABLE *table_arg,
|
|
HA_CREATE_INFO *create_info)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::create");
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
/*
|
|
Intended to support partitioning.
|
|
Allows a particular partition to be truncated.
|
|
*/
|
|
int ha_blackhole::truncate()
|
|
{
|
|
DBUG_ENTER("ha_blackhole::truncate");
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
const char *ha_blackhole::index_type(uint key_number)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::index_type");
|
|
DBUG_RETURN((table_share->key_info[key_number].flags & HA_FULLTEXT) ?
|
|
"FULLTEXT" :
|
|
(table_share->key_info[key_number].flags & HA_SPATIAL) ?
|
|
"SPATIAL" :
|
|
(table_share->key_info[key_number].algorithm ==
|
|
HA_KEY_ALG_RTREE) ? "RTREE" : "BTREE");
|
|
}
|
|
|
|
int ha_blackhole::write_row(uchar * buf)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::write_row");
|
|
DBUG_RETURN(table->next_number_field ? update_auto_increment() : 0);
|
|
}
|
|
|
|
int ha_blackhole::update_row(const uchar *old_data, const uchar *new_data)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::update_row");
|
|
THD *thd= ha_thd();
|
|
if (is_row_based_replication(thd))
|
|
DBUG_RETURN(0);
|
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
|
}
|
|
|
|
int ha_blackhole::delete_row(const uchar *buf)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::delete_row");
|
|
THD *thd= ha_thd();
|
|
if (is_row_based_replication(thd))
|
|
DBUG_RETURN(0);
|
|
DBUG_RETURN(HA_ERR_WRONG_COMMAND);
|
|
}
|
|
|
|
int ha_blackhole::rnd_init(bool scan)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::rnd_init");
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
int ha_blackhole::rnd_next(uchar *buf)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::rnd_next");
|
|
THD *thd= ha_thd();
|
|
if (is_row_based_replication(thd))
|
|
rc= 0;
|
|
else
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
int ha_blackhole::rnd_pos(uchar * buf, uchar *pos)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::rnd_pos");
|
|
DBUG_ASSERT(0);
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
void ha_blackhole::position(const uchar *record)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::position");
|
|
DBUG_ASSERT(0);
|
|
DBUG_VOID_RETURN;
|
|
}
|
|
|
|
|
|
int ha_blackhole::info(uint flag)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::info");
|
|
|
|
bzero((char*) &stats, sizeof(stats));
|
|
if (flag & HA_STATUS_AUTO)
|
|
stats.auto_increment_value= 1;
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
int ha_blackhole::external_lock(THD *thd, int lock_type)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::external_lock");
|
|
DBUG_RETURN(0);
|
|
}
|
|
|
|
|
|
THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd,
|
|
THR_LOCK_DATA **to,
|
|
enum thr_lock_type lock_type)
|
|
{
|
|
DBUG_ENTER("ha_blackhole::store_lock");
|
|
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
|
|
{
|
|
/*
|
|
Here is where we get into the guts of a row level lock.
|
|
If TL_UNLOCK is set
|
|
If we are not doing a LOCK TABLE or DISCARD/IMPORT
|
|
TABLESPACE, then allow multiple writers
|
|
*/
|
|
|
|
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
|
|
lock_type <= TL_WRITE) && !thd_in_lock_tables(thd)
|
|
&& !thd_tablespace_op(thd))
|
|
lock_type = TL_WRITE_ALLOW_WRITE;
|
|
|
|
/*
|
|
In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
|
|
MySQL would use the lock TL_READ_NO_INSERT on t2, and that
|
|
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
|
|
to t2. Convert the lock to a normal read lock to allow
|
|
concurrent inserts to t2.
|
|
*/
|
|
|
|
if (lock_type == TL_READ_NO_INSERT && !thd_in_lock_tables(thd))
|
|
lock_type = TL_READ;
|
|
|
|
lock.type= lock_type;
|
|
}
|
|
*to++= &lock;
|
|
DBUG_RETURN(to);
|
|
}
|
|
|
|
|
|
int ha_blackhole::index_read_map(uchar * buf, const uchar * key,
|
|
key_part_map keypart_map,
|
|
enum ha_rkey_function find_flag)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::index_read");
|
|
THD *thd= ha_thd();
|
|
if (is_row_based_replication(thd))
|
|
rc= 0;
|
|
else
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
int ha_blackhole::index_read_idx_map(uchar * buf, uint idx, const uchar * key,
|
|
key_part_map keypart_map,
|
|
enum ha_rkey_function find_flag)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::index_read_idx");
|
|
THD *thd= ha_thd();
|
|
if (is_row_based_replication(thd))
|
|
rc= 0;
|
|
else
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
int ha_blackhole::index_read_last_map(uchar * buf, const uchar * key,
|
|
key_part_map keypart_map)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::index_read_last");
|
|
THD *thd= ha_thd();
|
|
if (is_row_based_replication(thd))
|
|
rc= 0;
|
|
else
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
int ha_blackhole::index_next(uchar * buf)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::index_next");
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
int ha_blackhole::index_prev(uchar * buf)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::index_prev");
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
int ha_blackhole::index_first(uchar * buf)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::index_first");
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
int ha_blackhole::index_last(uchar * buf)
|
|
{
|
|
int rc;
|
|
DBUG_ENTER("ha_blackhole::index_last");
|
|
rc= HA_ERR_END_OF_FILE;
|
|
DBUG_RETURN(rc);
|
|
}
|
|
|
|
|
|
static st_blackhole_share *get_share(const char *table_name)
|
|
{
|
|
st_blackhole_share *share;
|
|
uint length;
|
|
|
|
length= (uint) strlen(table_name);
|
|
mysql_mutex_lock(&blackhole_mutex);
|
|
|
|
if (!(share= (st_blackhole_share*)
|
|
my_hash_search(&blackhole_open_tables,
|
|
(uchar*) table_name, length)))
|
|
{
|
|
if (!(share= (st_blackhole_share*) my_malloc(sizeof(st_blackhole_share) +
|
|
length,
|
|
MYF(MY_WME | MY_ZEROFILL))))
|
|
goto error;
|
|
|
|
share->table_name_length= length;
|
|
strmov(share->table_name, table_name);
|
|
|
|
if (my_hash_insert(&blackhole_open_tables, (uchar*) share))
|
|
{
|
|
my_free(share);
|
|
share= NULL;
|
|
goto error;
|
|
}
|
|
|
|
thr_lock_init(&share->lock);
|
|
}
|
|
share->use_count++;
|
|
|
|
error:
|
|
mysql_mutex_unlock(&blackhole_mutex);
|
|
return share;
|
|
}
|
|
|
|
static void free_share(st_blackhole_share *share)
|
|
{
|
|
mysql_mutex_lock(&blackhole_mutex);
|
|
if (!--share->use_count)
|
|
my_hash_delete(&blackhole_open_tables, (uchar*) share);
|
|
mysql_mutex_unlock(&blackhole_mutex);
|
|
}
|
|
|
|
static void blackhole_free_key(st_blackhole_share *share)
|
|
{
|
|
thr_lock_delete(&share->lock);
|
|
my_free(share);
|
|
}
|
|
|
|
static uchar* blackhole_get_key(st_blackhole_share *share, size_t *length,
|
|
my_bool not_used __attribute__((unused)))
|
|
{
|
|
*length= share->table_name_length;
|
|
return (uchar*) share->table_name;
|
|
}
|
|
|
|
#ifdef HAVE_PSI_INTERFACE
|
|
static PSI_mutex_key bh_key_mutex_blackhole;
|
|
|
|
static PSI_mutex_info all_blackhole_mutexes[]=
|
|
{
|
|
{ &bh_key_mutex_blackhole, "blackhole", PSI_FLAG_GLOBAL}
|
|
};
|
|
|
|
void init_blackhole_psi_keys()
|
|
{
|
|
const char* category= "blackhole";
|
|
int count;
|
|
|
|
if (PSI_server == NULL)
|
|
return;
|
|
|
|
count= array_elements(all_blackhole_mutexes);
|
|
PSI_server->register_mutex(category, all_blackhole_mutexes, count);
|
|
}
|
|
#endif
|
|
|
|
static int blackhole_init(void *p)
|
|
{
|
|
handlerton *blackhole_hton;
|
|
|
|
#ifdef HAVE_PSI_INTERFACE
|
|
init_blackhole_psi_keys();
|
|
#endif
|
|
|
|
blackhole_hton= (handlerton *)p;
|
|
blackhole_hton->state= SHOW_OPTION_YES;
|
|
blackhole_hton->db_type= DB_TYPE_BLACKHOLE_DB;
|
|
blackhole_hton->create= blackhole_create_handler;
|
|
blackhole_hton->flags= HTON_CAN_RECREATE;
|
|
|
|
mysql_mutex_init(bh_key_mutex_blackhole,
|
|
&blackhole_mutex, MY_MUTEX_INIT_FAST);
|
|
(void) my_hash_init(&blackhole_open_tables, system_charset_info,32,0,0,
|
|
(my_hash_get_key) blackhole_get_key,
|
|
(my_hash_free_key) blackhole_free_key, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int blackhole_fini(void *p)
|
|
{
|
|
my_hash_free(&blackhole_open_tables);
|
|
mysql_mutex_destroy(&blackhole_mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct st_mysql_storage_engine blackhole_storage_engine=
|
|
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
|
|
|
|
mysql_declare_plugin(blackhole)
|
|
{
|
|
MYSQL_STORAGE_ENGINE_PLUGIN,
|
|
&blackhole_storage_engine,
|
|
"BLACKHOLE",
|
|
"MySQL AB",
|
|
"/dev/null storage engine (anything you write to it disappears)",
|
|
PLUGIN_LICENSE_GPL,
|
|
blackhole_init, /* Plugin Init */
|
|
blackhole_fini, /* Plugin Deinit */
|
|
0x0100 /* 1.0 */,
|
|
NULL, /* status variables */
|
|
NULL, /* system variables */
|
|
NULL, /* config options */
|
|
0, /* flags */
|
|
}
|
|
mysql_declare_plugin_end;
|
|
maria_declare_plugin(blackhole)
|
|
{
|
|
MYSQL_STORAGE_ENGINE_PLUGIN,
|
|
&blackhole_storage_engine,
|
|
"BLACKHOLE",
|
|
"MySQL AB",
|
|
"/dev/null storage engine (anything you write to it disappears)",
|
|
PLUGIN_LICENSE_GPL,
|
|
blackhole_init, /* Plugin Init */
|
|
blackhole_fini, /* Plugin Deinit */
|
|
0x0100 /* 1.0 */,
|
|
NULL, /* status variables */
|
|
NULL, /* system variables */
|
|
"1.0", /* string version */
|
|
MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
|
|
}
|
|
maria_declare_plugin_end;
|