DictCache.cpp 10.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

17
#include <ndb_global.h>
18 19 20 21 22 23
#include "DictCache.hpp"
#include "NdbDictionaryImpl.hpp"
#include <NdbTick.h>
#include <NdbCondition.h>
#include <NdbSleep.h>

24 25 26
static NdbTableImpl f_invalid_table;
static NdbTableImpl f_altered_table;

27 28 29
Ndb_local_table_info *
Ndb_local_table_info::create(NdbTableImpl *table_impl, Uint32 sz)
{
30 31
  Uint32 tot_size= sizeof(Ndb_local_table_info) - sizeof(Uint64)
    + ((sz+7) & ~7); // round to Uint64
32
  void *data= malloc(tot_size);
33 34
  if (data == 0)
    return 0;
35
  memset(data, 0, tot_size);
36 37 38 39 40 41 42 43 44 45
  new (data) Ndb_local_table_info(table_impl);
  return (Ndb_local_table_info *) data;
}

void Ndb_local_table_info::destroy(Ndb_local_table_info *info)
{
  free((void *)info);
}

Ndb_local_table_info::Ndb_local_table_info(NdbTableImpl *table_impl)
46 47 48 49 50 51 52 53
{
  m_table_impl= table_impl;
}

Ndb_local_table_info::~Ndb_local_table_info()
{
}

54 55 56 57 58 59 60 61
LocalDictCache::LocalDictCache(){
  m_tableHash.createHashTable();
}

LocalDictCache::~LocalDictCache(){
  m_tableHash.releaseHashTable();
}

62
Ndb_local_table_info * 
63 64 65 66 67 68
LocalDictCache::get(const char * name){
  const Uint32 len = strlen(name);
  return m_tableHash.getData(name, len);
}

void 
69
LocalDictCache::put(const char * name, Ndb_local_table_info * tab_info){
70
  const Uint32 id = tab_info->m_table_impl->m_id;
71
  m_tableHash.insertKey(name, strlen(name), id, tab_info);
72 73 74 75
}

void
LocalDictCache::drop(const char * name){
76 77
  Ndb_local_table_info *info= m_tableHash.deleteKey(name, strlen(name));
  DBUG_ASSERT(info != 0);
78
  Ndb_local_table_info::destroy(info);
79 80 81 82 83 84
}

/*****************************************************************
 * Global cache
 */
GlobalDictCache::GlobalDictCache(){
85
  DBUG_ENTER("GlobalDictCache::GlobalDictCache");
86 87
  m_tableHash.createHashTable();
  m_waitForTableCondition = NdbCondition_Create();
88
  DBUG_VOID_RETURN;
89 90 91
}

GlobalDictCache::~GlobalDictCache(){
92
  DBUG_ENTER("GlobalDictCache::~GlobalDictCache");
93 94 95 96 97 98 99 100 101
  NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
  while(curr != 0){
    Vector<TableVersion> * vers = curr->theData;
    const unsigned sz = vers->size();
    for(unsigned i = 0; i<sz ; i++){
      if((* vers)[i].m_impl != 0)
	delete (* vers)[i].m_impl;
    }
    delete curr->theData;
102
    curr->theData= NULL;
103 104 105 106
    curr = m_tableHash.getNext(curr);
  }
  m_tableHash.releaseHashTable();
  NdbCondition_Destroy(m_waitForTableCondition);
107
  DBUG_VOID_RETURN;
108 109
}

110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
void GlobalDictCache::printCache()
{
  DBUG_ENTER("GlobalDictCache::printCache");
  NdbElement_t<Vector<TableVersion> > * curr = m_tableHash.getNext(0);
  while(curr != 0){
    DBUG_PRINT("curr", ("len: %d, hash: %d, lk: %d, str: %s",
                        curr->len, curr->hash, curr->localkey1, curr->str));
    if (curr->theData){
      Vector<TableVersion> * vers = curr->theData;
      const unsigned sz = vers->size();
      for(unsigned i = 0; i<sz ; i++){
        TableVersion tv= (*vers)[i];
        DBUG_PRINT("  ", ("vers[%d]: ver: %d, refCount: %d, status: %d",
                          sz, tv.m_version, tv.m_refCount, tv.m_status));
        if(tv.m_impl != 0)
        {
          DBUG_PRINT("  ", ("m_impl: internalname: %s",
                            tv.m_impl->m_internalName.c_str()));
        }
      }
    }
    else
    {
      DBUG_PRINT("  ", ("NULL"));
    }
    curr = m_tableHash.getNext(curr);
  }
  DBUG_VOID_RETURN;
}
139

140
NdbTableImpl *
141 142
GlobalDictCache::get(const char * name)
{
143 144 145
  DBUG_ENTER("GlobalDictCache::get");
  DBUG_PRINT("enter", ("name: %s", name));

146
  const Uint32 len = strlen(name);
147
  Vector<TableVersion> * versions = 0;
148 149 150 151 152 153 154 155 156 157 158 159 160 161
  versions = m_tableHash.getData(name, len);
  if(versions == 0){
    versions = new Vector<TableVersion>(2);
    m_tableHash.insertKey(name, len, 0, versions);
  }

  int waitTime = 100;

  bool retreive = false;
  while(versions->size() > 0 && !retreive){
    TableVersion * ver = & versions->back();
    switch(ver->m_status){
    case OK:
      ver->m_refCount++;
162 163 164 165
      DBUG_PRINT("info", ("Table OK version=%x.%x refCount=%u",
                           ver->m_impl->m_version & 0xFFFFFF,
                           ver->m_impl->m_version >> 24,
                           ver->m_refCount));
166
      DBUG_RETURN(ver->m_impl);
167 168 169 170
    case DROPPED:
      retreive = true; // Break loop
      break;
    case RETREIVING:
171
      DBUG_PRINT("info", ("Wait for retrieving thread"));
172 173 174 175 176 177 178 179 180 181 182 183 184 185
      NdbCondition_WaitTimeout(m_waitForTableCondition, m_mutex, waitTime);
      continue;
    }
  }
  
  /**
   * Create new...
   */
  TableVersion tmp;
  tmp.m_version = 0;
  tmp.m_impl = 0;
  tmp.m_status = RETREIVING;
  tmp.m_refCount = 1; // The one retreiving it
  versions->push_back(tmp);
186
  DBUG_PRINT("info", ("No table found"));
187
  DBUG_RETURN(0);
188 189 190 191 192
}

NdbTableImpl *
GlobalDictCache::put(const char * name, NdbTableImpl * tab)
{
193
  DBUG_ENTER("GlobalDictCache::put");
194 195 196 197 198
  DBUG_PRINT("enter", ("name: %s, internal_name: %s version: %x.%x",
                       name,
                       tab ? tab->m_internalName.c_str() : "tab NULL",
                       tab ? tab->m_version & 0xFFFFFF : 0,
                       tab ? tab->m_version >> 24 : 0));
199

200 201 202 203
  const Uint32 len = strlen(name);
  Vector<TableVersion> * vers = m_tableHash.getData(name, len);
  if(vers == 0){
    // Should always tried to retreive it first 
204
    // and thus there should be a record
205 206 207 208 209 210
    abort(); 
  }

  const Uint32 sz = vers->size();
  if(sz == 0){
    // Should always tried to retreive it first 
211
    // and thus there should be a record
212 213 214 215 216
    abort(); 
  }
  
  TableVersion & ver = vers->back();
  if(ver.m_status != RETREIVING || 
217 218
     !(ver.m_impl == 0 || 
       ver.m_impl == &f_invalid_table || ver.m_impl == &f_altered_table) || 
219 220 221 222 223
     ver.m_version != 0 || 
     ver.m_refCount == 0){
    abort();
  }
  
224 225
  if(tab == 0)
  {
226
    DBUG_PRINT("info", ("No table found in db"));
227
    vers->erase(sz - 1);
228 229
  } 
  else if (ver.m_impl == 0) {
230
    DBUG_PRINT("info", ("Table OK"));
231 232 233
    ver.m_impl = tab;
    ver.m_version = tab->m_version;
    ver.m_status = OK;
234 235 236
  } 
  else if (ver.m_impl == &f_invalid_table) 
  {
237
    DBUG_PRINT("info", ("Table DROPPED invalid"));
238 239 240 241 242 243 244
    ver.m_impl = tab;
    ver.m_version = tab->m_version;
    ver.m_status = DROPPED;
    ver.m_impl->m_status = NdbDictionary::Object::Invalid;    
  }
  else if(ver.m_impl == &f_altered_table)
  {
245
    DBUG_PRINT("info", ("Table DROPPED altered"));
246 247 248 249 250 251 252 253
    ver.m_impl = tab;
    ver.m_version = tab->m_version;
    ver.m_status = DROPPED;
    ver.m_impl->m_status = NdbDictionary::Object::Altered;    
  }
  else
  {
    abort();
254 255
  }
  NdbCondition_Broadcast(m_waitForTableCondition);
256
  DBUG_RETURN(tab);
257 258 259 260 261
} 

void
GlobalDictCache::drop(NdbTableImpl * tab)
{
262 263 264
  DBUG_ENTER("GlobalDictCache::drop");
  DBUG_PRINT("enter", ("internal_name: %s", tab->m_internalName.c_str()));

265
  unsigned i;
266 267 268 269 270
  const Uint32 len = strlen(tab->m_internalName.c_str());
  Vector<TableVersion> * vers = 
    m_tableHash.getData(tab->m_internalName.c_str(), len);
  if(vers == 0){
    // Should always tried to retreive it first 
271
    // and thus there should be a record
272 273 274 275 276 277
    abort(); 
  }

  const Uint32 sz = vers->size();
  if(sz == 0){
    // Should always tried to retreive it first 
278
    // and thus there should be a record
279 280
    abort(); 
  }
281

282
  for(i = 0; i < sz; i++){
283 284
    TableVersion & ver = (* vers)[i];
    if(ver.m_impl == tab){
285
      if(ver.m_refCount == 0 || ver.m_status == RETREIVING ||
286
	 ver.m_version != tab->m_version){
287 288
	DBUG_PRINT("info", ("Dropping with refCount=%d status=%d impl=%p",
                            ver.m_refCount, ver.m_status, ver.m_impl));
289 290
	break;
      }
291 292
      DBUG_PRINT("info", ("Found table to drop, i: %d, name: %s",
                          i, ver.m_impl->m_internalName.c_str()));
293 294 295
      ver.m_refCount--;
      ver.m_status = DROPPED;
      if(ver.m_refCount == 0){
serg@serg.mylan's avatar
serg@serg.mylan committed
296
        DBUG_PRINT("info", ("refCount is zero, deleting m_impl"));
297 298 299
	delete ver.m_impl;
	vers->erase(i);
      }
300
      DBUG_VOID_RETURN;
301 302
    }
  }
303

304
  for(i = 0; i<sz; i++){
305
    TableVersion & ver = (* vers)[i];
306 307 308
    ndbout_c("%d: version: %d refCount: %d status: %d impl: %p",
	     i, ver.m_version, ver.m_refCount,
	     ver.m_status, ver.m_impl);
309 310 311 312 313 314
  }
  
  abort();
}

void
315 316 317 318 319
GlobalDictCache::release(NdbTableImpl * tab)
{
  DBUG_ENTER("GlobalDictCache::release");
  DBUG_PRINT("enter", ("internal_name: %s", tab->m_internalName.c_str()));

320
  unsigned i;
321 322 323 324 325
  const Uint32 len = strlen(tab->m_internalName.c_str());
  Vector<TableVersion> * vers = 
    m_tableHash.getData(tab->m_internalName.c_str(), len);
  if(vers == 0){
    // Should always tried to retreive it first 
326
    // and thus there should be a record
327 328 329 330 331 332
    abort(); 
  }

  const Uint32 sz = vers->size();
  if(sz == 0){
    // Should always tried to retreive it first 
333
    // and thus there should be a record
334 335 336
    abort(); 
  }
  
337
  for(i = 0; i < sz; i++){
338 339 340 341
    TableVersion & ver = (* vers)[i];
    if(ver.m_impl == tab){
      if(ver.m_refCount == 0 || ver.m_status == RETREIVING || 
	 ver.m_version != tab->m_version){
342 343
	DBUG_PRINT("info", ("Releasing with refCount=%d status=%d impl=%p",
                            ver.m_refCount, ver.m_status, ver.m_impl));
344 345 346 347
	break;
      }
      
      ver.m_refCount--;
348
      DBUG_VOID_RETURN;
349 350 351
    }
  }
  
352
  for(i = 0; i<sz; i++){
353
    TableVersion & ver = (* vers)[i];
354 355 356
    ndbout_c("%d: version: %d refCount: %d status: %d impl: %p",
	     i, ver.m_version, ver.m_refCount,
	     ver.m_status, ver.m_impl);
357 358 359 360 361
  }
  
  abort();
}

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
void
GlobalDictCache::alter_table_rep(const char * name, 
				 Uint32 tableId, 
				 Uint32 tableVersion,
				 bool altered)
{
  const Uint32 len = strlen(name);
  Vector<TableVersion> * vers = 
    m_tableHash.getData(name, len);
  
  if(vers == 0)
  {
    return;
  }

  const Uint32 sz = vers->size();
  if(sz == 0)
  {
    return;
  }
  
  for(Uint32 i = 0; i < sz; i++)
  {
    TableVersion & ver = (* vers)[i];
    if(ver.m_version == tableVersion && ver.m_impl && 
387
       ver.m_impl->m_id == tableId)
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
    {
      ver.m_status = DROPPED;
      ver.m_impl->m_status = altered ? 
	NdbDictionary::Object::Altered : NdbDictionary::Object::Invalid;
      return;
    }

    if(i == sz - 1 && ver.m_status == RETREIVING)
    {
      ver.m_impl = altered ? &f_altered_table : &f_invalid_table;
      return;
    } 
  }
}

403
template class Vector<GlobalDictCache::TableVersion>;