1 /*
2    Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "ndb_share.h"
26 #include "ndb_event_data.h"
27 #include "ndb_dist_priv_util.h"
28 #include "ha_ndbcluster_tables.h"
29 #include "ndb_conflict.h"
30 #include "ndb_name_util.h"
31 
32 #include <ndbapi/NdbEventOperation.hpp>
33 
34 #include <my_sys.h>
35 
36 extern Ndb* g_ndb;
37 
38 void
destroy(NDB_SHARE * share)39 NDB_SHARE::destroy(NDB_SHARE* share)
40 {
41   thr_lock_delete(&share->lock);
42   native_mutex_destroy(&share->mutex);
43 
44 #ifdef HAVE_NDB_BINLOG
45   teardown_conflict_fn(g_ndb, share->m_cfn_share);
46 #endif
47   share->new_op= 0;
48   Ndb_event_data* event_data = share->event_data;
49   if (event_data)
50   {
51     delete event_data;
52     event_data= 0;
53   }
54   // Release memory for the variable length strings held by
55   // key but also referenced by db, table_name and shadow_table->db etc.
56   free_key(share->key);
57   my_free(share);
58 }
59 
60 /*
61   Struct holding dynamic length strings for NDB_SHARE. The type is
62   opaque to the user of NDB_SHARE and should
63   only be accessed using NDB_SHARE accessor functions.
64 
65   All the strings are zero terminated.
66 
67   Layout:
68   size_t key_length
69   "key"\0
70   "db\0"
71   "table_name\0"
72 */
73 struct NDB_SHARE_KEY {
74   size_t m_key_length;
75   char m_buffer[1];
76 };
77 
78 NDB_SHARE_KEY*
create_key(const char * new_key)79 NDB_SHARE::create_key(const char *new_key)
80 {
81   const size_t new_key_length = strlen(new_key);
82 
83   char db_name_buf[FN_HEADLEN];
84   ndb_set_dbname(new_key, db_name_buf);
85   const size_t db_name_len = strlen(db_name_buf);
86 
87   char table_name_buf[FN_HEADLEN];
88   ndb_set_tabname(new_key, table_name_buf);
89   const size_t table_name_len = strlen(table_name_buf);
90 
91   // Calculate total size needed for the variable length strings
92   const size_t size=
93       sizeof(NDB_SHARE_KEY) +
94       new_key_length +
95       db_name_len + 1 +
96       table_name_len + 1;
97 
98   NDB_SHARE_KEY* allocated_key=
99       (NDB_SHARE_KEY*) my_malloc(PSI_INSTRUMENT_ME,
100                                  size,
101                                  MYF(MY_WME | ME_FATALERROR));
102 
103   allocated_key->m_key_length = new_key_length;
104 
105   // Copy key into the buffer
106   char* buf_ptr = allocated_key->m_buffer;
107   my_stpcpy(buf_ptr, new_key);
108   buf_ptr += new_key_length + 1;
109 
110   // Copy db_name into the buffer
111   my_stpcpy(buf_ptr, db_name_buf);
112   buf_ptr += db_name_len + 1;
113 
114   // Copy table_name into the buffer
115   my_stpcpy(buf_ptr, table_name_buf);
116   buf_ptr += table_name_len;
117 
118   // Check that writing has not occured beyond end of allocated memory
119   assert(buf_ptr < reinterpret_cast<char*>(allocated_key) + size);
120 
121   DBUG_PRINT("info", ("size: %lu, sizeof(NDB_SHARE_KEY): %lu",
122                       size, sizeof(NDB_SHARE_KEY)));
123   DBUG_PRINT("info", ("new_key: '%s', %lu", new_key, new_key_length));
124   DBUG_PRINT("info", ("db_name: '%s', %lu", db_name_buf, db_name_len));
125   DBUG_PRINT("info", ("table_name: '%s', %lu", table_name_buf, table_name_len));
126   DBUG_DUMP("NDB_SHARE_KEY: ", (const uchar*)allocated_key->m_buffer, size);
127 
128   return allocated_key;
129 }
130 
131 
free_key(NDB_SHARE_KEY * key)132 void NDB_SHARE::free_key(NDB_SHARE_KEY* key)
133 {
134   my_free(key);
135 }
136 
137 
key_get_key(NDB_SHARE_KEY * key)138 const uchar* NDB_SHARE::key_get_key(NDB_SHARE_KEY* key)
139 {
140   assert(key->m_key_length == strlen(key->m_buffer));
141   return (const uchar*)key->m_buffer;
142 }
143 
144 
key_get_length(NDB_SHARE_KEY * key)145 size_t NDB_SHARE::key_get_length(NDB_SHARE_KEY* key)
146 {
147   assert(key->m_key_length == strlen(key->m_buffer));
148   return key->m_key_length;
149 }
150 
151 
key_get_db_name(NDB_SHARE_KEY * key)152 char* NDB_SHARE::key_get_db_name(NDB_SHARE_KEY* key)
153 {
154   char* buf_ptr = key->m_buffer;
155   // Step past the key string and it's zero terminator
156   buf_ptr += key->m_key_length + 1;
157   return buf_ptr;
158 }
159 
160 
key_get_table_name(NDB_SHARE_KEY * key)161 char* NDB_SHARE::key_get_table_name(NDB_SHARE_KEY* key)
162 {
163   char* buf_ptr = key_get_db_name(key);
164   const size_t db_name_len = strlen(buf_ptr);
165   // Step past the db name string and it's zero terminator
166   buf_ptr += db_name_len + 1;
167   return buf_ptr;
168 }
169 
170 
key_length() const171 size_t NDB_SHARE::key_length() const
172 {
173   assert(key->m_key_length == strlen(key->m_buffer));
174   return key->m_key_length;
175 }
176 
177 
key_string() const178 const char* NDB_SHARE::key_string() const
179 {
180   assert(strlen(key->m_buffer) == key->m_key_length);
181   return key->m_buffer;
182 }
183 
184 
185 bool
need_events(bool default_on) const186 NDB_SHARE::need_events(bool default_on) const
187 {
188   DBUG_ENTER("NDB_SHARE::need_events");
189   DBUG_PRINT("enter", ("db: %s, table_name: %s",
190                         db, table_name));
191 
192   if (default_on)
193   {
194     // Events are on by default, check if it should be turned off
195 
196     if (Ndb_dist_priv_util::is_distributed_priv_table(db, table_name))
197     {
198       /*
199         The distributed privilege tables are distributed by writing
200         the CREATE USER, GRANT, REVOKE etc. to ndb_schema -> no need
201         to listen to events from those table
202       */
203       DBUG_PRINT("exit", ("no events for dist priv table"));
204       DBUG_RETURN(false);
205     }
206 
207     DBUG_PRINT("exit", ("need events(the default for this mysqld)"));
208     DBUG_RETURN(true);
209   }
210 
211   // Events are off by default, check if it should be turned on
212   if (strcmp(db, NDB_REP_DB) == 0)
213   {
214     // The table is in "mysql" database
215     if (strcmp(table_name, NDB_SCHEMA_TABLE) == 0)
216     {
217       DBUG_PRINT("exit", ("need events for " NDB_SCHEMA_TABLE));
218       DBUG_RETURN(true);
219     }
220 
221     if (strcmp(table_name, NDB_APPLY_TABLE) == 0)
222     {
223       DBUG_PRINT("exit", ("need events for " NDB_APPLY_TABLE));
224       DBUG_RETURN(true);
225     }
226   }
227 
228   DBUG_PRINT("exit", ("no events(the default for this mysqld)"));
229   DBUG_RETURN(false);
230 }
231 
232 
get_event_data_ptr() const233 Ndb_event_data* NDB_SHARE::get_event_data_ptr() const
234 {
235   if (event_data)
236   {
237     // The event_data pointer is only used before
238     // creating the NdbEventoperation -> check no op yet
239     assert(!op);
240 
241     return event_data;
242   }
243 
244   if (op)
245   {
246     // The event_data should now be empty since it's been moved to
247     // op's custom data
248     assert(!event_data);
249 
250     // Check that op has custom data
251     assert(op->getCustomData());
252 
253     return (Ndb_event_data*)op->getCustomData();
254   }
255 
256   return NULL;
257 }
258 
259 
print(const char * where,FILE * file) const260 void NDB_SHARE::print(const char* where, FILE* file) const
261 {
262   fprintf(file, "%s %s.%s: use_count: %u\n",
263           where, db, table_name, use_count);
264   fprintf(file, "  - key: '%s', key_length: %lu\n",
265           key_string(), key_length());
266   fprintf(file, "  - commit_count: %llu\n", commit_count);
267   if (event_data)
268     fprintf(file, "  - event_data: %p\n", event_data);
269   if (op)
270     fprintf(file, "  - op: %p\n", op);
271   if (new_op)
272     fprintf(file, "  - new_op: %p\n", new_op);
273 
274   Ndb_event_data *event_data_ptr= get_event_data_ptr();
275   if (event_data_ptr)
276     event_data_ptr->print("  -", file);
277 }
278