00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "cslib/CSConfig.h"
00031
00032 #include <stdlib.h>
00033 #include <stddef.h>
00034
00035 #include "defs_ms.h"
00036
00037 #include "cslib/CSGlobal.h"
00038 #include "cslib/CSLog.h"
00039 #include "cslib/CSPath.h"
00040 #include "cslib/CSStrUtil.h"
00041
00042 #include "database_ms.h"
00043 #include "open_table_ms.h"
00044
00045 MSTable::MSTable():
00046 CSSharedRefObject(),
00047 myTableName(NULL),
00048 myTableID(0),
00049 myDatabase(NULL),
00050 iTableFileSize(0),
00051 iTableHeadSize(0),
00052 iFreeList(0),
00053 iToDelete(0),
00054 iTabDeleteTime(0),
00055 iTabTempLogID(0),
00056 iTabTempLogOffset(0)
00057 {
00058 }
00059
00060 MSTable::~MSTable()
00061 {
00062 if (myTableName)
00063 myTableName->release();
00064 }
00065
00066 #define MS_DELETE_MARK "#DEL#"
00067 #define MS_DELETE_MARK_LEN 5
00068
00069 CSPath *MSTable::getTableFile(const char *table_name, bool to_delete)
00070 {
00071 char file_name[MS_TABLE_NAME_SIZE + 50];
00072
00073 if ((table_name && to_delete) || iToDelete) {
00074 cs_strcpy(MS_TABLE_NAME_SIZE + 50, file_name, "bs-logs");
00075
00076 cs_add_dir_char(MS_TABLE_NAME_SIZE + 50, file_name);
00077 }
00078 else
00079 *file_name = 0;
00080 if (table_name)
00081 cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, table_name);
00082 else {
00083 cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableName->getCString());
00084 if (iToDelete) {
00085 char *str = file_name + strlen(file_name) - MS_DELETE_MARK_LEN;
00086
00087 while (str > file_name) {
00088 if (strncmp(str, MS_DELETE_MARK, MS_DELETE_MARK_LEN) == 0) {
00089 *str = 0;
00090 break;
00091 }
00092 str--;
00093 }
00094 }
00095 }
00096 cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, "-");
00097 cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, myTableID);
00098 cs_strcat(MS_TABLE_NAME_SIZE + 50, file_name, ".bst");
00099
00100 return CSPath::newPath(RETAIN(myDatabase->myDatabasePath), file_name);
00101 }
00102
00103 CSPath *MSTable::getTableFile()
00104 {
00105 return getTableFile(NULL, false);
00106 }
00107
00108 CSFile *MSTable::openTableFile()
00109 {
00110 CSPath *path;
00111 CSFile *fh;
00112
00113 enter_();
00114 path = getTableFile();
00115 push_(path);
00116 fh = iTableFileSize ? path->openFile(CSFile::DEFAULT) : path->openFile(CSFile::CREATE);
00117 push_(fh);
00118 if (!iTableHeadSize) {
00119 MSTableHeadRec tab_head;
00120
00121 lock_(this);
00122
00123 if (!iTableHeadSize) {
00124 size_t rem;
00125
00126 if (fh->read(&tab_head, 0, offsetof(MSTableHeadRec, th_reserved_4), 0) < offsetof(MSTableHeadRec, th_reserved_4)) {
00127 CS_SET_DISK_4(tab_head.th_magic_4, MS_TABLE_FILE_MAGIC);
00128 CS_SET_DISK_2(tab_head.th_version_2, MS_TABLE_FILE_VERSION);
00129 CS_SET_DISK_2(tab_head.th_head_size_2, MS_TABLE_FILE_HEAD_SIZE);
00130 CS_SET_DISK_8(tab_head.th_free_list_8, 0);
00131 CS_SET_DISK_4(tab_head.th_del_time_4, 0);
00132 CS_SET_DISK_4(tab_head.th_temp_log_id_4, 0);
00133 CS_SET_DISK_4(tab_head.th_temp_log_offset_4, 0);
00134 CS_SET_DISK_4(tab_head.th_reserved_4, 0);
00135 fh->write(&tab_head, 0, sizeof(MSTableHeadRec));
00136 }
00137
00138
00139 if (CS_GET_DISK_4(tab_head.th_magic_4) != MS_TABLE_FILE_MAGIC)
00140 CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_BAD_HEADER_MAGIC);
00141 if (CS_GET_DISK_2(tab_head.th_version_2) > MS_TABLE_FILE_VERSION)
00142 CSException::throwFileError(CS_CONTEXT, path->getString(), CS_ERR_VERSION_TOO_NEW);
00143
00144
00145 iFreeList = CS_GET_DISK_8(tab_head.th_free_list_8);
00146 iTableHeadSize = CS_GET_DISK_2(tab_head.th_head_size_2);
00147 iTabDeleteTime = CS_GET_DISK_4(tab_head.th_del_time_4);
00148 iTabTempLogID = CS_GET_DISK_4(tab_head.th_temp_log_id_4);
00149 iTabTempLogOffset = CS_GET_DISK_4(tab_head.th_temp_log_offset_4);
00150
00151
00152 if (iTableFileSize < iTableHeadSize)
00153 iTableFileSize = iTableHeadSize;
00154 if ((rem = (iTableFileSize - iTableHeadSize) % sizeof(MSTableBlobRec)))
00155 iTableFileSize += sizeof(MSTableBlobRec) - rem;
00156 }
00157 unlock_(this);
00158 }
00159 pop_(fh);
00160 release_(path);
00161 return_(fh);
00162 }
00163
00164 void MSTable::prepareToDelete()
00165 {
00166 MSOpenTable *otab;
00167 uint32_t delete_time = 0;
00168
00169 enter_();
00170 iToDelete = true;
00171 otab = MSOpenTable::newOpenTable(NULL);
00172 push_(otab);
00173 otab->myTableFile = openTableFile();
00174 if (iTabTempLogID) {
00175 MSTempLogFile *log;
00176 MSTempLogItemRec log_item;
00177
00178 log = myDatabase->openTempLogFile(iTabTempLogID, NULL, NULL);
00179 if (log) {
00180 push_(log);
00181 if (log->read(&log_item, iTabTempLogOffset, sizeof(MSTempLogItemRec), 0) == sizeof(MSTempLogItemRec)) {
00182 delete_time = CS_GET_DISK_4(log_item.ti_time_4);
00183 if (delete_time != iTabDeleteTime)
00184 delete_time = 0;
00185 }
00186 release_(log);
00187 }
00188 }
00189
00190 if (!delete_time) {
00191 MSTableHeadRec tab_head;
00192
00193 myDatabase->queueForDeletion(otab, MS_TL_TABLE_REF, myTableID, 0, 0, &iTabTempLogID, &iTabTempLogOffset, &iTabDeleteTime);
00194 CS_SET_DISK_4(tab_head.th_del_time_4, iTabDeleteTime);
00195 CS_SET_DISK_4(tab_head.th_temp_log_id_4, iTabTempLogID);
00196 CS_SET_DISK_4(tab_head.th_temp_log_offset_4, iTabTempLogOffset);
00197 otab->myTableFile->write(&tab_head.th_del_time_4, offsetof(MSTableHeadRec, th_del_time_4), 12);
00198 }
00199
00200 release_(otab);
00201 exit_();
00202 }
00203
00204 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)
00205 {
00206 uint64_t blob_id = 0;
00207 off64_t offset = iTableHeadSize;
00208 MSTableBlobRec blob;
00209 enter_();
00210 lock_(this);
00211
00212 while (offset < iTableFileSize && !blob_id) {
00213 otab->myTableFile->read(&blob, offset, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
00214 if ( (CS_GET_DISK_1(blob.tb_status_1) == 1) &&
00215 (CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id) &&
00216 (CS_GET_DISK_6(blob.tb_offset_6) == file_offset) &&
00217 (CS_GET_DISK_6(blob.tb_size_6) == size) &&
00218 (CS_GET_DISK_2(blob.tb_header_size_2) == head_size) &&
00219 (CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) ) {
00220
00221 blob_id = offset;
00222 }
00223 offset += sizeof(MSTableBlobRec);
00224 }
00225 unlock_(this);
00226 return_(blob_id);
00227 }
00228
00229 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)
00230 {
00231 uint64_t blob_id;
00232 MSTableBlobRec blob;
00233
00234 enter_();
00235 lock_(this);
00236 if (iFreeList) {
00237 MSTableFreeBlobRec freeb;
00238 MSTableHeadRec tab_head;
00239
00240 blob_id = iFreeList;
00241 otab->myTableFile->read(&freeb, iFreeList, sizeof(MSTableFreeBlobRec), sizeof(MSTableFreeBlobRec));
00242 iFreeList = CS_GET_DISK_6(freeb.tf_next_6);
00243 CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
00244 otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
00245 }
00246 else {
00247 blob_id = iTableFileSize;
00248 iTableFileSize += sizeof(MSTableBlobRec);
00249 }
00250 unlock_(this);
00251
00252 CS_SET_DISK_1(blob.tb_status_1, 1);
00253 CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
00254 CS_SET_DISK_6(blob.tb_offset_6, file_offset);
00255 CS_SET_DISK_6(blob.tb_size_6, size);
00256 CS_SET_DISK_2(blob.tb_header_size_2, head_size);
00257 CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
00258 otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
00259
00260 return_(blob_id);
00261 }
00262
00263 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)
00264 {
00265 MSTableBlobRec blob;
00266
00267 if (!otab->myTableFile && !otab->isNotATable)
00268 otab->myTableFile = openTableFile();
00269
00270 CS_SET_DISK_1(blob.tb_status_1, 1);
00271 CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
00272 CS_SET_DISK_6(blob.tb_offset_6, file_offset);
00273 CS_SET_DISK_6(blob.tb_size_6, size);
00274 CS_SET_DISK_2(blob.tb_header_size_2, head_size);
00275 CS_SET_DISK_4(blob.tb_auth_code_4, auth_code);
00276 otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
00277 }
00278
00279 void MSTable::updateBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t offset, uint16_t head_size)
00280 {
00281 MSTableBlobRec blob;
00282
00283 if (!otab->myTableFile && !otab->isNotATable)
00284 otab->myTableFile = openTableFile();
00285
00286 CS_SET_DISK_3(blob.tb_repo_id_3, repo_id);
00287 CS_SET_DISK_6(blob.tb_offset_6, offset);
00288 if (head_size) {
00289 CS_SET_DISK_2(blob.tb_header_size_2, head_size);
00290 otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 11);
00291 }
00292 else
00293 otab->myTableFile->write(&blob.tb_repo_id_3, blob_id + offsetof(MSTableBlobRec, tb_repo_id_3), 9);
00294 }
00295
00296 bool MSTable::readBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t *auth_code,
00297 uint32_t *repo_id, uint64_t *offset, uint64_t *data_size, uint16_t *head_size, bool throw_error)
00298 {
00299 MSTableBlobRec blob;
00300 uint32_t ac;
00301
00302 if (!otab->myTableFile && !otab->isNotATable)
00303 otab->myTableFile = openTableFile();
00304
00305 otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
00306 if (!(*repo_id = CS_GET_DISK_3(blob.tb_repo_id_3))) {
00307 if (throw_error)
00308 CSException::throwException(CS_CONTEXT, MS_ERR_NOT_FOUND, "BLOB has already been freed");
00309 return false;
00310 }
00311 *offset = CS_GET_DISK_6(blob.tb_offset_6);
00312 *data_size = CS_GET_DISK_6(blob.tb_size_6);
00313 *head_size = CS_GET_DISK_2(blob.tb_header_size_2);
00314 ac = CS_GET_DISK_4(blob.tb_auth_code_4);
00315 if (!*auth_code)
00316 *auth_code = ac;
00317 else if (*auth_code != ac) {
00318 if (throw_error)
00319 CSException::throwException(CS_CONTEXT, MS_ERR_AUTH_FAILED, "Invalid BLOB identifier");
00320 return false;
00321 }
00322 return true;
00323 }
00324
00325 void MSTable::freeBlobHandle(MSOpenTable *otab, uint64_t blob_id, uint32_t repo_id, uint64_t file_offset, uint32_t auth_code)
00326 {
00327 MSTableBlobRec blob;
00328 MSTableFreeBlobPtr fblob = (MSTableFreeBlobPtr) &blob;
00329 MSTableHeadRec tab_head;
00330
00331 enter_();
00332 otab->openForReading();
00333 otab->myTableFile->read(&blob, blob_id, sizeof(MSTableBlobRec), sizeof(MSTableBlobRec));
00334 if (CS_GET_DISK_1(blob.tb_status_1) == 1 &&
00335 CS_GET_DISK_3(blob.tb_repo_id_3) == repo_id &&
00336 CS_GET_DISK_6(blob.tb_offset_6) == file_offset &&
00337 CS_GET_DISK_4(blob.tb_auth_code_4) == auth_code) {
00338 lock_(this);
00339 memset(&blob, 0, sizeof(MSTableBlobRec));
00340 CS_SET_DISK_6(fblob->tf_next_6, iFreeList);
00341 iFreeList = blob_id;
00342 CS_SET_DISK_8(tab_head.th_free_list_8, iFreeList);
00343 otab->myTableFile->write(&blob, blob_id, sizeof(MSTableBlobRec));
00344 otab->myTableFile->write(&tab_head.th_free_list_8, offsetof(MSTableHeadRec, th_free_list_8), 8);
00345 unlock_(this);
00346 }
00347 exit_();
00348 }
00349
00350 CSObject *MSTable::getKey()
00351 {
00352 return (CSObject *) myTableName;
00353 }
00354
00355 int MSTable::compareKey(CSObject *key)
00356 {
00357 return myTableName->compare((CSString *) key);
00358 }
00359
00360 uint32_t MSTable::hashKey()
00361 {
00362 return myTableName->hashKey();
00363 }
00364
00365 CSString *MSTable::getTableName()
00366 {
00367 return myTableName;
00368 }
00369
00370 void MSTable::getDeleteInfo(uint32_t *log, uint32_t *offs, time_t *tim)
00371 {
00372 if (!iTableHeadSize) {
00373 CSFile *fh;
00374
00375 fh = openTableFile();
00376 fh->release();
00377 }
00378
00379 *log = iTabTempLogID;
00380 *offs = iTabTempLogOffset;
00381 *tim = iTabDeleteTime;
00382 }
00383
00384 MSTable *MSTable::newTable(uint32_t tab_id, CSString *tab_name, MSDatabase *db, off64_t file_size, bool to_delete)
00385 {
00386 MSTable *tab;
00387
00388 if (!(tab = new MSTable())) {
00389 tab_name->release();
00390 CSException::throwOSError(CS_CONTEXT, ENOMEM);
00391 }
00392 if (to_delete) {
00393
00394 char name_buffer[MS_TABLE_NAME_SIZE + 40];
00395
00396 cs_strcpy(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_name->getCString());
00397 cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, MS_DELETE_MARK);
00398 cs_strcat(MS_TABLE_NAME_SIZE + 40, name_buffer, tab_id);
00399 tab_name->release();
00400 tab_name = CSString::newString(name_buffer);
00401 }
00402
00403 tab->myTableID = tab_id;
00404 tab->myTableName = tab_name;
00405 tab->myDatabase = db;
00406 tab->iTableFileSize = file_size;
00407 tab->iToDelete = to_delete;
00408 return tab;
00409 }
00410
00411 MSTable *MSTable::newTable(uint32_t tab_id, const char *name, MSDatabase *db, off64_t file_size, bool to_delete)
00412 {
00413 return newTable(tab_id, CSString::newString(name), db, file_size, to_delete);
00414 }
00415
00416