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.
37
#include "CSStrUtil.h"
39
#include "Database_ms.h"
40
#include "OpenTable_ms.h"
60
myTableName->release();
63
#define MS_DELETE_MARK "#DEL#"
64
#define MS_DELETE_MARK_LEN 5
66
CSPath *MSTable::getTableFile(const char *table_name, bool to_delete)
68
char file_name[MS_TABLE_NAME_SIZE + 50];
70
if ((table_name && to_delete) || iToDelete) {
71
cs_strcpy(MS_TABLE_NAME_SIZE + 50, file_name, "bs-logs");
72
// Make sure it exists
73
cs_add_dir_char(MS_TABLE_NAME_SIZE + 50, file_name);
78
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, table_name);
80
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableName->getCString());
82
char *str = file_name + strlen(file_name) - MS_DELETE_MARK_LEN;
84
while (str > file_name) {
85
if (strncmp(str, MS_DELETE_MARK, MS_DELETE_MARK_LEN) == 0) {
93
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, "-");
94
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableID);
95
cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, ".bst");
97
return CSPath::newPath(RETAIN(myDatabase->myDatabasePath), file_name);
100
CSPath *MSTable::getTableFile()
102
return getTableFile(NULL, false);
105
CSFile *MSTable::openTableFile()
111
path = getTableFile();
113
fh = iTableFileSize ? path->openFile(CSFile::DEFAULT) : path->openFile(CSFile::CREATE);
115
if (!iTableHeadSize) {
116
MSTableHeadRec tab_head;
119
/* Check again after locking: */
120
if (!iTableHeadSize) {
123
if (fh->read(&tab_head, 0, offsetof(MSTableHeadRec, th_reserved_4), 0) < offsetof(MSTableHeadRec, th_reserved_4)) {
124
CS_SET_DISK_4(tab_head.th_magic_4, MS_TABLE_FILE_MAGIC);
125
CS_SET_DISK_2(tab_head.th_version_2, MS_TABLE_FILE_VERSION);
126
CS_SET_DISK_2(tab_head.th_head_size_2, MS_TABLE_FILE_HEAD_SIZE);
127
CS_SET_DISK_8(tab_head.th_free_list_8, 0);
128
CS_SET_DISK_4(tab_head.th_del_time_4, 0);
129
CS_SET_DISK_4(tab_head.th_temp_log_id_4, 0);
130
CS_SET_DISK_4(tab_head.th_temp_log_offset_4, 0);
131
CS_SET_DISK_4(tab_head.th_reserved_4, 0);
132
fh->write(&tab_head, 0, sizeof(MSTableHeadRec));
135
/* Check the file header: */
136
if (CS_GET_DISK_4(tab_head.th_magic_4) != MS_TABLE_FILE_MAGIC)
137
CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_BAD_HEADER_MAGIC);
138
if (CS_GET_DISK_2(tab_head.th_version_2) > MS_TABLE_FILE_VERSION)
139
CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_VERSION_TOO_NEW);
141
/* Load the header details: */
142
iFreeList = CS_GET_DISK_8(tab_head.th_free_list_8);
143
iTableHeadSize = CS_GET_DISK_2(tab_head.th_head_size_2);
144
iTabDeleteTime = CS_GET_DISK_4(tab_head.th_del_time_4);
145
iTabTempLogID = CS_GET_DISK_4(tab_head.th_temp_log_id_4);
146
iTabTempLogOffset = CS_GET_DISK_4(tab_head.th_temp_log_offset_4);
148
/* Round file size up to a header boundary: */
149
if (iTableFileSize < iTableHeadSize)
150
iTableFileSize = iTableHeadSize;
151
if ((rem = (iTableFileSize - iTableHeadSize) % sizeof(MSTableBlobRec)))
152
iTableFileSize += sizeof(MSTableBlobRec) - rem;
161
void MSTable::prepareToDelete()
164
uint32_t delete_time = 0;
168
otab = MSOpenTable::newOpenTable(NULL);
170
otab->myTableFile = openTableFile();
173
MSTempLogItemRec log_item;
175
log = myDatabase->openTempLogFile(iTabTempLogID, NULL, NULL);
178
if (log->read(&log_item, iTabTempLogOffset, sizeof(MSTempLogItemRec), 0) == sizeof(MSTempLogItemRec)) {
179
delete_time = CS_GET_DISK_4(log_item.ti_time_4);
180
if (delete_time != iTabDeleteTime)
188
MSTableHeadRec tab_head;
190
myDatabase->queueForDeletion(otab, MS_TL_TABLE_REF, myTableID, 0, 0, &iTabTempLogID, &iTabTempLogOffset, &iTabDeleteTime);
191
CS_SET_DISK_4(tab_head.th_del_time_4, iTabDeleteTime);
192
CS_SET_DISK_4(tab_head.th_temp_log_id_4, iTabTempLogID);
193
CS_SET_DISK_4(tab_head.th_temp_log_offset_4, iTabTempLogOffset);
194
otab->myTableFile->write(&tab_head.th_del_time_4, offsetof(MSTableHeadRec, th_del_time_4), 12);
201
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)
203
uint64_t blob_id = 0;
204
off_t offset = iTableHeadSize;
209
while (offset < iTableFileSize && !blob_id) {
210
otab->myTableFile->read(&blob, offset, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
211
if ( (CS_GET_DISK_1(blob.tb_status_1) == 1) &&
212
(CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id) &&
213
(CS_GET_DISK_6(blob.tb_offset_6) == file_offset) &&
214
(CS_GET_DISK_6(blob.tb_size_6) == size) &&
215
(CS_GET_DISK_2(blob.tb_header_size_2) == head_size) &&
216
(CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) ) {
220
offset += sizeof(MSTableBlobRec);
226
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)
234
MSTableFreeBlobRec freeb;
235
MSTableHeadRec tab_head;
238
otab->myTableFile->read(&freeb, iFreeList, sizeof(MSTableFreeBlobRec), sizeof(MSTableFreeBlobRec));
239
iFreeList = CS_GET_DISK_6(freeb.tf_next_6);
240
CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
241
otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
244
blob_id = iTableFileSize;
245
iTableFileSize += sizeof(MSTableBlobRec);
249
CS_SET_DISK_1(blob.tb_status_1, 1);
250
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
251
CS_SET_DISK_6(blob.tb_offset_6, file_offset);
252
CS_SET_DISK_6(blob.tb_size_6, size);
253
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
254
CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
255
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
260
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)
264
if (!otab->myTableFile && !otab->isNotATable)
265
otab->myTableFile = openTableFile();
267
CS_SET_DISK_1(blob.tb_status_1, 1);
268
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
269
CS_SET_DISK_6(blob.tb_offset_6, file_offset);
270
CS_SET_DISK_6(blob.tb_size_6, size);
271
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
272
CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
273
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
276
void MSTable::updateBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t offset, uint16_t head_size)
280
if (!otab->myTableFile && !otab->isNotATable)
281
otab->myTableFile = openTableFile();
283
CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
284
CS_SET_DISK_6(blob.tb_offset_6, offset);
286
CS_SET_DISK_2(blob.tb_header_size_2, head_size);
287
otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 11);
290
otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 9);
293
bool MSTable::readBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t *auth_code,
294
uint32_t *repo_id, uint64_t *offset, uint64_t *data_size, uint16_t *head_size, bool throw_error)
299
if (!otab->myTableFile && !otab->isNotATable)
300
otab->myTableFile = openTableFile();
302
otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
303
if (!(*repo_id = CS_GET_DISK_3(blob.tb_repo_id_3))) {
305
CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been freed");
308
*offset = CS_GET_DISK_6(blob.tb_offset_6);
309
*data_size = CS_GET_DISK_6(blob.tb_size_6);
310
*head_size = CS_GET_DISK_2(blob.tb_header_size_2);
311
ac = CS_GET_DISK_4(blob.tb_auth_code_4);
314
else if (*auth_code != ac) {
316
CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
322
void MSTable::freeBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t file_offset, uint32_t auth_code)
325
MSTableFreeBlobPtr fblob = (MSTableFreeBlobPtr) &blob;
326
MSTableHeadRec tab_head;
329
otab->openForReading();
330
otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
331
if (CS_GET_DISK_1(blob.tb_status_1) == 1 &&
332
CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id &&
333
CS_GET_DISK_6(blob.tb_offset_6) == file_offset &&
334
CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) {
336
memset(&blob, 0, sizeof(MSTableBlobRec));
337
CS_SET_DISK_6(fblob->tf_next_6, iFreeList);
339
CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
340
otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
341
otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
347
CSObject *MSTable::getKey()
349
return (CSObject *) myTableName;
352
int MSTable::compareKey(CSObject *key)
354
return myTableName->compare((CSString *) key);
357
u_int MSTable::hashKey()
359
return myTableName->hashKey();
362
CSString *MSTable::getTableName()
367
void MSTable::getDeleteInfo(uint32_t *log, uint32_t *offs, time_t *tim)
369
if (!iTableHeadSize) {
372
fh = openTableFile();
376
*log = iTabTempLogID;
377
*offs = iTabTempLogOffset;
378
*tim = iTabDeleteTime;
381
MSTable *MSTable::newTable(uint32_t tab_id, CSString *tab_name, MSDatabase *db, off_t file_size, bool to_delete)
385
if (!(tab = new MSTable())) {
387
CSException::throwOSError(CS_CONTEXT, ENOMEM);
390
/* Create a new table name: */
391
char name_buffer[MS_TABLE_NAME_SIZE + 40];
393
cs_strcpy(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_name->getCString());
394
cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, MS_DELETE_MARK);
395
cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_id);
397
tab_name = CSString::newString(name_buffer);
400
tab->myTableID = tab_id;
401
tab->myTableName = tab_name;
402
tab->myDatabase = db;
403
tab->iTableFileSize = file_size;
404
tab->iToDelete = to_delete;
408
MSTable *MSTable::newTable(uint32_t tab_id, const char *name, MSDatabase *db, off_t file_size, bool to_delete)
410
return newTable(tab_id, CSString::newString(name), db, file_size, to_delete);