diff options
Diffstat (limited to '')
-rw-r--r-- | sql/rpl_tblmap.cc | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/sql/rpl_tblmap.cc b/sql/rpl_tblmap.cc new file mode 100644 index 00000000..a230b9f6 --- /dev/null +++ b/sql/rpl_tblmap.cc @@ -0,0 +1,182 @@ +/* Copyright (c) 2005, 2010, 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 */ + +#include "mariadb.h" +#include "sql_priv.h" + +#ifdef HAVE_REPLICATION + +#include "rpl_tblmap.h" +#ifndef MYSQL_CLIENT +#include "table.h" +#endif + +#ifdef MYSQL_CLIENT +#define MAYBE_TABLE_NAME(T) ("") +#else +#define MAYBE_TABLE_NAME(T) ((T) ? (T)->s->table_name.str : "<>") +#endif +#define TABLE_ID_HASH_SIZE 32 +#define TABLE_ID_CHUNK 256 + +table_mapping::table_mapping() + : m_free(0) +{ +#ifdef MYSQL_CLIENT + PSI_memory_key psi_key= PSI_NOT_INSTRUMENTED; +#else + PSI_memory_key psi_key= key_memory_table_mapping_root; +#endif + + DBUG_ENTER("table_mapping::table_mapping"); + /* + No "free_element" function for entries passed here, as the entries are + allocated in a MEM_ROOT (freed as a whole in the destructor), they cannot + be freed one by one. + Note that below we don't test if my_hash_init() succeeded. This + constructor is called at startup only. + */ + (void) my_hash_init(psi_key, &m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE, + offsetof(entry,table_id),sizeof(ulonglong), + 0,0,0); + /* We don't preallocate any block, this is consistent with m_free=0 above */ + init_alloc_root(psi_key, &m_mem_root, TABLE_ID_HASH_SIZE*sizeof(entry), 0, MYF(0)); + DBUG_VOID_RETURN; +} + +table_mapping::~table_mapping() +{ +#ifdef MYSQL_CLIENT + clear_tables(); +#endif + my_hash_free(&m_table_ids); + free_root(&m_mem_root, MYF(0)); +} + +TABLE* table_mapping::get_table(ulonglong table_id) +{ + DBUG_ENTER("table_mapping::get_table(ulong)"); + DBUG_PRINT("enter", ("table_id: %llu", table_id)); + entry *e= find_entry(table_id); + if (e) + { + DBUG_PRINT("info", ("tid %llu -> table %p (%s)", + table_id, e->table, + MAYBE_TABLE_NAME(e->table))); + DBUG_RETURN(e->table); + } + + DBUG_PRINT("info", ("tid %llu is not mapped!", table_id)); + DBUG_RETURN(NULL); +} + +/* + Called when we are out of table id entries. Creates TABLE_ID_CHUNK + new entries, chain them and attach them at the head of the list of free + (free for use) entries. +*/ +int table_mapping::expand() +{ + /* + If we wanted to use "tmp= new (&m_mem_root) entry[TABLE_ID_CHUNK]", + we would have to make "entry" derive from Sql_alloc but then it would not + be a POD anymore and we want it to be (see rpl_tblmap.h). So we allocate + in C. + */ + entry *tmp= (entry *)alloc_root(&m_mem_root, TABLE_ID_CHUNK*sizeof(entry)); + if (tmp == NULL) + return ERR_MEMORY_ALLOCATION; // Memory allocation failed + + /* Find the end of this fresh new array of free entries */ + entry *e_end= tmp+TABLE_ID_CHUNK-1; + for (entry *e= tmp; e < e_end; e++) + e->next= e+1; + e_end->next= m_free; + m_free= tmp; + return 0; +} + +int table_mapping::set_table(ulonglong table_id, TABLE* table) +{ + DBUG_ENTER("table_mapping::set_table(ulong,TABLE*)"); + DBUG_PRINT("enter", ("table_id: %llu table: %p (%s)", + table_id, + table, MAYBE_TABLE_NAME(table))); + entry *e= find_entry(table_id); + if (e == 0) + { + if (m_free == 0 && expand()) + DBUG_RETURN(ERR_MEMORY_ALLOCATION); // Memory allocation failed + e= m_free; + m_free= m_free->next; + } + else + { +#ifdef MYSQL_CLIENT + free_table_map_log_event(e->table); +#endif + my_hash_delete(&m_table_ids,(uchar *)e); + } + e->table_id= table_id; + e->table= table; + if (my_hash_insert(&m_table_ids,(uchar *)e)) + { + /* we add this entry to the chain of free (free for use) entries */ + e->next= m_free; + m_free= e; + DBUG_RETURN(ERR_MEMORY_ALLOCATION); + } + + DBUG_PRINT("info", ("tid %llu -> table %p (%s)", + table_id, e->table, + MAYBE_TABLE_NAME(e->table))); + DBUG_RETURN(0); // All OK +} + +int table_mapping::remove_table(ulonglong table_id) +{ + entry *e= find_entry(table_id); + if (e) + { + my_hash_delete(&m_table_ids,(uchar *)e); + /* we add this entry to the chain of free (free for use) entries */ + e->next= m_free; + m_free= e; + return 0; // All OK + } + return 1; // No table to remove +} + +/* + Puts all entries into the list of free-for-use entries (does not free any + memory), and empties the hash. +*/ +void table_mapping::clear_tables() +{ + DBUG_ENTER("table_mapping::clear_tables()"); + for (uint i= 0; i < m_table_ids.records; i++) + { + entry *e= (entry *)my_hash_element(&m_table_ids, i); +#ifdef MYSQL_CLIENT + free_table_map_log_event(e->table); +#endif + e->next= m_free; + m_free= e; + } + my_hash_reset(&m_table_ids); + DBUG_VOID_RETURN; +} + +#endif |