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 | |
34 | table_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 | |
54 | table_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 | |
63 | TABLE* 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 | */ |
85 | int 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 | |
106 | int 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 | |
143 | int 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 | */ |
161 | void 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 | |