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
26
#include <drizzled/common.h>
27
#include <drizzled/session.h>
28
#include <drizzled/field/blob.h>
31
#include "cslib/CSConfig.h"
33
#include <sys/types.h>
39
//#include "mysql_priv.h"
40
#include "cslib/CSGlobal.h"
41
#include "cslib/CSStrUtil.h"
47
#include "repository_ms.h"
48
#include "database_ms.h"
49
#include "compactor_ms.h"
50
#include "open_table_ms.h"
51
#include "discover_ms.h"
52
#include "transaction_ms.h"
53
#include "systab_variable_ms.h"
54
#include "backup_ms.h"
57
#include "systab_dump_ms.h"
60
DT_FIELD_INFO pbms_dump_info[]=
62
{"Data", NULL, NULL, MYSQL_TYPE_LONG_BLOB, &my_charset_bin, NOT_NULL_FLAG, "A BLOB repository record"},
63
{NULL,NULL, NULL, MYSQL_TYPE_STRING,NULL, 0, NULL}
66
DT_KEY_INFO pbms_dump_keys[]=
73
* -------------------------------------------------------------------------
76
//-----------------------
77
MSDumpTable::MSDumpTable(MSSystemTableShare *share, TABLE *table):
78
MSRepositoryTable(share, table)
82
//-----------------------
83
MSDumpTable::~MSDumpTable()
87
//-----------------------
88
void MSDumpTable::use()
90
dt_hasInfo = dt_hasCompleted = dt_haveCloudInfo = false;
93
// Suspend the transaction writer while the dump is running.
94
MSTransactionManager::suspend(true);
96
MSRepositoryTable::use();
99
//-----------------------
100
void MSDumpTable::unuse()
102
MSBackupInfo *backupInfo;
104
backupInfo = myShare->mySysDatabase->myBlobCloud->cl_getBackupInfo();
108
myShare->mySysDatabase->myBlobCloud->cl_clearBackupInfo();
109
if (backupInfo->isBackupRunning()) {
111
backupInfo->backupCompleted(RETAIN(myShare->mySysDatabase));
113
backupInfo->backupTerminated(RETAIN(myShare->mySysDatabase));
115
release_(backupInfo);
119
MSTransactionManager::resume();
120
MSRepositoryTable::unuse();
123
//-----------------------
124
void MSDumpTable::seqScanInit()
126
dt_hasInfo = dt_hasCompleted = false;
127
return MSRepositoryTable::seqScanInit();
129
//-----------------------
130
bool MSDumpTable::seqScanNext(char *buf)
134
return returnInfoRow(buf);
136
// Reset the position
137
if (!MSRepositoryTable::seqScanNext(buf))
138
dt_hasCompleted = true;
140
return !dt_hasCompleted;
143
//-----------------------
144
bool MSDumpTable::returnDumpRow(char *record, uint64_t record_size, char *buf)
146
TABLE *table = mySQLTable;
149
MY_BITMAP *save_write_set;
154
/* ASSERT_COLUMN_MARKED_FOR_WRITE is failing when
156
* But I want to use it! :(
158
save_write_set = table->write_set;
159
table->write_set = NULL;
160
memset(buf, 0xFF, table->s->null_bytes);
162
for (Field **field=GET_TABLE_FIELDS(table) ; *field ; field++) {
165
save = curr_field->ptr;
166
#if MYSQL_VERSION_ID < 50114
167
curr_field->ptr = (byte *) buf + curr_field->offset();
169
curr_field->ptr = (byte *) buf + curr_field->offset(curr_field->getTable()->getInsertRecord());
171
switch (curr_field->field_name[0]) {
175
ASSERT(strcmp(curr_field->field_name, "Data") == 0);
176
if (record_size <= 0xFFFFFFF) {
177
((Field_blob *) curr_field)->set_ptr(record_size, (byte *) record);
178
setNotNullInRecord(curr_field, buf);
182
curr_field->ptr = save;
185
table->write_set = save_write_set;
189
//-----------------------
190
bool MSDumpTable::returnRow(MSBlobHeadPtr blob, char *buf)
192
uint64_t record_size, blob_repo_size;
193
uint16_t ref_size, ref_count, refs = 0, table_refs = 0, header_size;
194
uint8_t blob_storage_type;
195
MSRepoPointersRec ptr;
196
MSDatabase *myDB = myShare->mySysDatabase;
199
// Reset the references for the BLOB and recreate
200
// the temp log references.
201
ref_count = CS_GET_DISK_2(blob->rb_ref_count_2);
202
ref_size = CS_GET_DISK_1(blob->rb_ref_size_1);
204
blob_storage_type = CS_GET_DISK_1(blob->rb_storage_type_1);
206
header_size = CS_GET_DISK_2(blob->rb_head_size_2);
207
blob_repo_size = CS_GET_DISK_6(blob->rb_blob_repo_size_6);
209
iBlobBuffer->setLength(header_size);
210
iRepoFile->read(iBlobBuffer->getBuffer(0), iRepoOffset, (size_t) header_size, header_size);
212
// First check to see if the BLOB is referenced
213
ptr.rp_chars = iBlobBuffer->getBuffer(0) + dt_headerSize;
214
for (int count = 0; count < ref_count; count++) {
215
int ref_type = CS_GET_DISK_2(ptr.rp_ref->rr_type_2);
218
case MS_BLOB_TABLE_REF:
222
case MS_BLOB_FREE_REF:
223
case MS_BLOB_DELETE_REF:
226
default: // Assumed to be a MSRepoBlobRefRec.
227
// Only committed references are backed up.
228
if (IS_COMMITTED(CS_GET_DISK_8(ptr.rp_blob_ref->er_blob_ref_id_8))) {
231
CS_SET_DISK_2(ptr.rp_ref->rr_type_2, MS_BLOB_FREE_REF);
237
ptr.rp_chars += ref_size;
241
if (refs && table_refs) { // Unreferenced BLOBs are ignored.
242
if (blob_storage_type == MS_CLOUD_STORAGE) {
243
CloudKeyRec cloud_key;
244
MSRepoFile::getBlobKey(blob, &cloud_key);
245
myDB->myBlobCloud->cl_backupBLOB(&cloud_key);
246
record_size = header_size;
248
record_size = header_size + blob_repo_size;
249
iBlobBuffer->setLength(record_size);
250
iRepoFile->read(iBlobBuffer->getBuffer(header_size), iRepoOffset + header_size, (size_t) blob_repo_size, blob_repo_size);
253
record_size = 0; // An empty record is returned for unreferenced BLOBs.
257
return returnDumpRow(iBlobBuffer->getBuffer(0), record_size, buf);
260
//-----------------------
261
#define INC_INFO_SPACE(i) record_size+=i; space-=i;ptr+=i;
262
#define MS_DUMP_MAGIC 0x5A74C1EB
264
CSDiskValue4 ti_table_id_4;
265
char ti_name[1]; // variable length buffer
266
} TabInfoRec, *TabInfoPtr;
269
CSDiskValue4 di_magic_4;
270
CSDiskValue2 di_header_size_2;
271
} RepInfoRec, *RepInfoPtr;
273
// Repository DUMP info record format:
274
// <Dump magic><BLOB header size><database ID><backup number><sysTables size><sysTables dump>[<table ID><table name>]...
275
bool MSDumpTable::returnInfoRow(char *buf)
277
uint64_t record_size = 0, space = 1024;
280
uint32_t space_needed, next_tab = 0, cloudRef, cloudbackupNo, backupRef;
283
CSStringBuffer *sysTablesDump;
284
MSBackupInfo *backupInfo;
288
// Setup the sysvar table with the cloud backup number then dump it.
289
if (myShare->mySysDatabase->myBlobType == MS_CLOUD_STORAGE) {
290
cloudbackupNo = myShare->mySysDatabase->myBlobCloud->cl_getNextBackupNumber();
291
cloudRef = myShare->mySysDatabase->myBlobCloud->cl_getDefaultCloudRef();
293
// It is still possible that the database contains BLOBs in cloud storage
294
// even if it isn't currently flaged to use cloud storage.
295
cloudbackupNo = cloudRef = 0;
298
backupInfo = MSBackupInfo::startDump(RETAIN(myShare->mySysDatabase), cloudRef, cloudbackupNo);
299
backupRef = backupInfo->getBackupRefId();
300
myShare->mySysDatabase->myBlobCloud->cl_setBackupInfo(backupInfo);
302
dt_cloudbackupDBID = myShare->mySysDatabase->myDatabaseID;
304
sysTablesDump = PBMSSystemTables::dumpSystemTables(RETAIN(myShare->mySysDatabase));
305
push_(sysTablesDump);
307
iBlobBuffer->setLength(space + sysTablesDump->length() + 4 + 4);
308
ptr = iBlobBuffer->getBuffer(0);
309
rep_info = (RepInfoPtr) iBlobBuffer->getBuffer(0);
310
dt_headerSize = sizeof(MSBlobHeadRec);
313
CS_SET_DISK_4(rep_info->di_magic_4, MS_DUMP_MAGIC);
314
CS_SET_DISK_2(rep_info->di_header_size_2, dt_headerSize);
316
INC_INFO_SPACE(sizeof(RepInfoRec));
319
CS_SET_DISK_4(d.int_val->val_4, dt_cloudbackupDBID);
323
CS_SET_DISK_4(d.int_val->val_4, backupRef);
326
// Add the system tables to the dump
328
CS_SET_DISK_4(d.int_val->val_4, sysTablesDump->length());
330
memcpy(ptr, sysTablesDump->getBuffer(0), sysTablesDump->length());
331
INC_INFO_SPACE(sysTablesDump->length());
332
sysTablesDump->release();
333
sysTablesDump = NULL;
335
tab_info = (TabInfoPtr)ptr;
337
// Get a list of the tables containing BLOB references.
338
while ((tab = myShare->mySysDatabase->getNextTable(&next_tab))) {
340
space_needed = tab->myTableName->length() + 5;
341
if (space < space_needed) {
343
iBlobBuffer->setLength(space);
344
ptr = iBlobBuffer->getBuffer(0) + record_size;
347
tab_info = (TabInfoPtr)ptr;
348
CS_SET_DISK_4(tab_info->ti_table_id_4, tab->myTableID);
349
strcpy(tab_info->ti_name, tab->myTableName->getCString());
350
INC_INFO_SPACE(space_needed);
355
return_(returnDumpRow(iBlobBuffer->getBuffer(0), record_size, buf));
358
#define INC_INFO_REC(i) info_buffer+=i; length-=i; tab_info = (TabInfoPtr) info_buffer;
359
//-----------------------
360
void MSDumpTable::setUpRepository(const char *info_buffer, uint32_t length)
362
uint32_t tab_id, magic;
363
MSDatabase *myDB = myShare->mySysDatabase;
364
RepInfoPtr rep_info = (RepInfoPtr) info_buffer;
366
uint32_t sys_size, backupRefID;
367
MSBackupInfo *backupInfo;
370
if (length < sizeof(RepInfoRec)) {
371
CSException::throwException(CS_CONTEXT, CS_ERR_INVALID_RECORD, "Invalid repository info record.");
374
magic = CS_GET_DISK_4(rep_info->di_magic_4);
375
if (CS_GET_DISK_4(rep_info->di_magic_4) != MS_DUMP_MAGIC) {
376
CSException::throwException(CS_CONTEXT, CS_ERR_BAD_HEADER_MAGIC, "Invalid repository info record.");
379
dt_headerSize = CS_GET_DISK_2(rep_info->di_header_size_2);
380
INC_INFO_REC(sizeof(RepInfoRec));
382
d.rec_cchars = info_buffer;
383
dt_cloudbackupDBID = CS_GET_DISK_4(d.int_val->val_4);
386
// Get the backup information
387
d.rec_cchars = info_buffer;
388
backupRefID = CS_GET_DISK_4(d.int_val->val_4);
391
// If the backup information is missing then the restore may still
392
// be able to complete so long as cloud storage was not used.
393
backupInfo = MSBackupInfo::findBackupInfo(backupRefID);
395
myShare->mySysDatabase->myBlobCloud->cl_setBackupInfo(backupInfo);
396
dt_haveCloudInfo = true;
399
// Restore the System table.
400
d.rec_cchars = info_buffer;
401
sys_size = CS_GET_DISK_4(d.int_val->val_4);
404
PBMSSystemTables::restoreSystemTables(RETAIN(myDB), info_buffer, sys_size);
405
INC_INFO_REC(sys_size);
408
tab_id = CS_GET_DISK_4(tab_info->ti_table_id_4);
409
myDB->addTable(tab_id, tab_info->ti_name, 0, false);
410
INC_INFO_REC(strlen(tab_info->ti_name) +5);
414
CSException::throwException(CS_CONTEXT, CS_ERR_INVALID_RECORD, "Invalid repository info record.");
418
//-----------------------
419
void MSDumpTable::insertRow(char *buf)
421
TABLE *table = mySQLTable;
423
uint32_t packlength, length;
424
const char *blob_rec, *blob_ptr;
426
field = (Field_blob *)GET_FIELD(table, 0);
428
/* Get the blob record: */
429
blob_rec= buf + field->offset(table->getInsertRecord());
430
packlength= field->pack_length() - table->s->blob_ptr_size;
432
memcpy(&blob_ptr, blob_rec +packlength, sizeof(char*));
433
length= field->get_length();
436
setUpRepository(blob_ptr, length);
439
insertRepoRow((MSBlobHeadPtr)blob_ptr, length);
443
//-----------------------
444
void MSDumpTable::insertRepoRow(MSBlobHeadPtr blob, uint32_t length)
447
MSRepoFile *repo_file;
448
uint64_t repo_offset;
449
uint64_t blob_data_size;
451
uint16_t ref_size, ref_count, refs = 0, table_refs = 0;
452
uint8_t blob_storage_type;
453
MSRepoPointersRec ptr;
454
MSDatabase *myDB = myShare->mySysDatabase;
455
CloudKeyRec cloud_key;
461
if (length != (CS_GET_DISK_2(blob->rb_head_size_2) + CS_GET_DISK_6(blob->rb_blob_repo_size_6))) {
462
CSException::throwException(CS_CONTEXT, MS_ERR_INVALID_RECORD, "Damaged Repository record");
465
// Get a repository file.
466
repo = myDB->lockRepo(length);
469
repo_file = myDB->getRepoFileFromPool(repo->myRepoID, false);
470
frompool_(repo_file);
472
repo_offset = repo->myRepoFileSize;
474
// Reset the references for the BLOB and recreate
475
// the temp log references.
476
auth_code = CS_GET_DISK_4(blob->rb_auth_code_4);
477
ref_count = CS_GET_DISK_2(blob->rb_ref_count_2);
478
ref_size = CS_GET_DISK_1(blob->rb_ref_size_1);
479
blob_data_size = CS_GET_DISK_6(blob->rb_blob_data_size_6);
481
blob_storage_type = CS_GET_DISK_1(blob->rb_storage_type_1);
482
if (blob_storage_type == MS_CLOUD_STORAGE) {
483
MSRepoFile::getBlobKey(blob, &cloud_key);
486
// First check to see if the BLOB is referenced
487
ptr.rp_chars = ((char*) blob) + dt_headerSize;
488
for (int count = 0; count < ref_count; count++) {
489
int ref_type = CS_GET_DISK_2(ptr.rp_ref->rr_type_2);
492
case MS_BLOB_TABLE_REF:
496
case MS_BLOB_FREE_REF:
497
case MS_BLOB_DELETE_REF:
500
default: // Assumed to be a MSRepoBlobRefRec.
501
// Only committed references are backed up.
502
if (IS_COMMITTED(CS_GET_DISK_8(ptr.rp_blob_ref->er_blob_ref_id_8))) {
505
CS_SET_DISK_2(ptr.rp_ref->rr_type_2, MS_BLOB_FREE_REF);
511
ptr.rp_chars += ref_size;
515
if (refs && table_refs) { // Unreferenced BLOBs are ignored.
518
// Set table references.
519
ptr.rp_chars = ((char*) blob) + dt_headerSize;
520
for (int count = 0; count < ref_count; count++) {
521
int ref_type = CS_GET_DISK_2(ptr.rp_ref->rr_type_2);
527
case MS_BLOB_TABLE_REF:
528
tab_id = CS_GET_DISK_4(ptr.rp_tab_ref->tr_table_id_4);
529
blob_id = CS_GET_DISK_6(ptr.rp_tab_ref->tr_blob_id_6);
530
otab = MSTableList::getOpenTableByID(myDB->myDatabaseID, tab_id);
533
otab->getDBTable()->setBlobHandle(otab, blob_id, repo->myRepoID, repo_offset, blob_data_size, dt_headerSize, auth_code);
537
case MS_BLOB_DELETE_REF:
540
case MS_BLOB_FREE_REF:
545
ptr.rp_chars += ref_size;
548
// Write the repository record.
549
repo_file->write(blob, repo_offset, length);
550
repo->myRepoFileSize += length;
552
#ifdef HAVE_ALIAS_SUPPORT
553
uint16_t alias_offset;
554
if (alias_offset = CS_GET_DISK_2(blob->rb_alias_offset_2)) {
555
myDB->registerBlobAlias(repo->myRepoID, repo_offset, ((char*)blob) + alias_offset);
558
if (blob_storage_type == MS_CLOUD_STORAGE) {
559
if (!dt_haveCloudInfo) {
560
CSException::throwException(CS_CONTEXT, MS_ERR_MISSING_CLOUD_REFFERENCE, "Missing cloud backup information.");
562
myDB->myBlobCloud->cl_restoreBLOB(&cloud_key, dt_cloudbackupDBID);
566
backtopool_(repo_file);