00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef DRIZZLED
00025 #include <config.h>
00026 #include <drizzled/common.h>
00027 #include <drizzled/session.h>
00028 #include <drizzled/field/blob.h>
00029 #endif
00030
00031 #include "cslib/CSConfig.h"
00032 #include <inttypes.h>
00033
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <stdlib.h>
00037 #include <time.h>
00038
00039
00040 #include "cslib/CSGlobal.h"
00041 #include "cslib/CSStrUtil.h"
00042 #include "cslib/CSLog.h"
00043
00044 #include "ha_pbms.h"
00045
00046
00047 #include "mysql_ms.h"
00048 #include "repository_ms.h"
00049 #include "database_ms.h"
00050 #include "compactor_ms.h"
00051 #include "open_table_ms.h"
00052 #include "discover_ms.h"
00053
00054
00055
00056 #include "systab_variable_ms.h"
00057
00058 #define MS_REPOSITORY_STORAGE_TYPE "REPOSITORY"
00059 #define MS_CLOUD_STORAGE_TYPE "CLOUD"
00060
00061 DT_FIELD_INFO pbms_variable_info[]=
00062 {
00063 {"Id", NOVAL, NULL, MYSQL_TYPE_LONG, NULL, NOT_NULL_FLAG, "The variable ID"},
00064 {"Name", 32, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "PBMS variable name"},
00065 {"Value", 1024, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, 0, "PBMS variable value."},
00066 {"Description", 124, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "PBMS variable description."},
00067 {NULL,NOVAL, NULL, MYSQL_TYPE_STRING,NULL, 0, NULL}
00068 };
00069
00070 DT_KEY_INFO pbms_variable_keys[]=
00071 {
00072 {"pbms_variable_pk", PRI_KEY_FLAG, {"Id", NULL}},
00073 {NULL, 0, {NULL}}
00074 };
00075
00076 typedef const char *(*PBMSVarGetFunc)(MSDatabase *db, const char *dflt_value);
00077 typedef const char *(*PBMSVarCheckFunc)(char *value, bool *ok);
00078 typedef void (*PBMSVarActionFunc)(MSDatabase *db, const char *value);
00079
00080 typedef struct {
00081 bool hidden;
00082 const char *name;
00083 const char *value;
00084 const char *info;
00085 bool save;
00086 PBMSVarGetFunc get;
00087 PBMSVarCheckFunc check;
00088 PBMSVarActionFunc action;
00089 } PBMSVariableRec, *PBMSVariablePtr;
00090
00091 CSLock MSVariableTable::gVarLock;
00092
00093
00094 static char *cleanupVariable(char *value, int *len)
00095 {
00096 char *ptr;
00097
00098 while (*value && isspace(*value)) value++;
00099 ptr = value + strlen(value) -1;
00100 while ((ptr > value) && isspace(*ptr)) ptr--;
00101 ptr++;
00102 *ptr = 0;
00103
00104 ptr = value;
00105 while (*ptr) {
00106 *ptr = toupper(*ptr);
00107 ptr++;
00108 }
00109
00110 *len = ptr - value;
00111 return value;
00112 }
00113
00114
00115 static const char *get_DumpRestore(MSDatabase *db, const char *)
00116 {
00117 const char *value;
00118 enter_();
00119 push_(db);
00120 if (db->isRecovering())
00121 value = "TRUE";
00122 else
00123 value = "FALSE";
00124 release_(db);
00125 return_(value);
00126 }
00127
00128
00129 static const char *readOnlyCheck(char *, bool *ok)
00130 {
00131 *ok = false;
00132 return "Value is Read Only.";
00133 }
00134
00135 static const char *boolCheck(char *value, bool *ok)
00136 {
00137 const char *val = "Invalid boolean variable, try 'true' or 'false'";
00138 int len;
00139
00140 value = cleanupVariable(value, &len);
00141
00142 *ok = false;
00143 switch (*value) {
00144 case '0':
00145 if (len == 1) {
00146 *ok = true;
00147 val = "FALSE";
00148 }
00149 break;
00150
00151 case '1':
00152 if (len == 1) {
00153 *ok = true;
00154 val = "TRUE";
00155 }
00156 break;
00157
00158 case 'T':
00159 if (!strcmp(value, "TRUE")) {
00160 *ok = true;
00161 val = "TRUE";
00162 }
00163 break;
00164
00165 case 'F':
00166 if (!strcmp(value, "FALSE")) {
00167 *ok = true;
00168 val = "FALSE";
00169 }
00170 break;
00171
00172
00173 }
00174
00175 return val;
00176 }
00177
00178
00179 static const char *storageTypeCheck(char *value, bool *ok)
00180 {
00181 const char *val = "Invalid storage type, try '"MS_REPOSITORY_STORAGE_TYPE"' or '"MS_CLOUD_STORAGE_TYPE"'";
00182 int len;
00183
00184 value = cleanupVariable(value, &len);
00185 *ok = false;
00186
00187 if (!strcmp(value, MS_REPOSITORY_STORAGE_TYPE)) {
00188 *ok = true;
00189 val = MS_REPOSITORY_STORAGE_TYPE;
00190 } else if (!strcmp(value, MS_CLOUD_STORAGE_TYPE)) {
00191 *ok = true;
00192 val = MS_CLOUD_STORAGE_TYPE;
00193 }
00194
00195 return val;
00196 }
00197
00198
00199 static void set_DumpRestore(MSDatabase *db, const char *value)
00200 {
00201 enter_();
00202 push_(db);
00203 db->setRecovering((strcmp(value, "TRUE") == 0));
00204 release_(db);
00205 exit_();
00206 }
00207
00208
00209 static void set_StorageType(MSDatabase *db, const char *value)
00210 {
00211 enter_();
00212 push_(db);
00213
00214 if (!strcmp(value, MS_REPOSITORY_STORAGE_TYPE))
00215 db->myBlobType = MS_STANDARD_STORAGE;
00216 else if (!strcmp(value, MS_CLOUD_STORAGE_TYPE))
00217 db->myBlobType = MS_CLOUD_STORAGE;
00218
00219 release_(db);
00220 exit_();
00221 }
00222
00223
00224 static const char *get_StorageType(MSDatabase *db, const char *)
00225 {
00226 const char *value = "Unknown";
00227 enter_();
00228 push_(db);
00229
00230 if (db->myBlobType == MS_STANDARD_STORAGE)
00231 value = MS_REPOSITORY_STORAGE_TYPE;
00232 else if (db->myBlobType == MS_CLOUD_STORAGE)
00233 value = MS_CLOUD_STORAGE_TYPE;
00234
00235 release_(db);
00236 return_(value);
00237 }
00238
00239
00240 static const char *get_S3CloudRefNo(MSDatabase *db, const char *)
00241 {
00242 static char value[20];
00243 uint32_t num;
00244 enter_();
00245 push_(db);
00246
00247 num = db->myBlobCloud->cl_getDefaultCloudRef();
00248 snprintf(value, 20, "%"PRIu32"", num);
00249
00250 release_(db);
00251 return_(value);
00252 }
00253
00254
00255 static void set_S3CloudRefNo(MSDatabase *db, const char *value)
00256 {
00257 enter_();
00258 push_(db);
00259
00260 db->myBlobCloud->cl_setDefaultCloudRef(atol(value));
00261
00262 release_(db);
00263 exit_();
00264 }
00265
00266
00267 static void set_BackupNo(MSDatabase *db, const char *value)
00268 {
00269 enter_();
00270 push_(db);
00271
00272 db->myBlobCloud->cl_setRecoveryNumber(value);
00273
00274 release_(db);
00275 exit_();
00276 }
00277
00278
00279 static const char *get_BackupNo(MSDatabase *db, const char *)
00280 {
00281 const char *value;
00282 enter_();
00283 push_(db);
00284
00285 value = db->myBlobCloud->cl_getRecoveryNumber();
00286
00287 release_(db);
00288 return_(value);
00289 }
00290
00291 static PBMSVariableRec variables[] = {
00292 {false, "Storage-Type", MS_REPOSITORY_STORAGE_TYPE, "How the BLOB data is to be stored.", true, get_StorageType, storageTypeCheck, set_StorageType},
00293 {false, "S3-Cloud-Ref", NULL, "The S3 cloud reference id from the pbms.pbms_cloud table used for new BLOB storage.", true, get_S3CloudRefNo, NULL, set_S3CloudRefNo},
00294 {false, RESTORE_DUMP_VAR, "FALSE", "Indicate if the database is being restored from a dump file.", false, get_DumpRestore, boolCheck, set_DumpRestore},
00295
00296 {true, BACKUP_NUMBER_VAR, NULL, "The backup number for cloud blob data after a drag and drop restore.", true, get_BackupNo, readOnlyCheck, set_BackupNo}
00297 };
00298
00299 static const uint32_t num_variables = 4;
00300
00301
00302
00303 #define PBMS_VARIABLES_FILE "pbms_variables"
00304 static CSPath *getSysVarFile(CSString *db_path)
00305 {
00306 CSPath *path;
00307
00308 enter_();
00309
00310 push_(db_path);
00311
00312 path = CSPath::newPath(RETAIN(db_path), PBMS_VARIABLES_FILE".dat");
00313 push_(path);
00314 if (!path->exists()) {
00315 CSPath *tmp_path;
00316
00317 tmp_path = CSPath::newPath(RETAIN(db_path), PBMS_VARIABLES_FILE".tmp");
00318 push_(tmp_path);
00319 if (tmp_path->exists())
00320 tmp_path->rename(PBMS_VARIABLES_FILE".dat");
00321 release_(tmp_path);
00322 }
00323
00324
00325 pop_(path);
00326 release_(db_path);
00327 return_(path);
00328 }
00329
00330 class LoadTableCleanUp : public CSRefObject {
00331 bool do_cleanup;
00332 CSThread *myself;
00333
00334 uint32_t ref_id;
00335
00336 public:
00337
00338 LoadTableCleanUp(): CSRefObject(),
00339 do_cleanup(false), myself(NULL){}
00340
00341 ~LoadTableCleanUp()
00342 {
00343 if (do_cleanup) {
00344 CSL.log(myself, CSLog::Protocol, "\nRestore failed!\n");
00345 CSL.flush();
00346 myself->logException();
00347 }
00348 }
00349
00350 void setCleanUp(CSThread *self)
00351 {
00352 myself = self;
00353 do_cleanup = true;
00354 }
00355
00356 void cancelCleanUp()
00357 {
00358 do_cleanup = false;
00359 }
00360
00361 };
00362
00363 void MSVariableTable::loadTable(MSDatabase *db)
00364 {
00365 CSPath *path;
00366
00367 enter_();
00368
00369 push_(db);
00370 path = getSysVarFile(RETAIN(db->myDatabasePath));
00371 push_(path);
00372
00373 if (path->exists()) {
00374 CSFile *file;
00375 CSStringBuffer *string;
00376 size_t size = 0, pos =0;
00377 char *name, *value;
00378
00379 new_(string, CSStringBuffer(20));
00380 push_(string);
00381
00382 file = path->openFile(CSFile::READONLY);
00383 push_(file);
00384 size = file->getEOF();
00385 string->setLength(size);
00386 file->read(string->getBuffer(0), 0, size, size);
00387 release_(file);
00388
00389 while (pos < size) {
00390 name = string->getBuffer(pos);
00391 pos += strlen(name) +1;
00392 if (pos >= size)
00393 break;
00394
00395 value = string->getBuffer(pos);
00396 pos += strlen(value) +1;
00397 if (pos > size)
00398 break;
00399
00400 for (uint32_t i =0; i < num_variables; i++) {
00401 if (variables[i].save && variables[i].action && !strcmp(name, variables[i].name)) {
00402 variables[i].action(RETAIN(db), value);
00403 }
00404 }
00405
00406 }
00407
00408 release_(string);
00409
00410 } else {
00411 for (uint32_t i =0; i < num_variables; i++) {
00412 if (variables[i].value && variables[i].action) {
00413 variables[i].action(RETAIN(db), variables[i].value);
00414 }
00415 }
00416 }
00417
00418
00419 release_(path);
00420
00421
00422
00423 if ((db->myBlobType == MS_CLOUD_STORAGE) && db->myBlobCloud->cl_mustRecoverBlobs() && !db->isRecovering()) {
00424 CSL.log(self, CSLog::Protocol, "Restoring Cloud BLOBs for database: ");
00425 CSL.log(self, CSLog::Protocol, db->myDatabaseName->getCString());
00426 CSL.log(self, CSLog::Protocol, " ...");
00427 CSL.flush();
00428 LoadTableCleanUp *cleanup;
00429
00430 new_(cleanup, LoadTableCleanUp());
00431 push_(cleanup);
00432 cleanup->setCleanUp(self);
00433
00434 db->myBlobCloud->cl_restoreDB();
00435
00436 cleanup->cancelCleanUp();
00437 release_(cleanup);
00438
00439 CSL.log(self, CSLog::Protocol, "\nRestore done.\n");
00440 CSL.flush();
00441 set_BackupNo(RETAIN(db), "0");
00442 saveTable(RETAIN(db));
00443 }
00444
00445 release_(db);
00446
00447 exit_();
00448 }
00449
00450 void MSVariableTable::saveTable(MSDatabase *db)
00451 {
00452 CSPath *path;
00453 CSPath *old_path;
00454 CSFile *file;
00455 const char *value;
00456 size_t offset = 0, len;
00457 char null_char = 0;
00458 enter_();
00459
00460 push_(db);
00461 path = CSPath::newPath(RETAIN(db->myDatabasePath), PBMS_VARIABLES_FILE".tmp");
00462 push_(path);
00463 file = path->openFile(CSFile::CREATE | CSFile::TRUNCATE);
00464 push_(file);
00465
00466 for (uint32_t i = 0; i < num_variables; i++) {
00467 if (! variables[i].save) continue;
00468
00469 len = strlen(variables[i].name)+1;
00470 file->write(variables[i].name, offset, len);
00471 offset += len;
00472
00473 value = variables[i].get(RETAIN(db), variables[i].value);
00474 if (value) {
00475 len = strlen(value)+1;
00476 file->write(value, offset, len);
00477 offset += len;
00478 } else {
00479 file->write(&null_char, offset, 1);
00480 offset++;
00481 }
00482 }
00483 file->close();
00484 release_(file);
00485
00486 old_path = CSPath::newPath(RETAIN(db->myDatabasePath), PBMS_VARIABLES_FILE".dat");
00487 push_(old_path);
00488 if (old_path->exists())
00489 old_path->remove();
00490 path->rename(PBMS_VARIABLES_FILE".dat");
00491 release_(old_path);
00492
00493 release_(path);
00494 release_(db);
00495 exit_();
00496 }
00497
00498
00499 MSVariableTable::MSVariableTable(MSSystemTableShare *share, TABLE *table):
00500 MSOpenSystemTable(share, table),
00501 iVariableIndex(0)
00502 {
00503 }
00504
00505 MSVariableTable::~MSVariableTable()
00506 {
00507
00508 }
00509
00510 void MSVariableTable::use()
00511 {
00512 gVarLock.lock();
00513 }
00514
00515 void MSVariableTable::unuse()
00516 {
00517 gVarLock.unlock();
00518 }
00519
00520
00521 void MSVariableTable::seqScanInit()
00522 {
00523 iVariableIndex = 0;
00524 }
00525
00526 bool MSVariableTable::seqScanNext(char *buf)
00527 {
00528 TABLE *table = mySQLTable;
00529 Field *curr_field;
00530 byte *save;
00531 MY_BITMAP *save_write_set;
00532 PBMSVariablePtr var;
00533
00534 enter_();
00535
00536 do {
00537 if (iVariableIndex >= num_variables)
00538 return_(false);
00539 var = &(variables[iVariableIndex++]);
00540
00541 } while (var->hidden);
00542
00543 save_write_set = table->write_set;
00544 table->write_set = NULL;
00545
00546 #ifdef DRIZZLED
00547 memset(buf, 0xFF, table->getNullBytes());
00548 #else
00549 memset(buf, 0xFF, table->s->null_bytes);
00550 #endif
00551 for (Field **field=GET_TABLE_FIELDS(table) ; *field ; field++) {
00552 curr_field = *field;
00553 save = curr_field->ptr;
00554 #if MYSQL_VERSION_ID < 50114
00555 curr_field->ptr = (byte *) buf + curr_field->offset();
00556 #else
00557 #ifdef DRIZZLED
00558 curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->getTable()->getInsertRecord());
00559 #else
00560 curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]);
00561 #endif
00562 #endif
00563 switch (curr_field->field_name[0]) {
00564 case 'I':
00565 ASSERT(strcmp(curr_field->field_name, "Id") == 0);
00566 curr_field->store(iVariableIndex, true);
00567 setNotNullInRecord(curr_field, buf);
00568 break;
00569
00570 case 'N':
00571 ASSERT(strcmp(curr_field->field_name, "Name") == 0);
00572 curr_field->store(var->name, strlen(var->name), &UTF8_CHARSET);
00573 setNotNullInRecord(curr_field, buf);
00574 break;
00575
00576 case 'V': {
00577 ASSERT(strcmp(curr_field->field_name, "Value") == 0);
00578 const char *value;
00579 value = var->get(RETAIN(myShare->mySysDatabase), var->value);
00580 if (value) {
00581 curr_field->store(value, strlen(value), &UTF8_CHARSET);
00582 setNotNullInRecord(curr_field, buf);
00583 }
00584 }
00585 break;
00586
00587 case 'D':
00588 ASSERT(strcmp(curr_field->field_name, "Description") == 0);
00589 curr_field->store(var->info, strlen(var->info), &UTF8_CHARSET);
00590 setNotNullInRecord(curr_field, buf);
00591 break;
00592
00593 }
00594 curr_field->ptr = save;
00595 }
00596
00597 table->write_set = save_write_set;
00598 return_(true);
00599 }
00600
00601 void MSVariableTable::seqScanPos(unsigned char *pos)
00602 {
00603 int32_t index = iVariableIndex -1;
00604 if (index < 0)
00605 index = 0;
00606
00607 mi_int4store(pos, index);
00608 }
00609
00610 void MSVariableTable::seqScanRead(unsigned char *pos, char *buf)
00611 {
00612 iVariableIndex = mi_uint4korr(pos);
00613 seqScanNext(buf);
00614 }
00615
00616 void MSVariableTable::updateRow(char *old_data, char *new_data)
00617 {
00618 uint32_t n_id, o_id;
00619 String n_var_name, n_var_value;
00620 String o_var_name;
00621 const char *clean_value;
00622
00623 enter_();
00624
00625 getFieldValue(old_data, 0, &o_id);
00626 getFieldValue(old_data, 1, &o_var_name);
00627
00628 getFieldValue(new_data, 0, &n_id);
00629 getFieldValue(new_data, 1, &n_var_name);
00630 getFieldValue(new_data, 2, &n_var_value);
00631
00632
00633 if ((n_id != o_id) || my_strcasecmp(&UTF8_CHARSET, o_var_name.c_ptr_safe(), n_var_name.c_ptr_safe()))
00634 CSException::throwException(CS_CONTEXT, HA_ERR_TABLE_READONLY, "Attempt to update read only fields in the "VARIABLES_TABLE_NAME" table.");
00635
00636 n_id--;
00637 if (n_id > num_variables)
00638 CSException::throwException(CS_CONTEXT, HA_ERR_KEY_NOT_FOUND, "Invalid id");
00639
00640 CSStringBuffer *value;
00641 new_(value, CSStringBuffer(0));
00642 push_(value);
00643 value->append(n_var_value.c_ptr(), n_var_value.length());
00644
00645
00646 if (variables[n_id].check) {
00647 bool ok = false;
00648 clean_value = variables[n_id].check(value->getCString(), &ok);
00649 if (!ok)
00650 CSException::throwException(CS_CONTEXT, HA_ERR_GENERIC, clean_value);
00651 } else
00652 clean_value = value->getCString();
00653
00654
00655 if (variables[n_id].action) {
00656 variables[n_id].action(RETAIN(myShare->mySysDatabase), clean_value);
00657 }
00658
00659 release_(value);
00660
00661 if (variables[n_id].save) {
00662 saveTable(RETAIN(myShare->mySysDatabase));
00663 }
00664
00665 exit_();
00666 }
00667
00668 void MSVariableTable::transferTable(MSDatabase *to_db, MSDatabase *from_db)
00669 {
00670 CSPath *path;
00671 enter_();
00672
00673 push_(from_db);
00674 push_(to_db);
00675
00676 path = CSPath::newPath(RETAIN(from_db->myDatabasePath), PBMS_VARIABLES_FILE".dat");
00677 push_(path);
00678 if (path->exists()) {
00679 CSPath *bu_path;
00680 bu_path = CSPath::newPath(RETAIN(to_db->myDatabasePath), PBMS_VARIABLES_FILE".dat");
00681 path->copyTo(bu_path, true);
00682 }
00683
00684 release_(path);
00685 release_(to_db);
00686 release_(from_db);
00687
00688 exit_();
00689 }
00690
00691 void MSVariableTable::setVariable(MSDatabase *db, const char *name, const char *value)
00692 {
00693 enter_();
00694
00695 push_(db);
00696
00697 for (uint32_t i =0; db && i < num_variables; i++) {
00698 if (variables[i].action && !strcmp(name, variables[i].name)) {
00699 variables[i].action(RETAIN(db), value);
00700 if (variables[i].save) {
00701 pop_(db);
00702 saveTable(db);
00703 } else
00704 release_(db);
00705 db = NULL;
00706 }
00707 }
00708
00709 if (db) {
00710 release_(db);
00711 CSException::throwException(CS_CONTEXT, HA_ERR_KEY_NOT_FOUND, name);
00712 }
00713 exit_();
00714 }
00715
00716 CSStringBuffer *MSVariableTable::dumpTable(MSDatabase *db)
00717 {
00718
00719 CSPath *path;
00720 CSStringBuffer *dump;
00721
00722 enter_();
00723
00724 push_(db);
00725 path = getSysVarFile(RETAIN(db->myDatabasePath));
00726 release_(db);
00727
00728 push_(path);
00729 new_(dump, CSStringBuffer(20));
00730 push_(dump);
00731
00732 if (path->exists()) {
00733 CSFile *file;
00734 size_t size;
00735
00736 file = path->openFile(CSFile::READONLY);
00737 push_(file);
00738
00739 size = file->getEOF();
00740 dump->setLength(size);
00741 file->read(dump->getBuffer(0), 0, size, size);
00742 release_(file);
00743 }
00744
00745 pop_(dump);
00746 release_(path);
00747 return_(dump);
00748 }
00749
00750 void MSVariableTable::restoreTable(MSDatabase *db, const char *data, size_t size, bool reload)
00751 {
00752 CSPath *path;
00753 CSFile *file;
00754
00755 enter_();
00756
00757 push_(db);
00758 path = getSysVarFile(RETAIN(db->myDatabasePath));
00759 push_(path);
00760
00761 file = path->openFile(CSFile::CREATE | CSFile::TRUNCATE);
00762 push_(file);
00763
00764 file->write(data, 0, size);
00765 file->close();
00766 release_(file);
00767
00768 release_(path);
00769
00770 pop_(db);
00771 if (reload)
00772 loadTable(db);
00773 else
00774 db->release();
00775 exit_();
00776 }
00777
00778 void MSVariableTable::removeTable(CSString *db_path)
00779 {
00780 CSPath *path;
00781 enter_();
00782
00783 path = getSysVarFile(db_path);
00784 push_(path);
00785
00786 path->removeFile();
00787 release_(path);
00788 exit_();
00789 }
00790