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
* Contains the information about a table.
30
#include "cslib/CSConfig.h"
37
#include "cslib/CSGlobal.h"
38
#include "cslib/CSLog.h"
39
#include "cslib/CSPath.h"
40
#include "cslib/CSStrUtil.h"
42
#include "database_ms.h"
43
#include "open_table_ms.h"
63
myTableName->release();
66
#define MS_DELETE_MARK "#DEL#"
67
#define MS_DELETE_MARK_LEN 5
69
CSPath *MSTable::getTableFile(const char *table_name, bool to_delete)
71
char file_name[MS_TABLE_NAME_SIZE + 50];
73
if ((table_name && to_delete) || iToDelete) {
74
cs_strcpy(MS_TABLE_NAME_SIZE + 50, file_name, "bs-logs");
75
// Make sure it exists
76
cs_add_dir_char(MS_TABLE_NAME_SIZE + 50, file_name);
81
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, table_name);
83
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableName->getCString());
85
char *str = file_name + strlen(file_name) - MS_DELETE_MARK_LEN;
87
while (str > file_name) {
88
if (strncmp(str, MS_DELETE_MARK, MS_DELETE_MARK_LEN) == 0) {
96
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, "-");
97
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableID);
98
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, ".bst");
100
return CSPath::newPath(RETAIN(myDatabase->myDatabasePath), file_name);
103
CSPath *MSTable::getTableFile()
105
return getTableFile(NULL, false);
108
CSFile *MSTable::openTableFile()
114
path = getTableFile();
116
fh = iTableFileSize ? path->openFile(CSFile::DEFAULT) : path->openFile(CSFile::CREATE);
118
if (!iTableHeadSize) {
119
MSTableHeadRec tab_head;
122
/* Check again after locking: */
123
if (!iTableHeadSize) {
126
if (fh->read(&tab_head, 0, offsetof(MSTableHeadRec, th_reserved_4), 0) < offsetof(MSTableHeadRec, th_reserved_4)) {
127
CS_SET_DISK_4(tab_head.th_magic_4, MS_TABLE_FILE_MAGIC);
128
CS_SET_DISK_2(tab_head.th_version_2, MS_TABLE_FILE_VERSION);
129
CS_SET_DISK_2(tab_head.th_head_size_2, MS_TABLE_FILE_HEAD_SIZE);
130
CS_SET_DISK_8(tab_head.th_free_list_8, 0);
131
CS_SET_DISK_4(tab_head.th_del_time_4, 0);
132
CS_SET_DISK_4(tab_head.th_temp_log_id_4, 0);
133
CS_SET_DISK_4(tab_head.th_temp_log_offset_4, 0);
134
CS_SET_DISK_4(tab_head.th_reserved_4, 0);
135
fh->write(&tab_head, 0, sizeof(MSTableHeadRec));
138
/* Check the file header: */
139
if (CS_GET_DISK_4(tab_head.th_magic_4) != MS_TABLE_FILE_MAGIC)
140
CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_BAD_HEADER_MAGIC);
141
if (CS_GET_DISK_2(tab_head.th_version_2) > MS_TABLE_FILE_VERSION)
142
CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_VERSION_TOO_NEW);
144
/* Load the header details: */
145
iFreeList = CS_GET_DISK_8(tab_head.th_free_list_8);
146
iTableHeadSize = CS_GET_DISK_2(tab_head.th_head_size_2);
147
iTabDeleteTime = CS_GET_DISK_4(tab_head.th_del_time_4);
148
iTabTempLogID = CS_GET_DISK_4(tab_head.th_temp_log_id_4);
149
iTabTempLogOffset = CS_GET_DISK_4(tab_head.th_temp_log_offset_4);
151
/* Round file size up to a header boundary: */
152
if (iTableFileSize < iTableHeadSize)
153
iTableFileSize = iTableHeadSize;
154
if ((rem = (iTableFileSize - iTableHeadSize) % sizeof(MSTableBlobRec)))
155
iTableFileSize += sizeof(MSTableBlobRec) - rem;
164
void MSTable::prepareToDelete()
167
uint32_t delete_time = 0;
171
otab = MSOpenTable::newOpenTable(NULL);
173
otab->myTableFile = openTableFile();
176
MSTempLogItemRec log_item;
178
log = myDatabase->openTempLogFile(iTabTempLogID, NULL, NULL);
181
if (log->read(&log_item, iTabTempLogOffset, sizeof(MSTempLogItemRec), 0) == sizeof(MSTempLogItemRec)) {
182
delete_time = CS_GET_DISK_4(log_item.ti_time_4);
183
if (delete_time != iTabDeleteTime)
191
MSTableHeadRec tab_head;
193
myDatabase->queueForDeletion(otab, MS_TL_TABLE_REF, myTableID, 0, 0, &iTabTempLogID, &iTabTempLogOffset, &iTabDeleteTime);
194
CS_SET_DISK_4(tab_head.th_del_time_4, iTabDeleteTime);
195
CS_SET_DISK_4(tab_head.th_temp_log_id_4, iTabTempLogID);
196
CS_SET_DISK_4(tab_head.th_temp_log_offset_4, iTabTempLogOffset);
197
otab->myTableFile->write(&tab_head.th_del_time_4, offsetof(MSTableHeadRec, th_del_time_4), 12);
204
uint64_t MSTable::findBlobHandle(MSOpenTable *otab, uint32_t repo_id, uint64_t file_offset, uint64_t size, uint16_t head_size, uint32_t auth_code)
206
uint64_t blob_id = 0;
207
off64_t offset = iTableHeadSize;
212
while (offset < iTableFileSize && !blob_id) {
213
otab->myTableFile->read(&blob, offset, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
214
if ( (CS_GET_DISK_1(blob.tb_status_1) == 1) &&
215
(CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id) &&
216
(CS_GET_DISK_6(blob.tb_offset_6) == file_offset) &&
217
(CS_GET_DISK_6(blob.tb_size_6) == size) &&
218
(CS_GET_DISK_2(blob.tb_header_size_2) == head_size) &&
219
(CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) ) {
223
offset += sizeof(MSTableBlobRec);
229
uint64_t MSTable::createBlobHandle(MSOpenTable *otab, uint32_t repo_id, uint64_t file_offset, uint64_t size, uint16_t head_size, uint32_t auth_code)
237
MSTableFreeBlobRec freeb;
238
MSTableHeadRec tab_head;
241
otab->myTableFile->read(&freeb, iFreeList, sizeof(MSTableFreeBlobRec), sizeof(MSTableFreeBlobRec));
242
iFreeList = CS_GET_DISK_6(freeb.tf_next_6);
243
CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
244
otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
247
blob_id = iTableFileSize;
248
iTableFileSize += sizeof(MSTableBlobRec);
252
CS_SET_DISK_1(blob.tb_status_1, 1);
253
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
254
CS_SET_DISK_6(blob.tb_offset_6, file_offset);
255
CS_SET_DISK_6(blob.tb_size_6, size);
256
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
257
CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
258
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
263
void MSTable::setBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t file_offset, uint64_t size, uint16_t head_size, uint32_t auth_code)
267
if (!otab->myTableFile && !otab->isNotATable)
268
otab->myTableFile = openTableFile();
270
CS_SET_DISK_1(blob.tb_status_1, 1);
271
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
272
CS_SET_DISK_6(blob.tb_offset_6, file_offset);
273
CS_SET_DISK_6(blob.tb_size_6, size);
274
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
275
CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
276
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
279
void MSTable::updateBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t offset, uint16_t head_size)
283
if (!otab->myTableFile && !otab->isNotATable)
284
otab->myTableFile = openTableFile();
286
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
287
CS_SET_DISK_6(blob.tb_offset_6, offset);
289
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
290
otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 11);
293
otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 9);
296
bool MSTable::readBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t *auth_code,
297
uint32_t *repo_id, uint64_t *offset, uint64_t *data_size, uint16_t *head_size, bool throw_error)
302
if (!otab->myTableFile && !otab->isNotATable)
303
otab->myTableFile = openTableFile();
305
otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
306
if (!(*repo_id = CS_GET_DISK_3(blob.tb_repo_id_3))) {
308
CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been freed");
311
*offset = CS_GET_DISK_6(blob.tb_offset_6);
312
*data_size = CS_GET_DISK_6(blob.tb_size_6);
313
*head_size = CS_GET_DISK_2(blob.tb_header_size_2);
314
ac = CS_GET_DISK_4(blob.tb_auth_code_4);
317
else if (*auth_code != ac) {
319
CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
325
void MSTable::freeBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t file_offset, uint32_t auth_code)
328
MSTableFreeBlobPtr fblob = (MSTableFreeBlobPtr) &blob;
329
MSTableHeadRec tab_head;
332
otab->openForReading();
333
otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
334
if (CS_GET_DISK_1(blob.tb_status_1) == 1 &&
335
CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id &&
336
CS_GET_DISK_6(blob.tb_offset_6) == file_offset &&
337
CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) {
339
memset(&blob, 0, sizeof(MSTableBlobRec));
340
CS_SET_DISK_6(fblob->tf_next_6, iFreeList);
342
CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
343
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
344
otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
350
CSObject *MSTable::getKey()
352
return (CSObject *) myTableName;
355
int MSTable::compareKey(CSObject *key)
357
return myTableName->compare((CSString *) key);
360
uint32_t MSTable::hashKey()
362
return myTableName->hashKey();
365
CSString *MSTable::getTableName()
370
void MSTable::getDeleteInfo(uint32_t *log, uint32_t *offs, time_t *tim)
372
if (!iTableHeadSize) {
375
fh = openTableFile();
379
*log = iTabTempLogID;
380
*offs = iTabTempLogOffset;
381
*tim = iTabDeleteTime;
384
MSTable *MSTable::newTable(uint32_t tab_id, CSString *tab_name, MSDatabase *db, off64_t file_size, bool to_delete)
388
if (!(tab = new MSTable())) {
390
CSException::throwOSError(CS_CONTEXT, ENOMEM);
393
/* Create a new table name: */
394
char name_buffer[MS_TABLE_NAME_SIZE + 40];
396
cs_strcpy(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_name->getCString());
397
cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, MS_DELETE_MARK);
398
cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_id);
400
tab_name = CSString::newString(name_buffer);
403
tab->myTableID = tab_id;
404
tab->myTableName = tab_name;
405
tab->myDatabase = db;
406
tab->iTableFileSize = file_size;
407
tab->iToDelete = to_delete;
411
MSTable *MSTable::newTable(uint32_t tab_id, const char *name, MSDatabase *db, off64_t file_size, bool to_delete)
413
return newTable(tab_id, CSString::newString(name), db, file_size, to_delete);