1
/* Copyright (c) 2009 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
* System cloud starage info table.
29
#include <sys/types.h>
35
#include <drizzled/server_includes.h>
38
//#include "mysql_priv.h"
40
#include "CSStrUtil.h"
43
#include "CSDirectory.h"
49
#include "Database_ms.h"
50
#include "OpenTable_ms.h"
52
#include "Discover_ms.h"
53
#include "SysTab_util.h"
55
#include "SysTab_cloud.h"
57
DT_FIELD_INFO pbms_cloud_info[]=
59
{"Id", NULL, NULL, MYSQL_TYPE_LONG, NULL, NOT_NULL_FLAG, "The Cloud storage reference ID"},
60
{"Server", 1024, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "S3 server name"},
61
{"Bucket", 124, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "S3 bucket name"},
62
{"PublicKey", 124, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "S3 public key"},
63
{"PrivateKey", 124, NULL, MYSQL_TYPE_VARCHAR, &UTF8_CHARSET, NOT_NULL_FLAG, "S3 private key"},
64
{NULL,NULL, NULL, MYSQL_TYPE_STRING,NULL, 0, NULL}
67
DT_KEY_INFO pbms_cloud_keys[]=
69
{"pbms_cloud_pk", PRI_KEY_FLAG, {"Id", NULL}},
73
#define MIN_CLOUD_TABLE_SIZE 4
75
//----------------------------
76
void MSCloudTable::startUp()
78
MSCloudInfo::startUp();
81
//----------------------------
82
void MSCloudTable::shutDown()
84
MSCloudInfo::shutDown();
87
//----------------------------
88
void MSCloudTable::loadTable(MSDatabase *db)
94
lock_(MSCloudInfo::gCloudInfo);
96
if (MSCloudInfo::gMaxInfoRef == 0) {
98
path = getSysFile(getPBMSPath(RETAIN(db->myDatabasePath)), CLOUD_TABLE_NAME, MIN_CLOUD_TABLE_SIZE);
101
if (path->exists()) {
103
SysTabRec *cloudData;
104
const char *server, *bucket, *pubKey, *privKey;
109
new_(cloudData, SysTabRec("pbms", CLOUD_TABLE_NAME".dat", CLOUD_TABLE_NAME));
112
file = path->openFile(CSFile::READONLY);
114
size = file->getEOF();
115
cloudData->setLength(size);
116
file->read(cloudData->getBuffer(0), 0, size, size);
119
cloudData->firstRecord();
120
MSCloudInfo::gMaxInfoRef = cloudData->getInt4Field();
122
if (! cloudData->isValidRecord())
123
MSCloudInfo::gMaxInfoRef = 1;
125
while (cloudData->nextRecord()) {
126
info_id = cloudData->getInt4Field();
127
server = cloudData->getStringField();
128
bucket = cloudData->getStringField();
129
pubKey = cloudData->getStringField();
130
privKey = cloudData->getStringField();
132
if (cloudData->isValidRecord()) {
133
if (info_id > MSCloudInfo::gMaxInfoRef) {
135
snprintf(msg, 80, "Cloud info id (%"PRIu32") larger than expected (%"PRIu32")\n", info_id, MSCloudInfo::gMaxInfoRef);
136
CSL.log(self, CSLog::Warning, "pbms "CLOUD_TABLE_NAME".dat :possible damaged file or record. ");
137
CSL.log(self, CSLog::Warning, msg);
138
MSCloudInfo::gMaxInfoRef = info_id +1;
140
if ( MSCloudInfo::gCloudInfo->get(info_id)) {
142
snprintf(msg, 80, "Duplicate Cloud info id (%"PRIu32") being ignored\n", info_id);
143
CSL.log(self, CSLog::Warning, "pbms "CLOUD_TABLE_NAME".dat :possible damaged file or record. ");
144
CSL.log(self, CSLog::Warning, msg);
146
new_(info, MSCloudInfo( info_id, server, bucket, pubKey, privKey));
147
MSCloudInfo::gCloudInfo->set(info_id, info);
151
release_(cloudData); cloudData = NULL;
154
MSCloudInfo::gMaxInfoRef = 1;
159
unlock_(MSCloudInfo::gCloudInfo);
166
void MSCloudTable::saveTable(MSDatabase *db)
168
SysTabRec *cloudData;
174
new_(cloudData, SysTabRec("pbms", CLOUD_TABLE_NAME".dat", CLOUD_TABLE_NAME));
177
// Build the table records
179
lock_(MSCloudInfo::gCloudInfo);
181
cloudData->beginRecord();
182
cloudData->setInt4Field(MSCloudInfo::gMaxInfoRef);
183
cloudData->endRecord();
184
for (int i = 0;(info = (MSCloudInfo*) MSCloudInfo::gCloudInfo->itemAt(i)); i++) { // info is not referenced.
186
cloudData->beginRecord();
187
cloudData->setInt4Field(info->getCloudRefId());
188
cloudData->setStringField(info->getServer());
189
cloudData->setStringField(info->getBucket());
190
cloudData->setStringField(info->getPublicKey());
191
cloudData->setStringField(info->getPrivateKey());
192
cloudData->endRecord();
194
unlock_(MSCloudInfo::gCloudInfo);
196
restoreTable(RETAIN(db), cloudData->getBuffer(0), cloudData->length(), false);
204
MSCloudTable::MSCloudTable(MSSystemTableShare *share, TABLE *table):
205
MSOpenSystemTable(share, table),
210
MSCloudTable::~MSCloudTable()
215
void MSCloudTable::use()
217
MSCloudInfo::gCloudInfo->lock();
220
void MSCloudTable::unuse()
222
MSCloudInfo::gCloudInfo->unlock();
227
void MSCloudTable::seqScanInit()
232
#define MAX_PASSWORD 64
233
bool MSCloudTable::seqScanNext(char *buf)
235
char passwd[MAX_PASSWORD +1];
236
TABLE *table = mySQLTable;
239
MY_BITMAP *save_write_set;
245
info = (MSCloudInfo *) MSCloudInfo::gCloudInfo->itemAt(iCloudIndex++); // Object is not referenced.
249
save_write_set = table->write_set;
250
table->write_set = NULL;
252
memset(buf, 0xFF, table->s->null_bytes);
253
for (Field **field=table->field ; *field ; field++) {
255
save = curr_field->ptr;
256
#if MYSQL_VERSION_ID < 50114
257
curr_field->ptr = (byte *) buf + curr_field->offset();
259
curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->table->record[0]);
261
switch (curr_field->field_name[0]) {
263
ASSERT(strcmp(curr_field->field_name, "Id") == 0);
264
curr_field->store(info->getCloudRefId(), true);
268
ASSERT(strcmp(curr_field->field_name, "Server") == 0);
269
val = info->getServer();
270
curr_field->store(val, strlen(val), &UTF8_CHARSET);
271
ms_my_set_notnull_in_record(curr_field, buf);
275
ASSERT(strcmp(curr_field->field_name, "Bucket") == 0);
276
val = info->getBucket();
277
curr_field->store(val, strlen(val), &UTF8_CHARSET);
278
ms_my_set_notnull_in_record(curr_field, buf);
282
if (curr_field->field_name[1] == 'u') {
283
ASSERT(strcmp(curr_field->field_name, "PublicKey") == 0);
284
val = info->getPublicKey();
285
} else if (curr_field->field_name[1] == 'r') {
286
ASSERT(strcmp(curr_field->field_name, "PrivateKey") == 0);
287
val = info->getPrivateKey();
290
for (i = 0; i < MAX_PASSWORD && i < strlen(val); i++) passwd[i] = '*';
297
curr_field->store(val, strlen(val), &UTF8_CHARSET);
298
ms_my_set_notnull_in_record(curr_field, buf);
304
curr_field->ptr = save;
307
table->write_set = save_write_set;
312
void MSCloudTable::seqScanPos(uint8_t *pos)
314
int32_t index = iCloudIndex -1;
316
index = 0; // This is probably an error condition.
318
mi_int4store(pos, index);
321
void MSCloudTable::seqScanRead(uint8_t *pos, char *buf)
323
iCloudIndex = mi_uint4korr(pos);
327
void MSCloudTable::updateRow(char *old_data, char *new_data)
329
TABLE *table = mySQLTable;
330
uint32_t n_id, o_id, o_indx, n_indx;
331
const char *realPrivKey;
332
String server_val, bucket_val, pubKey_val, privKey_val, *server = &server_val, *bucket = &bucket_val, *pubKey = &pubKey_val, *privKey = &privKey_val;
333
String o_server_val, o_bucket_val, o_pubKey_val, o_privKey_val, *o_server = &o_server_val, *o_bucket = &o_bucket_val, *o_pubKey = &o_pubKey_val, *o_privKey = &o_privKey_val;
338
GET_INT_FIELD(n_id, 0, table, new_data);
339
GET_STR_FIELD(server, 1, table, new_data);
340
GET_STR_FIELD(bucket, 2, table, new_data);
341
GET_STR_FIELD(pubKey, 3, table, new_data);
342
GET_STR_FIELD(privKey, 4, table, new_data);
344
GET_INT_FIELD(o_id, 0, table, old_data);
345
GET_STR_FIELD(o_server, 1, table, old_data);
346
GET_STR_FIELD(o_bucket, 2, table, old_data);
347
GET_STR_FIELD(o_pubKey, 3, table, old_data);
348
GET_STR_FIELD(o_privKey, 4, table, old_data);
350
// The cloud ID must be unique
351
if ((o_id != n_id) && MSCloudInfo::gCloudInfo->get(n_id)) {
352
CSException::throwException(CS_CONTEXT, MS_ERR_DUPLICATE, "Attempt to update a row with a duplicate key in the "CLOUD_TABLE_NAME" table.");
355
// The private key is masked when returned to the caller, so
356
// unless the caller has updated it we need to get the real
357
// private key from the old record.
358
if (strcmp(privKey->c_ptr(), o_privKey->c_ptr()))
359
realPrivKey = privKey->c_ptr();
361
info = (MSCloudInfo*) MSCloudInfo::gCloudInfo->get(o_id); // unreference pointer
362
realPrivKey = info->getPrivateKey();
365
new_(info, MSCloudInfo( n_id, server->c_ptr(), bucket->c_ptr(), pubKey->c_ptr(), realPrivKey));
368
o_indx = MSCloudInfo::gCloudInfo->getIndex(o_id);
370
MSCloudInfo::gCloudInfo->remove(o_id);
372
MSCloudInfo::gCloudInfo->set(n_id, info);
373
n_indx = MSCloudInfo::gCloudInfo->getIndex(n_id);
375
// Adjust the current position in the array if required.
376
if (o_indx < n_indx )
379
saveTable(RETAIN(myShare->mySysDatabase));
383
void MSCloudTable::insertRow(char *data)
385
TABLE *table = mySQLTable;
387
String server_val, bucket_val, pubKey_val, privKey_val, *server = &server_val, *bucket = &bucket_val, *pubKey = &pubKey_val, *privKey = &privKey_val;
392
GET_INT_FIELD(ref_id, 0, table, data);
394
// The cloud ID must be unique
395
if (ref_id && MSCloudInfo::gCloudInfo->get(ref_id)) {
396
CSException::throwException(CS_CONTEXT, MS_ERR_DUPLICATE, "Attempt to insert a row with a duplicate key in the "CLOUD_TABLE_NAME" table.");
399
GET_STR_FIELD(server, 1, table, data);
400
GET_STR_FIELD(bucket, 2, table, data);
401
GET_STR_FIELD(pubKey, 3, table, data);
402
GET_STR_FIELD(privKey, 4, table, data);
405
ref_id = MSCloudInfo::gMaxInfoRef++;
406
else if (ref_id >= MSCloudInfo::gMaxInfoRef)
407
MSCloudInfo::gMaxInfoRef = ref_id +1;
409
new_(info, MSCloudInfo( ref_id, server->c_ptr(), bucket->c_ptr(), pubKey->c_ptr(), privKey->c_ptr()));
410
MSCloudInfo::gCloudInfo->set(ref_id, info);
412
saveTable(RETAIN(myShare->mySysDatabase));
416
void MSCloudTable::deleteRow(char *data)
418
TABLE *table = mySQLTable;
419
uint32_t ref_id, indx;
423
GET_INT_FIELD(ref_id, 0, table, data);
425
// Adjust the current position in the array if required.
426
indx = MSCloudInfo::gCloudInfo->getIndex(ref_id);
427
if (indx <= iCloudIndex)
430
MSCloudInfo::gCloudInfo->remove(ref_id);
431
saveTable(RETAIN(myShare->mySysDatabase));
435
void MSCloudTable::transferTable(MSDatabase *to_db, MSDatabase *from_db)
443
path = CSPath::newPath(getPBMSPath(RETAIN(from_db->myDatabasePath)), CLOUD_TABLE_NAME".dat");
445
if (path->exists()) {
447
bu_path = CSPath::newPath(getPBMSPath(RETAIN(to_db->myDatabasePath)), CLOUD_TABLE_NAME".dat");
448
path->copyTo(bu_path, true);
458
CSStringBuffer *MSCloudTable::dumpTable(MSDatabase *db)
462
CSStringBuffer *dump;
467
path = getSysFile(getPBMSPath(RETAIN(db->myDatabasePath)), CLOUD_TABLE_NAME, MIN_CLOUD_TABLE_SIZE);
471
new_(dump, CSStringBuffer(20));
474
if (path->exists()) {
478
file = path->openFile(CSFile::READONLY);
481
size = file->getEOF();
482
dump->setLength(size);
483
file->read(dump->getBuffer(0), 0, size, size);
492
void MSCloudTable::restoreTable(MSDatabase *db, const char *data, size_t size, bool reload)
500
path = getSysFile(getPBMSPath(RETAIN(db->myDatabasePath)), CLOUD_TABLE_NAME, MIN_CLOUD_TABLE_SIZE);
503
file = path->openFile(CSFile::CREATE | CSFile::TRUNCATE);
506
file->write(data, 0, size);
521
void MSCloudTable::removeTable(CSString *db_path)
524
char pbms_path[PATH_MAX];
529
cs_strcpy(PATH_MAX, pbms_path, db_path->getCString());
532
if (strcmp(cs_last_name_of_path(pbms_path), "pbms") != 0)
535
cs_remove_last_name_of_path(pbms_path);
537
path = getSysFile(CSString::newString(pbms_path), CLOUD_TABLE_NAME, MIN_CLOUD_TABLE_SIZE);