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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* Original author: Paul McCullagh
20
* Continued development: Barry Leslie
26
* Contains the information about a table.
30
#include "cslib/CSConfig.h"
35
#include "cslib/CSGlobal.h"
36
#include "cslib/CSLog.h"
37
#include "cslib/CSPath.h"
38
#include "cslib/CSStrUtil.h"
40
#include "database_ms.h"
41
#include "open_table_ms.h"
61
myTableName->release();
64
#define MS_DELETE_MARK "#DEL#"
65
#define MS_DELETE_MARK_LEN 5
67
CSPath *MSTable::getTableFile(const char *table_name, bool to_delete)
69
char file_name[MS_TABLE_NAME_SIZE + 50];
71
if ((table_name && to_delete) || iToDelete) {
72
cs_strcpy(MS_TABLE_NAME_SIZE + 50, file_name, "bs-logs");
73
// Make sure it exists
74
cs_add_dir_char(MS_TABLE_NAME_SIZE + 50, file_name);
79
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, table_name);
81
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableName->getCString());
83
char *str = file_name + strlen(file_name) - MS_DELETE_MARK_LEN;
85
while (str > file_name) {
86
if (strncmp(str, MS_DELETE_MARK, MS_DELETE_MARK_LEN) == 0) {
94
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, "-");
95
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableID);
96
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, ".bst");
98
return CSPath::newPath(RETAIN(myDatabase->myDatabasePath), file_name);
101
CSPath *MSTable::getTableFile()
103
return getTableFile(NULL, false);
106
CSFile *MSTable::openTableFile()
112
path = getTableFile();
114
fh = iTableFileSize ? path->openFile(CSFile::DEFAULT) : path->openFile(CSFile::CREATE);
116
if (!iTableHeadSize) {
117
MSTableHeadRec tab_head;
120
/* Check again after locking: */
121
if (!iTableHeadSize) {
124
if (fh->read(&tab_head, 0, offsetof(MSTableHeadRec, th_reserved_4), 0) < offsetof(MSTableHeadRec, th_reserved_4)) {
125
CS_SET_DISK_4(tab_head.th_magic_4, MS_TABLE_FILE_MAGIC);
126
CS_SET_DISK_2(tab_head.th_version_2, MS_TABLE_FILE_VERSION);
127
CS_SET_DISK_2(tab_head.th_head_size_2, MS_TABLE_FILE_HEAD_SIZE);
128
CS_SET_DISK_8(tab_head.th_free_list_8, 0);
129
CS_SET_DISK_4(tab_head.th_del_time_4, 0);
130
CS_SET_DISK_4(tab_head.th_temp_log_id_4, 0);
131
CS_SET_DISK_4(tab_head.th_temp_log_offset_4, 0);
132
CS_SET_DISK_4(tab_head.th_reserved_4, 0);
133
fh->write(&tab_head, 0, sizeof(MSTableHeadRec));
136
/* Check the file header: */
137
if (CS_GET_DISK_4(tab_head.th_magic_4) != MS_TABLE_FILE_MAGIC)
138
CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_BAD_HEADER_MAGIC);
139
if (CS_GET_DISK_2(tab_head.th_version_2) > MS_TABLE_FILE_VERSION)
140
CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_VERSION_TOO_NEW);
142
/* Load the header details: */
143
iFreeList = CS_GET_DISK_8(tab_head.th_free_list_8);
144
iTableHeadSize = CS_GET_DISK_2(tab_head.th_head_size_2);
145
iTabDeleteTime = CS_GET_DISK_4(tab_head.th_del_time_4);
146
iTabTempLogID = CS_GET_DISK_4(tab_head.th_temp_log_id_4);
147
iTabTempLogOffset = CS_GET_DISK_4(tab_head.th_temp_log_offset_4);
149
/* Round file size up to a header boundary: */
150
if (iTableFileSize < iTableHeadSize)
151
iTableFileSize = iTableHeadSize;
152
if ((rem = (iTableFileSize - iTableHeadSize) % sizeof(MSTableBlobRec)))
153
iTableFileSize += sizeof(MSTableBlobRec) - rem;
162
void MSTable::prepareToDelete()
165
uint32_t delete_time = 0;
169
otab = MSOpenTable::newOpenTable(NULL);
171
otab->myTableFile = openTableFile();
174
MSTempLogItemRec log_item;
176
log = myDatabase->openTempLogFile(iTabTempLogID, NULL, NULL);
179
if (log->read(&log_item, iTabTempLogOffset, sizeof(MSTempLogItemRec), 0) == sizeof(MSTempLogItemRec)) {
180
delete_time = CS_GET_DISK_4(log_item.ti_time_4);
181
if (delete_time != iTabDeleteTime)
189
MSTableHeadRec tab_head;
191
myDatabase->queueForDeletion(otab, MS_TL_TABLE_REF, myTableID, 0, 0, &iTabTempLogID, &iTabTempLogOffset, &iTabDeleteTime);
192
CS_SET_DISK_4(tab_head.th_del_time_4, iTabDeleteTime);
193
CS_SET_DISK_4(tab_head.th_temp_log_id_4, iTabTempLogID);
194
CS_SET_DISK_4(tab_head.th_temp_log_offset_4, iTabTempLogOffset);
195
otab->myTableFile->write(&tab_head.th_del_time_4, offsetof(MSTableHeadRec, th_del_time_4), 12);
202
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)
204
uint64_t blob_id = 0;
205
off64_t offset = iTableHeadSize;
210
while (offset < iTableFileSize && !blob_id) {
211
otab->myTableFile->read(&blob, offset, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
212
if ( (CS_GET_DISK_1(blob.tb_status_1) == 1) &&
213
(CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id) &&
214
(CS_GET_DISK_6(blob.tb_offset_6) == file_offset) &&
215
(CS_GET_DISK_6(blob.tb_size_6) == size) &&
216
(CS_GET_DISK_2(blob.tb_header_size_2) == head_size) &&
217
(CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) ) {
221
offset += sizeof(MSTableBlobRec);
227
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)
235
MSTableFreeBlobRec freeb;
236
MSTableHeadRec tab_head;
239
otab->myTableFile->read(&freeb, iFreeList, sizeof(MSTableFreeBlobRec), sizeof(MSTableFreeBlobRec));
240
iFreeList = CS_GET_DISK_6(freeb.tf_next_6);
241
CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
242
otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
245
blob_id = iTableFileSize;
246
iTableFileSize += sizeof(MSTableBlobRec);
250
CS_SET_DISK_1(blob.tb_status_1, 1);
251
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
252
CS_SET_DISK_6(blob.tb_offset_6, file_offset);
253
CS_SET_DISK_6(blob.tb_size_6, size);
254
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
255
CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
256
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
261
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)
265
if (!otab->myTableFile && !otab->isNotATable)
266
otab->myTableFile = openTableFile();
268
CS_SET_DISK_1(blob.tb_status_1, 1);
269
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
270
CS_SET_DISK_6(blob.tb_offset_6, file_offset);
271
CS_SET_DISK_6(blob.tb_size_6, size);
272
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
273
CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
274
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
277
void MSTable::updateBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t offset, uint16_t head_size)
281
if (!otab->myTableFile && !otab->isNotATable)
282
otab->myTableFile = openTableFile();
284
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
285
CS_SET_DISK_6(blob.tb_offset_6, offset);
287
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
288
otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 11);
291
otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 9);
294
bool MSTable::readBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t *auth_code,
295
uint32_t *repo_id, uint64_t *offset, uint64_t *data_size, uint16_t *head_size, bool throw_error)
300
if (!otab->myTableFile && !otab->isNotATable)
301
otab->myTableFile = openTableFile();
303
otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
304
if (!(*repo_id = CS_GET_DISK_3(blob.tb_repo_id_3))) {
306
CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been freed");
309
*offset = CS_GET_DISK_6(blob.tb_offset_6);
310
*data_size = CS_GET_DISK_6(blob.tb_size_6);
311
*head_size = CS_GET_DISK_2(blob.tb_header_size_2);
312
ac = CS_GET_DISK_4(blob.tb_auth_code_4);
315
else if (*auth_code != ac) {
317
CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
323
void MSTable::freeBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t file_offset, uint32_t auth_code)
326
MSTableFreeBlobPtr fblob = (MSTableFreeBlobPtr) &blob;
327
MSTableHeadRec tab_head;
330
otab->openForReading();
331
otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
332
if (CS_GET_DISK_1(blob.tb_status_1) == 1 &&
333
CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id &&
334
CS_GET_DISK_6(blob.tb_offset_6) == file_offset &&
335
CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) {
337
memset(&blob, 0, sizeof(MSTableBlobRec));
338
CS_SET_DISK_6(fblob->tf_next_6, iFreeList);
340
CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
341
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
342
otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
348
CSObject *MSTable::getKey()
350
return (CSObject *) myTableName;
353
int MSTable::compareKey(CSObject *key)
355
return myTableName->compare((CSString *) key);
358
uint32_t MSTable::hashKey()
360
return myTableName->hashKey();
363
CSString *MSTable::getTableName()
368
void MSTable::getDeleteInfo(uint32_t *log, uint32_t *offs, time_t *tim)
370
if (!iTableHeadSize) {
373
fh = openTableFile();
377
*log = iTabTempLogID;
378
*offs = iTabTempLogOffset;
379
*tim = iTabDeleteTime;
382
MSTable *MSTable::newTable(uint32_t tab_id, CSString *tab_name, MSDatabase *db, off64_t file_size, bool to_delete)
386
if (!(tab = new MSTable())) {
388
CSException::throwOSError(CS_CONTEXT, ENOMEM);
391
/* Create a new table name: */
392
char name_buffer[MS_TABLE_NAME_SIZE + 40];
394
cs_strcpy(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_name->getCString());
395
cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, MS_DELETE_MARK);
396
cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_id);
398
tab_name = CSString::newString(name_buffer);
401
tab->myTableID = tab_id;
402
tab->myTableName = tab_name;
403
tab->myDatabase = db;
404
tab->iTableFileSize = file_size;
405
tab->iToDelete = to_delete;
409
MSTable *MSTable::newTable(uint32_t tab_id, const char *name, MSDatabase *db, off64_t file_size, bool to_delete)
411
return newTable(tab_id, CSString::newString(name), db, file_size, to_delete);