MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DictCache.cpp
1 /*
2  Copyright (c) 2003, 2010, 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 as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include <ndb_global.h>
19 #include "DictCache.hpp"
20 #include "NdbDictionaryImpl.hpp"
21 #include <NdbTick.h>
22 #include <NdbCondition.h>
23 #include <NdbSleep.h>
24 
25 static NdbTableImpl * f_invalid_table = 0;
26 static NdbTableImpl * f_altered_table = 0;
27 
28 static int ndb_dict_cache_count = 0;
29 
31 Ndb_local_table_info::create(NdbTableImpl *table_impl, Uint32 sz)
32 {
33  assert(! is_ndb_blob_table(table_impl));
34  Uint32 tot_size= sizeof(Ndb_local_table_info) - sizeof(Uint64)
35  + ((sz+7) & ~7); // round to Uint64
36  void *data= malloc(tot_size);
37  if (data == 0)
38  return 0;
39  memset(data, 0, tot_size);
40  new (data) Ndb_local_table_info(table_impl);
41  return (Ndb_local_table_info *) data;
42 }
43 
44 void Ndb_local_table_info::destroy(Ndb_local_table_info *info)
45 {
46  free((void *)info);
47 }
48 
49 Ndb_local_table_info::Ndb_local_table_info(NdbTableImpl *table_impl)
50 {
51  assert(! is_ndb_blob_table(table_impl));
52  m_table_impl= table_impl;
53  m_tuple_id_range.reset();
54 }
55 
56 Ndb_local_table_info::~Ndb_local_table_info()
57 {
58 }
59 
60 LocalDictCache::LocalDictCache(){
61  m_tableHash.createHashTable();
62 }
63 
64 LocalDictCache::~LocalDictCache(){
65  m_tableHash.releaseHashTable();
66 }
67 
69 LocalDictCache::get(const char * name){
70  ASSERT_NOT_MYSQLD;
71  assert(! is_ndb_blob_table(name));
72  const Uint32 len = (Uint32)strlen(name);
73  return m_tableHash.getData(name, len);
74 }
75 
76 void
77 LocalDictCache::put(const char * name, Ndb_local_table_info * tab_info){
78  ASSERT_NOT_MYSQLD;
79  assert(! is_ndb_blob_table(name));
80  const Uint32 id = tab_info->m_table_impl->m_id;
81  m_tableHash.insertKey(name, (Uint32)strlen(name), id, tab_info);
82 }
83 
84 void
85 LocalDictCache::drop(const char * name){
86  ASSERT_NOT_MYSQLD;
87  assert(! is_ndb_blob_table(name));
88  Ndb_local_table_info *info= m_tableHash.deleteKey(name, (Uint32)strlen(name));
89  DBUG_ASSERT(info != 0);
90  Ndb_local_table_info::destroy(info);
91 }
92 
93 /*****************************************************************
94  * Global cache
95  */
96 GlobalDictCache::GlobalDictCache(){
97  DBUG_ENTER("GlobalDictCache::GlobalDictCache");
98  m_tableHash.createHashTable();
99  m_waitForTableCondition = NdbCondition_Create();
100  if (f_invalid_table == NULL)
101  f_invalid_table = new NdbTableImpl();
102  if (f_altered_table == NULL)
103  f_altered_table = new NdbTableImpl();
104  ndb_dict_cache_count++;
105  DBUG_VOID_RETURN;
106 }
107 
108 GlobalDictCache::~GlobalDictCache(){
109  DBUG_ENTER("GlobalDictCache::~GlobalDictCache");
110  if (--ndb_dict_cache_count == 0)
111  {
112  if (f_invalid_table)
113  {
114  delete f_invalid_table;
115  f_invalid_table = 0;
116  }
117  if (f_altered_table)
118  {
119  delete f_altered_table;
120  f_altered_table = 0;
121  }
122  }
123  NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
124  while(curr != 0){
125  Vector<TableVersion> * vers = curr->theData;
126  const unsigned sz = vers->size();
127  for(unsigned i = 0; i<sz ; i++){
128  TableVersion tv= (*vers)[i];
129  DBUG_PRINT(" ", ("vers[%d]: ver: %d, refCount: %d, status: %d",
130  i, tv.m_version, tv.m_refCount, tv.m_status));
131  if(tv.m_impl != 0)
132  {
133  DBUG_PRINT(" ", ("m_impl: internalname: %s",
134  tv.m_impl->m_internalName.c_str()));
135  delete (* vers)[i].m_impl;
136  }
137  }
138  delete curr->theData;
139  curr->theData= NULL;
140  curr = m_tableHash.getNext(curr);
141  }
142  m_tableHash.releaseHashTable();
143  NdbCondition_Destroy(m_waitForTableCondition);
144  DBUG_VOID_RETURN;
145 }
146 
147 void GlobalDictCache::printCache()
148 {
149  DBUG_ENTER("GlobalDictCache::printCache");
150  NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
151  while(curr != 0){
152  DBUG_PRINT("curr", ("len: %d, hash: %d, lk: %d, str: %s",
153  curr->len, curr->hash, curr->localkey1,
154  (char*) curr->str));
155  if (curr->theData){
156  Vector<TableVersion> * vers = curr->theData;
157  const unsigned sz = vers->size();
158  for(unsigned i = 0; i<sz ; i++){
159  TableVersion tv= (*vers)[i];
160  DBUG_PRINT(" ", ("impl: %p vers[%d]: ver: %d, refCount: %d, status: %d",
161  tv.m_impl, i, tv.m_version, tv.m_refCount, tv.m_status));
162  if(tv.m_impl != 0)
163  {
164  DBUG_PRINT(" ", ("m_impl: internalname: %s",
165  tv.m_impl->m_internalName.c_str()));
166  }
167  }
168  }
169  else
170  {
171  DBUG_PRINT(" ", ("NULL"));
172  }
173  curr = m_tableHash.getNext(curr);
174  }
175  DBUG_VOID_RETURN;
176 }
177 
178 NdbTableImpl *
179 GlobalDictCache::get(const char * name, int *error)
180 {
181  DBUG_ENTER("GlobalDictCache::get");
182  DBUG_PRINT("enter", ("name: %s", name));
183  assert(! is_ndb_blob_table(name));
184 
185  const Uint32 len = (Uint32)strlen(name);
186  Vector<TableVersion> * versions = 0;
187  versions = m_tableHash.getData(name, len);
188  if(versions == 0){
189  versions = new Vector<TableVersion>(2);
190  if (versions == NULL)
191  {
192  *error = -1;
193  DBUG_RETURN(0);
194  }
195  m_tableHash.insertKey(name, len, 0, versions);
196  }
197 
198  int waitTime = 100;
199 
200  bool retreive = false;
201  while(versions->size() > 0 && !retreive){
202  TableVersion * ver = & versions->back();
203  switch(ver->m_status){
204  case OK:
205  if (ver->m_impl->m_status == NdbDictionary::Object::Invalid)
206  {
207  ver->m_status = DROPPED;
208  retreive = true; // Break loop
209  if (ver->m_refCount == 0)
210  {
211  delete ver->m_impl;
212  versions->erase(versions->size() - 1);
213  }
214  break;
215  }
216  ver->m_refCount++;
217  DBUG_PRINT("info", ("Table OK tab: %p version=%x.%x refCount=%u",
218  ver->m_impl,
219  ver->m_impl->m_version & 0xFFFFFF,
220  ver->m_impl->m_version >> 24,
221  ver->m_refCount));
222  DBUG_RETURN(ver->m_impl);
223  case DROPPED:
224  retreive = true; // Break loop
225  break;
226  case RETREIVING:
227  DBUG_PRINT("info", ("Wait for retrieving thread"));
228  NdbCondition_WaitTimeout(m_waitForTableCondition, m_mutex, waitTime);
229  continue;
230  }
231  }
232 
236  TableVersion tmp;
237  tmp.m_version = 0;
238  tmp.m_impl = 0;
239  tmp.m_status = RETREIVING;
240  tmp.m_refCount = 1; // The one retreiving it
241  if (versions->push_back(tmp))
242  {
243  *error = -1;
244  DBUG_RETURN(0);
245  }
246  DBUG_PRINT("info", ("No table found"));
247  DBUG_RETURN(0);
248 }
249 
250 NdbTableImpl *
251 GlobalDictCache::put(const char * name, NdbTableImpl * tab)
252 {
253  DBUG_ENTER("GlobalDictCache::put");
254  DBUG_PRINT("enter", ("tab: %p name: %s, internal_name: %s version: %x.%x",
255  tab, name,
256  tab ? tab->m_internalName.c_str() : "tab NULL",
257  tab ? tab->m_version & 0xFFFFFF : 0,
258  tab ? tab->m_version >> 24 : 0));
259  assert(! is_ndb_blob_table(name));
260 
261  const Uint32 len = (Uint32)strlen(name);
262  Vector<TableVersion> * vers = m_tableHash.getData(name, len);
263  if(vers == 0){
264  // Should always tried to retreive it first
265  // and thus there should be a record
266  abort();
267  }
268 
269  const Uint32 sz = vers->size();
270  if(sz == 0){
271  // Should always tried to retreive it first
272  // and thus there should be a record
273  abort();
274  }
275 
276  TableVersion & ver = vers->back();
277  if(ver.m_status != RETREIVING ||
278  !(ver.m_impl == 0 ||
279  ver.m_impl == f_invalid_table || ver.m_impl == f_altered_table) ||
280  ver.m_version != 0 ||
281  ver.m_refCount == 0){
282  abort();
283  }
284 
285  if(tab == 0)
286  {
287  DBUG_PRINT("info", ("No table found in db"));
288  vers->erase(sz - 1);
289  }
290  else if (ver.m_impl == 0) {
291  DBUG_PRINT("info", ("Table OK"));
292  ver.m_impl = tab;
293  ver.m_version = tab->m_version;
294  ver.m_status = OK;
295  }
296  else if (ver.m_impl == f_invalid_table)
297  {
298  DBUG_PRINT("info", ("Table DROPPED invalid"));
299  ver.m_impl = tab;
300  ver.m_version = tab->m_version;
301  ver.m_status = DROPPED;
302  ver.m_impl->m_status = NdbDictionary::Object::Invalid;
303  }
304  else if(ver.m_impl == f_altered_table)
305  {
306  DBUG_PRINT("info", ("Table DROPPED altered"));
307  ver.m_impl = tab;
308  ver.m_version = tab->m_version;
309  ver.m_status = DROPPED;
310  ver.m_impl->m_status = NdbDictionary::Object::Altered;
311  }
312  else
313  {
314  abort();
315  }
316  NdbCondition_Broadcast(m_waitForTableCondition);
317  DBUG_RETURN(tab);
318 }
319 
320 unsigned
321 GlobalDictCache::get_size()
322 {
323  NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
324  int sz = 0;
325  while(curr != 0){
326  sz += curr->theData->size();
327  curr = m_tableHash.getNext(curr);
328  }
329  if (sz)
330  {
331  printCache();
332  }
333  return sz;
334 }
335 
336 void
337 GlobalDictCache::invalidate_all()
338 {
339  DBUG_ENTER("GlobalDictCache::invalidate_all");
340  NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
341  while(curr != 0){
342  Vector<TableVersion> * vers = curr->theData;
343  if (vers->size())
344  {
345  TableVersion * ver = & vers->back();
346  if (ver->m_status != RETREIVING)
347  {
348  ver->m_impl->m_status = NdbDictionary::Object::Invalid;
349  ver->m_status = DROPPED;
350  if (ver->m_refCount == 0)
351  {
352  delete ver->m_impl;
353  vers->erase(vers->size() - 1);
354  }
355  }
356  }
357  curr = m_tableHash.getNext(curr);
358  }
359  DBUG_VOID_RETURN;
360 }
361 
362 void
363 GlobalDictCache::invalidateDb(const char * name, size_t len)
364 {
365  DBUG_ENTER("GlobalDictCache::invalidateDb");
366  NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
367  while(curr != 0)
368  {
369  Vector<TableVersion> * vers = curr->theData;
370  if (vers->size())
371  {
372  TableVersion * ver = & vers->back();
373  if (ver->m_status != RETREIVING)
374  {
375  if (ver->m_impl->matchDb(name, len))
376  {
377  ver->m_impl->m_status = NdbDictionary::Object::Invalid;
378  ver->m_status = DROPPED;
379  if (ver->m_refCount == 0)
380  {
381  delete ver->m_impl;
382  vers->erase(vers->size() - 1);
383  }
384  }
385  }
386  }
387  curr = m_tableHash.getNext(curr);
388  }
389  DBUG_VOID_RETURN;
390 }
391 
392 void
393 GlobalDictCache::release(const NdbTableImpl * tab, int invalidate)
394 {
395  DBUG_ENTER("GlobalDictCache::release");
396  DBUG_PRINT("enter", ("tab: %p internal_name: %s",
397  tab, tab->m_internalName.c_str()));
398  assert(! is_ndb_blob_table(tab));
399 
400  unsigned i;
401  const Uint32 len = (Uint32)strlen(tab->m_internalName.c_str());
402  Vector<TableVersion> * vers =
403  m_tableHash.getData(tab->m_internalName.c_str(), len);
404  if(vers == 0){
405  // Should always tried to retreive it first
406  // and thus there should be a record
407  abort();
408  }
409 
410  const Uint32 sz = vers->size();
411  if(sz == 0){
412  // Should always tried to retreive it first
413  // and thus there should be a record
414  abort();
415  }
416 
417  for(i = 0; i < sz; i++){
418  TableVersion & ver = (* vers)[i];
419  if(ver.m_impl == tab){
420  if(ver.m_refCount == 0 || ver.m_status == RETREIVING ||
421  ver.m_version != tab->m_version){
422  DBUG_PRINT("info", ("Releasing with refCount=%d status=%d impl=%p",
423  ver.m_refCount, ver.m_status, ver.m_impl));
424  break;
425  }
426 
427  ver.m_refCount--;
428  if (ver.m_impl->m_status == NdbDictionary::Object::Invalid || invalidate)
429  {
430  ver.m_impl->m_status = NdbDictionary::Object::Invalid;
431  ver.m_status = DROPPED;
432  }
433  if (ver.m_refCount == 0 && ver.m_status == DROPPED)
434  {
435  DBUG_PRINT("info", ("refCount is zero, deleting m_impl"));
436  delete ver.m_impl;
437  vers->erase(i);
438  }
439  DBUG_VOID_RETURN;
440  }
441  }
442 
443  for(i = 0; i<sz; i++){
444  TableVersion & ver = (* vers)[i];
445  ndbout_c("%d: version: %d refCount: %d status: %d impl: %p",
446  i, ver.m_version, ver.m_refCount,
447  ver.m_status, ver.m_impl);
448  }
449 
450  abort();
451 }
452 
453 void
454 GlobalDictCache::alter_table_rep(const char * name,
455  Uint32 tableId,
456  Uint32 tableVersion,
457  bool altered)
458 {
459  DBUG_ENTER("GlobalDictCache::alter_table_rep");
460  const Uint32 len = (Uint32)strlen(name);
461  Vector<TableVersion> * vers =
462  m_tableHash.getData(name, len);
463 
464  if(vers == 0)
465  {
466  DBUG_VOID_RETURN;
467  }
468 
469  assert(! is_ndb_blob_table(name));
470  const Uint32 sz = vers->size();
471  if(sz == 0)
472  {
473  DBUG_VOID_RETURN;
474  }
475 
476  for(Uint32 i = 0; i < sz; i++)
477  {
478  TableVersion & ver = (* vers)[i];
479  if(ver.m_version == tableVersion && ver.m_impl &&
480  (Uint32) ver.m_impl->m_id == tableId)
481  {
482  ver.m_status = DROPPED;
483  ver.m_impl->m_status = altered ?
485  if (ver.m_refCount == 0)
486  {
487  delete ver.m_impl;
488  vers->erase(i);
489  }
490  DBUG_VOID_RETURN;
491  }
492 
493  if(i == sz - 1 && ver.m_status == RETREIVING)
494  {
495  ver.m_impl = altered ? f_altered_table : f_invalid_table;
496  DBUG_VOID_RETURN;
497  }
498  }
499  DBUG_VOID_RETURN;
500 }
501 
502 int
503 GlobalDictCache::chg_ref_count(const NdbTableImpl * impl, int value)
504 {
505  DBUG_ENTER("GlobalDictCache::chg_ref_count");
506  const char * name = impl->m_internalName.c_str();
507  assert(! is_ndb_blob_table(name));
508 
509  const Uint32 tableId = impl->m_id;
510  const Uint32 tableVersion = impl->m_version;
511 
512  const Uint32 len = (Uint32)strlen(name);
513  Vector<TableVersion> * vers =
514  m_tableHash.getData(name, len);
515 
516  if(vers == 0)
517  {
518  DBUG_RETURN(-1);
519  }
520 
521  const Uint32 sz = vers->size();
522  if(sz == 0)
523  {
524  DBUG_RETURN(-1);
525  }
526 
527  for(Uint32 i = 0; i < sz; i++)
528  {
529  TableVersion & ver = (* vers)[i];
530  if(ver.m_impl == impl)
531  {
532  if (value == +1)
533  {
534  DBUG_PRINT("info", ("%s id=%u ver=0x%x: inc old ref count %u",
535  name, tableId, tableVersion, ver.m_refCount));
536  ver.m_refCount++;
537  }
538  else if (value == -1)
539  {
540  DBUG_PRINT("info", ("%s id=%u ver=0x%x: dec old ref count %u",
541  name, tableId, tableVersion, ver.m_refCount));
542  if (ver.m_refCount == 0)
543  abort();
544  ver.m_refCount--;
545  if (ver.m_refCount == 0)
546  {
547  delete ver.m_impl;
548  vers->erase(i);
549  }
550  }
551  else
552  abort();
553  DBUG_RETURN(0);
554  }
555  }
556  DBUG_RETURN(0);
557 }
558