1
/* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
3
* PrimeBase Media Stream for MySQL
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
* Original author: Paul McCullagh
20
* Continued development: Barry Leslie
26
* Media Stream Tables.
29
#include "cslib/CSConfig.h"
33
#include "cslib/CSGlobal.h"
34
#include "cslib/CSLog.h"
35
#include "cslib/CSStrUtil.h"
36
#include "cslib/CSPath.h"
38
#include "open_table_ms.h"
40
#include "connection_handler_ms.h"
41
#include "engine_ms.h"
42
#include "transaction_ms.h"
43
#include "parameters_ms.h"
46
* ---------------------------------------------------------------
50
MSOpenTable::MSOpenTable():
59
myWriteRepoFile(NULL),
67
memset(myOTBuffer, 0, MS_OT_BUFFER_SIZE); // wipe this to make valgrind happy.
70
MSOpenTable::~MSOpenTable()
75
void MSOpenTable::close()
79
myTableFile->release();
84
myTempLogFile->release();
98
void MSOpenTable::returnToPool()
100
MSTableList::releaseTable(this);
103
// This cleanup class is used to reset the
104
// repository size if something goes wrong.
105
class CreateBlobCleanUp : public CSRefObject {
113
CreateBlobCleanUp(): CSRefObject(),
119
repo->setRepoFileSize(ot, old_size);
124
void setCleanUp(MSOpenTable *ot_arg, MSRepository *repo_arg, uint64_t size)
139
void MSOpenTable::createBlob(PBMSBlobURLPtr bh, uint64_t blob_size, char *metadata, uint16_t metadata_size, CSInputStream *stream, CloudKeyPtr cloud_key, Md5Digest *checksum)
141
uint64_t repo_offset;
142
uint64_t blob_id = 0;
150
Md5Digest my_checksum;
151
CloudKeyRec cloud_key_rec;
152
CreateBlobCleanUp *cleanup;
155
new_(cleanup, CreateBlobCleanUp());
159
checksum = &my_checksum;
161
if (stream) push_(stream);
164
auth_code = random();
165
repo_size = myWriteRepo->getRepoFileSize();
166
temp_time = myWriteRepo->myLastTempTime;
168
// If an exception occurs the cleanup operation will be called.
169
cleanup->setCleanUp(this, myWriteRepo, repo_size);
171
head_size = myWriteRepo->getDefaultHeaderSize(metadata_size);
172
if (getDB()->myBlobType == MS_STANDARD_STORAGE) {
174
repo_offset = myWriteRepo->receiveBlob(this, head_size, blob_size, checksum, stream);
176
ASSERT(getDB()->myBlobType == MS_CLOUD_STORAGE);
177
CloudDB *cloud = getDB()->myBlobCloud;
180
CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Creating cloud BLOB without cloud.");
182
repo_offset = repo_size + head_size;
183
memset(checksum, 0, sizeof(Md5Digest)); // The checksum is only for local storage.
185
// If there is a stream then the data has not been sent to the cloud yet.
187
cloud_key = &cloud_key_rec;
188
cloud->cl_getNewKey(cloud_key);
190
cloud->cl_putData(cloud_key, stream, blob_size);
195
repo_id = myWriteRepo->myRepoID;
197
getDB()->queueForDeletion(this, MS_TL_REPO_REF, repo_id, repo_offset, auth_code, &log_id, &log_offset, &temp_time);
198
formatRepoURL(bh, repo_id, repo_offset, auth_code, blob_size);
201
blob_id = getDBTable()->createBlobHandle(this, myWriteRepo->myRepoID, repo_offset, blob_size, head_size, auth_code);
202
getDB()->queueForDeletion(this, MS_TL_BLOB_REF, getDBTable()->myTableID, blob_id, auth_code, &log_id, &log_offset, &temp_time);
203
formatBlobURL(bh, blob_id, auth_code, blob_size, 0);
206
myWriteRepo->writeBlobHead(this, repo_offset, myWriteRepo->myRepoDefRefSize, head_size, blob_size, checksum, metadata, metadata_size, blob_id, auth_code, log_id, log_offset, getDB()->myBlobType, cloud_key);
208
cleanup->cancelCleanUp();
214
// BLOBs created with this method are always created as standard local BLOBs. (No cloud storage)
215
void MSOpenTable::createBlob(PBMSBlobIDPtr blob_id, uint64_t blob_size, char *metadata, uint16_t metadata_size)
218
uint64_t repo_offset;
225
CreateBlobCleanUp *cleanup;
228
new_(cleanup, CreateBlobCleanUp());
233
auth_code = random();
235
repo_size = myWriteRepo->getRepoFileSize();
237
// If an exception occurs the cleanup operation will be called.
238
cleanup->setCleanUp(this, myWriteRepo, repo_size);
240
head_size = myWriteRepo->getDefaultHeaderSize(metadata_size);
242
repo_offset = myWriteRepo->receiveBlob(this, head_size, blob_size);
243
repo_id = myWriteRepo->myRepoID;
244
temp_time = myWriteRepo->myLastTempTime;
245
getDB()->queueForDeletion(this, MS_TL_REPO_REF, repo_id, repo_offset, auth_code, &log_id, &log_offset, &temp_time);
246
myWriteRepo->myLastTempTime = temp_time;
247
myWriteRepo->writeBlobHead(this, repo_offset, myWriteRepo->myRepoDefRefSize, head_size, blob_size, NULL, metadata, metadata_size, 0, auth_code, log_id, log_offset, MS_STANDARD_STORAGE, NULL);
248
// myWriteRepo->setRepoFileSize(this, repo_offset + head_size + blob_size);This is now set by writeBlobHead()
250
blob_id->bi_db_id = getDB()->myDatabaseID;
251
blob_id->bi_blob_id = repo_offset;
252
blob_id->bi_tab_id = repo_id;
253
blob_id->bi_auth_code = auth_code;
254
blob_id->bi_blob_size = blob_size;
255
blob_id->bi_blob_type = MS_URL_TYPE_REPO;
256
blob_id->bi_blob_ref_id = 0;
258
cleanup->cancelCleanUp();
264
void MSOpenTable::sendRepoBlob(uint64_t blob_id, uint64_t req_offset, uint64_t req_size, uint32_t auth_code, bool info_only, CSHTTPOutputStream *stream)
270
MSRepoFile *repo_file;
274
getDBTable()->readBlobHandle(this, blob_id, &auth_code, &repo_id, &offset, &size, &head_size, true);
275
repo_file = getDB()->getRepoFileFromPool(repo_id, false);
276
frompool_(repo_file);
277
//repo_file->sendBlob(this, offset, head_size, size, stream);
278
repo_file->sendBlob(this, offset, req_offset, req_size, 0, false, info_only, stream);
279
backtopool_(repo_file);
283
void MSOpenTable::freeReference(uint64_t blob_id, uint64_t blob_ref_id)
289
MSRepoFile *repo_file;
290
uint32_t auth_code = 0;
295
getDBTable()->readBlobHandle(this, blob_id, &auth_code, &repo_id, &offset, &blob_size, &head_size, true);
296
repo_file = getDB()->getRepoFileFromPool(repo_id, false);
298
frompool_(repo_file);
299
repo_file->releaseBlob(this, offset, head_size, getDBTable()->myTableID, blob_id, blob_ref_id, auth_code);
300
backtopool_(repo_file);
305
void MSOpenTable::commitReference(uint64_t blob_id, uint64_t blob_ref_id)
311
MSRepoFile *repo_file;
312
uint32_t auth_code = 0;
317
getDBTable()->readBlobHandle(this, blob_id, &auth_code, &repo_id, &offset, &blob_size, &head_size, true);
318
repo_file = getDB()->getRepoFileFromPool(repo_id, false);
320
frompool_(repo_file);
321
repo_file->commitBlob(this, offset, head_size, getDBTable()->myTableID, blob_id, blob_ref_id, auth_code);
322
backtopool_(repo_file);
327
void MSOpenTable::useBlob(int type, uint32_t db_id, uint32_t tab_id, uint64_t blob_id, uint32_t auth_code, uint16_t col_index, uint64_t blob_size, uint64_t blob_ref_id, PBMSBlobURLPtr ret_blob_url)
329
MSRepoFile *repo_file= NULL;
331
CSInputStream *stream;
335
uint64_t repo_offset;
343
if (!blob_db->isRecovering()) {
344
// During recovery the only thing that needs to be done is to
345
// reset the database ID which is done when the URL is created.
346
// Create the URL using the table ID passed in not the one from
347
// the table associated with this object.
350
if (type == MS_URL_TYPE_REPO) { // There is no table reference associated with this BLOB yet.
355
if (blob_db->myDatabaseID == db_id)
356
repo_file = blob_db->getRepoFileFromPool(tab_id, false);
359
blob_db = MSDatabase::getDatabase(db_id);
361
repo_file = blob_db->getRepoFileFromPool(tab_id, false);
363
blob_db = repo_file->myRepo->myRepoDatabase;
366
frompool_(repo_file);
367
repo_file->read(&blob, blob_id, MS_MIN_BLOB_HEAD_SIZE, MS_MIN_BLOB_HEAD_SIZE);
369
repo_offset = blob_id;
370
blob_size = CS_GET_DISK_6(blob.rb_blob_data_size_6);
371
head_size = CS_GET_DISK_2(blob.rb_head_size_2);
373
ac = CS_GET_DISK_4(blob.rb_auth_code_4);
375
CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
376
status = CS_GET_DISK_1(blob.rb_status_1);
377
if ( ! IN_USE_BLOB_STATUS(status))
378
CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been deleted");
381
// Create a table reference to the BLOB:
383
blob_id = getDBTable()->createBlobHandle(this, tab_id, blob_id, blob_size, head_size, auth_code);
384
state = MS_UB_NEW_HANDLE;
388
getDB()->openWriteRepo(this);
390
// If either databases are using cloud storage then this is
391
// not supported yet.
392
if (getDB()->myBlobCloud || myWriteRepo->myRepoDatabase->myBlobCloud)
393
CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Copying cloud BLOB between databases is not supported.");
395
stream = repo_file->getInputStream(repo_offset);
397
repo_offset = myWriteRepo->copyBlob(this, head_size + blob_size, stream);
400
// Create a table reference to the BLOB:
401
repo_id = myWriteRepo->myRepoID;
402
blob_id = getDBTable()->createBlobHandle(this, myWriteRepo->myRepoID, repo_offset, blob_size, head_size, auth_code);
403
state = MS_UB_NEW_BLOB;
405
backtopool_(repo_file);
409
if (blob_db->myDatabaseID == db_id && getDBTable()->myTableID == tab_id) {
410
getDBTable()->readBlobHandle(this, blob_id, &auth_code, &repo_id, &repo_offset, &blob_size, &head_size, true);
412
state = MS_UB_SAME_TAB;
415
MSOpenTable *blob_otab;
417
blob_otab = MSTableList::getOpenTableByID(db_id, tab_id);
418
frompool_(blob_otab);
419
blob_otab->getDBTable()->readBlobHandle(blob_otab, blob_id, &auth_code, &repo_id, &repo_offset, &blob_size, &head_size, true);
420
if (blob_db->myDatabaseID == db_id) {
421
blob_id = getDBTable()->findBlobHandle(this, repo_id, repo_offset, blob_size, head_size, auth_code);
423
blob_id = getDBTable()->createBlobHandle(this, repo_id, repo_offset, blob_size, head_size, auth_code);
424
state = MS_UB_NEW_HANDLE;
428
// If either databases are using cloud storage then this is
429
// not supported yet.
430
if (blob_db->myBlobCloud || myWriteRepo->myRepoDatabase->myBlobCloud)
431
CSException::throwException(CS_CONTEXT, CS_ERR_GENERIC_ERROR, "Copying cloud BLOB between databases is not supported.");
433
// NOTE: For each BLOB reference copied from one database to another a new
434
// BLOB will be created. This can result in multiple copies fo the same BLOB
435
// in the destination database. One way around this would be to redisign things
436
// so that there is one BLOB repository shared across all databases.
437
blob_db->openWriteRepo(this);
439
stream = repo_file->getInputStream(repo_offset);
442
repo_offset = myWriteRepo->copyBlob(this, head_size + blob_size, stream);
446
repo_id = myWriteRepo->myRepoID;
447
blob_id = getDBTable()->createBlobHandle(this, myWriteRepo->myRepoID, repo_offset, blob_size, head_size, auth_code);
448
state = MS_UB_NEW_BLOB;
450
backtopool_(blob_otab);
455
blob_ref_id = blob_db->newBlobRefId();
457
// Always use the table ID of this table because regardless of
458
// where the BLOB ref came from it is being inserted into this table.
459
tab_id = getDBTable()->myTableID;
461
// Add the BLOB reference to the repository.
462
repo_file = blob_db->getRepoFileFromPool(repo_id, false);
463
frompool_(repo_file);
464
repo_file->referenceBlob(this, repo_offset, head_size, tab_id, blob_id, blob_ref_id, auth_code, col_index);
465
backtopool_(repo_file);
467
MSTransactionManager::referenceBLOB(getDB()->myDatabaseID, tab_id, blob_id, blob_ref_id);
471
formatBlobURL(ret_blob_url, blob_id, auth_code, blob_size, tab_id, blob_ref_id);
476
void MSOpenTable::releaseReference(uint64_t blob_id, uint64_t blob_ref_id)
480
MSTransactionManager::dereferenceBLOB(getDB()->myDatabaseID, getDBTable()->myTableID, blob_id, blob_ref_id);
485
void MSOpenTable::checkBlob(CSStringBuffer *buffer, uint64_t blob_id, uint32_t auth_code, uint32_t temp_log_id, uint32_t temp_log_offset)
491
MSRepoFile *repo_file;
495
if (getDBTable()->readBlobHandle(this, blob_id, &auth_code, &repo_id, &offset, &size, &head_size, false)) {
496
if ((repo_file = getDB()->getRepoFileFromPool(repo_id, true))) {
497
frompool_(repo_file);
498
repo_file->checkBlob(buffer, offset, auth_code, temp_log_id, temp_log_offset);
499
backtopool_(repo_file);
502
getDBTable()->freeBlobHandle(this, blob_id, repo_id, offset, auth_code);
507
bool MSOpenTable::deleteReferences(uint32_t temp_log_id, uint32_t temp_log_offset, bool *must_quit)
509
MSTableHeadRec tab_head;
511
MSTableBlobRec tab_blob;
513
uint64_t repo_offset;
516
MSRepoFile *repo_file = NULL;
521
if (myTableFile->read(&tab_head, 0, offsetof(MSTableHeadRec, th_reserved_4), 0) < offsetof(MSTableHeadRec, th_reserved_4))
522
/* Nothing to read, delete it ... */
524
if (CS_GET_DISK_4(tab_head.th_temp_log_id_4) != temp_log_id ||
525
CS_GET_DISK_4(tab_head.th_temp_log_offset_4) != temp_log_offset) {
526
/* Wrong delete reference (ignore): */
531
blob_id = CS_GET_DISK_2(tab_head.th_head_size_2);
532
while (blob_id + sizeof(MSTableBlobRec) <= getDBTable()->getTableFileSize()) {
534
/* Bit of a waste of work, but we must quit! */
538
if (myTableFile->read(&tab_blob, blob_id, sizeof(MSTableBlobRec), 0) < sizeof(MSTableBlobRec))
540
repo_id = CS_GET_DISK_3(tab_blob.tb_repo_id_3);
541
repo_offset = CS_GET_DISK_6(tab_blob.tb_offset_6);
542
head_size = CS_GET_DISK_2(tab_blob.tb_header_size_2);
543
auth_code = CS_GET_DISK_4(tab_blob.tb_auth_code_4);
544
if (repo_file && repo_file->myRepo->myRepoID != repo_id) {
545
backtopool_(repo_file);
549
repo_file = getDB()->getRepoFileFromPool(repo_id, true);
551
frompool_(repo_file);
554
repo_file->freeTableReference(this, repo_offset, head_size, getDBTable()->myTableID, blob_id, auth_code);
556
blob_id += sizeof(MSTableBlobRec);
560
backtopool_(repo_file);
566
void MSOpenTable::openForReading()
568
if (!myTableFile && !isNotATable)
569
myTableFile = getDBTable()->openTableFile();
572
void MSOpenTable::openForWriting()
574
if (myTableFile && myWriteRepo && myWriteRepoFile)
578
if (!myWriteRepo || !myWriteRepoFile)
579
getDB()->openWriteRepo(this);
583
void MSOpenTable::closeForWriting()
585
if (myWriteRepoFile) {
586
myWriteRepoFile->myRepo->syncHead(myWriteRepoFile);
587
myWriteRepoFile->release();
588
myWriteRepoFile = NULL;
591
myWriteRepo->unlockRepo(REPO_WRITE);
592
#ifndef MS_COMPACTOR_POLLS
593
if (myWriteRepo->getGarbageLevel() >= PBMSParameters::getGarbageThreshold()) {
594
if (myWriteRepo->myRepoDatabase->myCompactorThread)
595
myWriteRepo->myRepoDatabase->myCompactorThread->wakeup();
598
myWriteRepo->release();
603
uint32_t MSOpenTable::getTableID()
605
return myPool->myPoolTable->myTableID;
608
MSTable *MSOpenTable::getDBTable()
610
return myPool->myPoolTable;
613
MSDatabase *MSOpenTable::getDB()
615
return myPool->myPoolDB;
618
void MSOpenTable::formatBlobURL(PBMSBlobURLPtr blob_url, uint64_t blob_id, uint32_t auth_code, uint64_t blob_size, uint32_t tab_id, uint64_t blob_ref_id)
622
blob.bu_type = MS_URL_TYPE_BLOB;
623
blob.bu_db_id = getDB()->myDatabaseID;
624
blob.bu_tab_id = tab_id;
625
blob.bu_blob_id = blob_id;
626
blob.bu_auth_code = auth_code;
627
blob.bu_server_id = PBMSParameters::getServerID();
628
blob.bu_blob_size = blob_size;
629
blob.bu_blob_ref_id = blob_ref_id;
631
PBMSBlobURLTools::buildBlobURL(&blob, blob_url);
634
void MSOpenTable::formatBlobURL(PBMSBlobURLPtr blob_url, uint64_t blob_id, uint32_t auth_code, uint64_t blob_size, uint64_t blob_ref_id)
636
formatBlobURL(blob_url, blob_id, auth_code, blob_size, getDBTable()->myTableID, blob_ref_id);
638
void MSOpenTable::formatRepoURL(PBMSBlobURLPtr blob_url, uint32_t log_id, uint64_t log_offset, uint32_t auth_code, uint64_t blob_size)
642
blob.bu_type = MS_URL_TYPE_REPO;
643
blob.bu_db_id = getDB()->myDatabaseID;
644
blob.bu_tab_id = log_id;
645
blob.bu_blob_id = log_offset;
646
blob.bu_auth_code = auth_code;
647
blob.bu_server_id = PBMSParameters::getServerID();
648
blob.bu_blob_size = blob_size;
649
blob.bu_blob_ref_id = 0;
651
PBMSBlobURLTools::buildBlobURL(&blob, blob_url);
654
MSOpenTable *MSOpenTable::newOpenTable(MSOpenTablePool *pool)
658
if (!(otab = new MSOpenTable()))
659
CSException::throwOSError(CS_CONTEXT, ENOMEM);
660
if ((otab->myPool = pool))
661
otab->isNotATable = pool->myPoolTable == NULL;
663
otab->isNotATable = false;
669
* ---------------------------------------------------------------
673
MSOpenTablePool::MSOpenTablePool():
682
MSOpenTablePool::~MSOpenTablePool()
685
removeOpenTablesNotInUse();
686
/* With this, I also delete those that are in use!: */
689
myPoolTable->release();
695
void MSOpenTablePool::check()
697
MSOpenTable *otab, *ptab;
699
if ((otab = (MSOpenTable *) iPoolTables.getBack())) {
709
ptab = ptab->nextTable;
717
otab = (MSOpenTable *) otab->getNextLink();
726
* This returns the table referenced. So it is safe from the pool being
729
MSOpenTable *MSOpenTablePool::getPoolTable()
733
if ((otab = iTablePool)) {
734
iTablePool = otab->nextTable;
735
otab->nextTable = NULL;
736
ASSERT(!otab->inUse);
743
void MSOpenTablePool::returnOpenTable(MSOpenTable *otab)
746
otab->nextTable = iTablePool;
751
* Add a table to the pool, but do not release it!
753
void MSOpenTablePool::addOpenTable(MSOpenTable *otab)
755
iPoolTables.addFront(otab);
758
void MSOpenTablePool::removeOpenTable(MSOpenTable *otab)
761
iPoolTables.remove(otab);
764
void MSOpenTablePool::removeOpenTablesNotInUse()
766
MSOpenTable *otab, *curr_otab;
769
/* Remove all tables that are not in use: */
770
if ((otab = (MSOpenTable *) iPoolTables.getBack())) {
773
otab = (MSOpenTable *) otab->getNextLink();
774
if (!curr_otab->inUse)
775
iPoolTables.remove(curr_otab);
780
void MSOpenTablePool::returnToPool()
782
MSTableList::removeTablePool(this);
785
MSOpenTablePool *MSOpenTablePool::newPool(uint32_t db_id, uint32_t tab_id)
787
MSOpenTablePool *pool;
790
if (!(pool = new MSOpenTablePool())) {
791
CSException::throwOSError(CS_CONTEXT, ENOMEM);
794
pool->myPoolDB = MSDatabase::getDatabase(db_id);
795
pool->myPoolTableID = tab_id;
797
pool->myPoolTable = pool->myPoolDB->getTable(tab_id, false);
803
* ---------------------------------------------------------------
807
CSSyncOrderedList *MSTableList::gPoolListByID;
809
MSTableList::MSTableList()
813
MSTableList::~MSTableList()
817
void MSTableList::startUp()
819
new_(gPoolListByID, CSSyncOrderedList);
822
void MSTableList::shutDown()
825
gPoolListByID->clear();
826
gPoolListByID->release();
827
gPoolListByID = NULL;
831
class MSTableKey : public CSOrderKey {
833
uint32_t myKeyDatabaseID;
834
uint32_t myKeyTableID;
836
MSTableKey(): myKeyDatabaseID(0), myKeyTableID(0){ }
838
virtual ~MSTableKey() {
841
int compareKey(CSObject *key) {return CSObject::compareKey(key);}
842
virtual int compareKey(CSOrderKey *x) {
843
MSTableKey *key = (MSTableKey *) x;
846
if (myKeyDatabaseID < key->myKeyDatabaseID)
848
else if (myKeyDatabaseID > key->myKeyDatabaseID)
852
if (myKeyTableID < key->myKeyTableID)
854
else if (myKeyTableID > key->myKeyTableID)
861
static MSTableKey *newTableKey(uint32_t db_id, uint32_t tab_id)
865
if (!(key = new MSTableKey())) {
866
CSException::throwOSError(CS_CONTEXT, ENOMEM);
868
key->myKeyDatabaseID = db_id;
869
key->myKeyTableID = tab_id;
874
MSOpenTable *MSTableList::getOpenTableByID(uint32_t db_id, uint32_t tab_id)
876
MSOpenTablePool *pool;
877
MSOpenTable *otab = NULL;
881
lock_(gPoolListByID);
882
key.myKeyDatabaseID = db_id;
883
key.myKeyTableID = tab_id;
884
pool = (MSOpenTablePool *) gPoolListByID->find(&key);
887
pool = MSOpenTablePool::newPool(db_id, tab_id);
888
key_ptr = MSTableKey::newTableKey(db_id, tab_id);
889
gPoolListByID->add(key_ptr, pool);
891
if (!(otab = pool->getPoolTable())) {
892
otab = MSOpenTable::newOpenTable(pool);
893
pool->addOpenTable(otab);
896
unlock_(gPoolListByID);
900
MSOpenTable *MSTableList::getOpenTableForDB(uint32_t db_id)
902
return(MSTableList::getOpenTableByID(db_id, 0));
906
void MSTableList::releaseTable(MSOpenTable *otab)
908
MSOpenTablePool *pool;
911
lock_(gPoolListByID);
913
if ((pool = otab->myPool)) {
914
if (pool->isRemovingTP) {
915
pool->removeOpenTable(otab);
916
gPoolListByID->wakeup();
919
pool->returnOpenTable(otab);
922
unlock_(gPoolListByID);
926
bool MSTableList::removeTablePoolIfEmpty(MSOpenTablePool *pool)
929
if (pool->getSize() == 0) {
932
key.myKeyDatabaseID = pool->myPoolDB->myDatabaseID;
933
key.myKeyTableID = pool->myPoolTableID;
934
gPoolListByID->remove(&key);
935
/* TODO: Remove the table from the database, if it does not exist
943
void MSTableList::removeTablePool(MSOpenTablePool *pool)
946
lock_(gPoolListByID);
948
pool->isRemovingTP = true;
949
pool->removeOpenTablesNotInUse();
950
if (removeTablePoolIfEmpty(pool))
954
* Wait for the tables that are in use to be
957
gPoolListByID->wait();
959
unlock_(gPoolListByID);
964
* Close the pool associated with this open table.
966
void MSTableList::removeTablePool(MSOpenTable *otab)
968
MSOpenTablePool *pool;
971
key.myKeyDatabaseID = otab->getDB()->myDatabaseID;
972
key.myKeyTableID = otab->getTableID();
976
lock_(gPoolListByID);
978
if (!(pool = (MSOpenTablePool *) gPoolListByID->find(&key)))
980
pool->isRemovingTP = true;
981
pool->removeOpenTablesNotInUse();
982
if (removeTablePoolIfEmpty(pool))
985
* Wait for the tables that are in use to be
988
gPoolListByID->wait();
990
unlock_(gPoolListByID);
995
void MSTableList::removeDatabaseTables(MSDatabase *database)
997
MSOpenTablePool *pool;
1005
lock_(gPoolListByID);
1007
while ((pool = (MSOpenTablePool *) gPoolListByID->itemAt(idx))) {
1008
if (pool->myPoolDB == database) {
1013
unlock_(gPoolListByID);
1016
removeTablePool(pool);
1024
// lockTablePoolForDeletion() is only called to lock a pool for a table which is about to be removed.
1025
// When the pool is returned then it will be removed from the global pool list.
1026
MSOpenTablePool *MSTableList::lockTablePoolForDeletion(uint32_t db_id, uint32_t tab_id, CSString *db_name, CSString *tab_name)
1028
MSOpenTablePool *pool;
1037
key.myKeyDatabaseID = db_id;
1038
key.myKeyTableID = tab_id;
1040
lock_(gPoolListByID);
1043
if (!(pool = (MSOpenTablePool *) gPoolListByID->find(&key))) {
1044
char buffer[CS_EXC_MESSAGE_SIZE];
1046
cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Table is temporarily not available: ");
1047
cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, db_name->getCString());
1049
cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, ".");
1050
cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, tab_name->getCString());
1052
CSException::throwException(CS_CONTEXT, MS_ERR_TABLE_LOCKED, buffer);
1054
pool->isRemovingTP = true;
1055
pool->removeOpenTablesNotInUse();
1056
if (pool->getSize() == 0) {
1057
// pool->retain(); Do not do this. The return to pool will free this by removing it from the list.
1061
* Wait for the tables that are in use to be
1064
gPoolListByID->wait();
1066
unlock_(gPoolListByID);
1075
MSOpenTablePool *MSTableList::lockTablePoolForDeletion(MSTable *tab)
1077
CSString *tab_name = NULL, *db_name;
1078
uint32_t db_id, tab_id;
1082
db_name = tab->myDatabase->myDatabaseName;
1085
tab_name = tab->myTableName;
1088
db_id = tab->myDatabase->myDatabaseID;
1089
tab_id = tab->myTableID;
1093
return_( lockTablePoolForDeletion(db_id, tab_id, db_name, tab_name));
1096
MSOpenTablePool *MSTableList::lockTablePoolForDeletion(MSOpenTable *otab)
1098
CSString *tab_name = NULL, *db_name;
1099
uint32_t db_id, tab_id;
1104
tab = otab->getDBTable();
1106
tab_name = tab->myTableName;
1110
db_name = otab->getDB()->myDatabaseName;
1113
db_id = otab->getDB()->myDatabaseID;
1114
tab_id = otab->getTableID();
1116
otab->returnToPool();
1118
return_( lockTablePoolForDeletion(db_id, tab_id, db_name, tab_name));