1/* Copyright (c) 2005, 2010, 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#include "mariadb.h"
17#include "sql_priv.h"
18
19#ifdef HAVE_REPLICATION
20
21#include "rpl_tblmap.h"
22#ifndef MYSQL_CLIENT
23#include "table.h"
24#endif
25
26#ifdef MYSQL_CLIENT
27#define MAYBE_TABLE_NAME(T) ("")
28#else
29#define MAYBE_TABLE_NAME(T) ((T) ? (T)->s->table_name.str : "<>")
30#endif
31#define TABLE_ID_HASH_SIZE 32
32#define TABLE_ID_CHUNK 256
33
34table_mapping::table_mapping()
35 : m_free(0)
36{
37 DBUG_ENTER("table_mapping::table_mapping");
38 /*
39 No "free_element" function for entries passed here, as the entries are
40 allocated in a MEM_ROOT (freed as a whole in the destructor), they cannot
41 be freed one by one.
42 Note that below we don't test if my_hash_init() succeeded. This
43 constructor is called at startup only.
44 */
45 (void) my_hash_init(&m_table_ids,&my_charset_bin,TABLE_ID_HASH_SIZE,
46 offsetof(entry,table_id),sizeof(ulong),
47 0,0,0);
48 /* We don't preallocate any block, this is consistent with m_free=0 above */
49 init_alloc_root(&m_mem_root, "table_mapping",
50 TABLE_ID_HASH_SIZE*sizeof(entry), 0, MYF(0));
51 DBUG_VOID_RETURN;
52}
53
54table_mapping::~table_mapping()
55{
56#ifdef MYSQL_CLIENT
57 clear_tables();
58#endif
59 my_hash_free(&m_table_ids);
60 free_root(&m_mem_root, MYF(0));
61}
62
63TABLE* table_mapping::get_table(ulong table_id)
64{
65 DBUG_ENTER("table_mapping::get_table(ulong)");
66 DBUG_PRINT("enter", ("table_id: %lu", table_id));
67 entry *e= find_entry(table_id);
68 if (e)
69 {
70 DBUG_PRINT("info", ("tid %lu -> table %p (%s)",
71 table_id, e->table,
72 MAYBE_TABLE_NAME(e->table)));
73 DBUG_RETURN(e->table);
74 }
75
76 DBUG_PRINT("info", ("tid %lu is not mapped!", table_id));
77 DBUG_RETURN(NULL);
78}
79
80/*
81 Called when we are out of table id entries. Creates TABLE_ID_CHUNK
82 new entries, chain them and attach them at the head of the list of free
83 (free for use) entries.
84*/
85int table_mapping::expand()
86{
87 /*
88 If we wanted to use "tmp= new (&m_mem_root) entry[TABLE_ID_CHUNK]",
89 we would have to make "entry" derive from Sql_alloc but then it would not
90 be a POD anymore and we want it to be (see rpl_tblmap.h). So we allocate
91 in C.
92 */
93 entry *tmp= (entry *)alloc_root(&m_mem_root, TABLE_ID_CHUNK*sizeof(entry));
94 if (tmp == NULL)
95 return ERR_MEMORY_ALLOCATION; // Memory allocation failed
96
97 /* Find the end of this fresh new array of free entries */
98 entry *e_end= tmp+TABLE_ID_CHUNK-1;
99 for (entry *e= tmp; e < e_end; e++)
100 e->next= e+1;
101 e_end->next= m_free;
102 m_free= tmp;
103 return 0;
104}
105
106int table_mapping::set_table(ulong table_id, TABLE* table)
107{
108 DBUG_ENTER("table_mapping::set_table(ulong,TABLE*)");
109 DBUG_PRINT("enter", ("table_id: %lu table: %p (%s)",
110 table_id,
111 table, MAYBE_TABLE_NAME(table)));
112 entry *e= find_entry(table_id);
113 if (e == 0)
114 {
115 if (m_free == 0 && expand())
116 DBUG_RETURN(ERR_MEMORY_ALLOCATION); // Memory allocation failed
117 e= m_free;
118 m_free= m_free->next;
119 }
120 else
121 {
122#ifdef MYSQL_CLIENT
123 free_table_map_log_event(e->table);
124#endif
125 my_hash_delete(&m_table_ids,(uchar *)e);
126 }
127 e->table_id= table_id;
128 e->table= table;
129 if (my_hash_insert(&m_table_ids,(uchar *)e))
130 {
131 /* we add this entry to the chain of free (free for use) entries */
132 e->next= m_free;
133 m_free= e;
134 DBUG_RETURN(ERR_MEMORY_ALLOCATION);
135 }
136
137 DBUG_PRINT("info", ("tid %lu -> table %p (%s)",
138 table_id, e->table,
139 MAYBE_TABLE_NAME(e->table)));
140 DBUG_RETURN(0); // All OK
141}
142
143int table_mapping::remove_table(ulong table_id)
144{
145 entry *e= find_entry(table_id);
146 if (e)
147 {
148 my_hash_delete(&m_table_ids,(uchar *)e);
149 /* we add this entry to the chain of free (free for use) entries */
150 e->next= m_free;
151 m_free= e;
152 return 0; // All OK
153 }
154 return 1; // No table to remove
155}
156
157/*
158 Puts all entries into the list of free-for-use entries (does not free any
159 memory), and empties the hash.
160*/
161void table_mapping::clear_tables()
162{
163 DBUG_ENTER("table_mapping::clear_tables()");
164 for (uint i= 0; i < m_table_ids.records; i++)
165 {
166 entry *e= (entry *)my_hash_element(&m_table_ids, i);
167#ifdef MYSQL_CLIENT
168 free_table_map_log_event(e->table);
169#endif
170 e->next= m_free;
171 m_free= e;
172 }
173 my_hash_reset(&m_table_ids);
174 DBUG_VOID_RETURN;
175}
176
177#endif
178