00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include<Allocator.h>
00017 #include<Database.h>
00018 #include<os.h>
00019 #include<Debug.h>
00020 #include<Config.h>
00021 #include<CatalogTables.h>
00022
00023
00024
00025
00026
00027
00028 void Chunk::setSize(size_t size)
00029 {
00030
00031 size_t needSize = size + sizeof(int);
00032 size_t multiple = (size_t) os::floor(needSize / sizeof(size_t));
00033 size_t rem = needSize % sizeof(size_t);
00034 if (0 == rem)
00035 allocSize_ = needSize;
00036 else
00037 allocSize_ = (multiple + 1) * sizeof(size_t);
00038 }
00039
00040 void* Chunk::allocateForLargeDataSize(Database *db)
00041 {
00042 PageInfo* pageInfo = ((PageInfo*)curPage_);
00043 DbRetVal ret = db->getAllocDatabaseMutex();
00044 if (ret != 0)
00045 {
00046 printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex");
00047 return NULL;
00048 }
00049
00050
00051 if (pageInfo->hasFreeSpace_ == 1)
00052 {
00053 char *data = ((char*)curPage_) + sizeof(PageInfo);
00054 pageInfo->hasFreeSpace_ =0;
00055 *((int*)data) = 1;
00056 db->releaseAllocDatabaseMutex();
00057 return data + sizeof(int);
00058 }
00059
00060
00061
00062 pageInfo = (PageInfo*)db->getFreePage(allocSize_);
00063 if (NULL == pageInfo)
00064 {
00065 db->releaseAllocDatabaseMutex();
00066 printError(ErrNoMemory,"No more free pages in the database");
00067 return NULL;
00068 }
00069 printDebug(DM_Alloc, "Chunk ID:%d Large Data Item newPage:%x",
00070 chunkID_, pageInfo);
00071 int multiple = os::floor(allocSize_ / PAGE_SIZE);
00072 int offset = ((multiple + 1) * PAGE_SIZE);
00073
00074 pageInfo->setPageAsUsed(offset);
00075
00076
00077 ((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo;
00078
00079 curPage_ = (Page*) pageInfo;
00080 char* data = ((char*)curPage_) + sizeof(PageInfo);
00081
00082 *((int*)data) = 1;
00083 db->releaseAllocDatabaseMutex();
00084 return data + sizeof(int);
00085
00086 }
00087
00088 void* Chunk::allocateFromFirstPage(Database *db, int noOfDataNodes)
00089 {
00090 PageInfo *pageIter = ((PageInfo*)firstPage_);
00091 printDebug(DM_Alloc, "Chunk ID:%d. No free page in database",
00092 chunkID_);
00093 printDebug(DM_Alloc, "Scan from firstPage:%x for free nodes",
00094 firstPage_);
00095 char *data = NULL;
00096 int i = 0;
00097
00098 while(NULL != pageIter)
00099 {
00100 data = ((char*)pageIter) + sizeof(PageInfo);
00101 if (pageIter->hasFreeSpace_ == 1)
00102 {
00103 for (i = 0; i< noOfDataNodes -1; i++)
00104 {
00105 if (1 == *((int*)data))
00106 data = data + allocSize_;
00107 else break;
00108 }
00109 if (i != noOfDataNodes -1) break;
00110 }
00111 printDebug(DM_Alloc, "Chunk ID: %d Page :%x does not have free nodes",
00112 chunkID_, pageIter);
00113 pageIter = (PageInfo*)((PageInfo*) pageIter)->nextPage_;
00114 }
00115 if (NULL == pageIter) return NULL;
00116 printDebug(DM_Alloc,"ChunkID:%d Scan for free node End:Page :%x",
00117 chunkID_, pageIter);
00118 *((int*)data) = 1;
00119 return data + sizeof(int);
00120
00121 }
00122
00123 void* Chunk::allocateFromNewPage(Database *db)
00124 {
00125 DbRetVal ret = db->getAllocDatabaseMutex();
00126 if (ret != 0)
00127 {
00128 printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex");
00129 return NULL;
00130 }
00131
00132 Page *page = db->getFreePage();
00133 if (page == NULL)
00134 {
00135 db->releaseAllocDatabaseMutex();
00136 return NULL;
00137 }
00138 printDebug(DM_Alloc, "ChunkID:%d Normal Data Item newPage:%x",
00139 chunkID_, page);
00140
00141 PageInfo *pInfo = (PageInfo*)page;
00142 pInfo->setPageAsUsed(0);
00143
00144
00145 PageInfo* pageInfo = ((PageInfo*)curPage_);
00146 pageInfo->nextPage_ = page;
00147
00148
00149 curPage_ = page;
00150
00151 char* data = ((char*)page) + sizeof(PageInfo);
00152 *((int*)data) = 1;
00153 db->releaseAllocDatabaseMutex();
00154 return data + sizeof(int);
00155 }
00156
00157
00158
00159
00160
00161
00162
00163 void* Chunk::allocate(Database *db, DbRetVal *status)
00164 {
00165 PageInfo* pageInfo = ((PageInfo*)curPage_);
00166
00167 int noOfDataNodes=os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_);
00168 char *data = ((char*)curPage_) + sizeof(PageInfo);
00169 printDebug(DM_Alloc, "Chunk::allocate id:%d curPage:%x noOfDataNodes:%d",
00170 chunkID_, curPage_, noOfDataNodes);
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 if (0 == noOfDataNodes)
00181 {
00182 data = (char*) allocateForLargeDataSize(db);
00183 return data;
00184 }
00185
00186 int ret = getChunkMutex(db->procSlot);
00187 if (ret != 0)
00188 {
00189 if (status != NULL) *status = ErrLockTimeOut;
00190 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
00191 return NULL;
00192 }
00193 int i = noOfDataNodes;
00194 if (pageInfo->hasFreeSpace_ == 1)
00195 {
00196 for (i = 1; i< noOfDataNodes; i++)
00197 {
00198 if (*((int*)data) == 1) data = data + allocSize_;
00199 else break;
00200 }
00201
00202 }
00203 printDebug(DM_Alloc, "ChunkID:%d Node which might be free is %d",
00204 chunkID_, i);
00205
00206
00207 if (i == noOfDataNodes && *((int*)data) == 1)
00208 {
00209
00210 printDebug(DM_Alloc, "ChunkID:%d curPage does not have free nodes.", chunkID_);
00211
00212 pageInfo->hasFreeSpace_ = 0;
00213 if (chunkID_ == LockTableId || chunkID_ == TransHasTableId)
00214 {
00215 data = (char*) allocateFromFirstPage(db, noOfDataNodes);
00216 if (NULL == data)
00217 {
00218 data = (char*) allocateFromNewPage(db);
00219 if (data == NULL)
00220 {
00221 printError(ErrNoMemory, "No memory in any of the pages:Increase db size");
00222 if (status != NULL) *status = ErrNoMemory;
00223 }
00224 }
00225 }
00226 else
00227 {
00228 data = (char*) allocateFromNewPage(db);
00229 if (NULL == data)
00230 {
00231 data = (char*) allocateFromFirstPage(db, noOfDataNodes);
00232 if (data == NULL)
00233 {
00234 printError(ErrNoMemory, "No memory in any of the pages:Increase db size");
00235 if (status != NULL) *status = ErrNoMemory;
00236 }
00237 }
00238 }
00239 releaseChunkMutex(db->procSlot);
00240 return data;
00241 }
00242 *((int*)data) = 1;
00243 releaseChunkMutex(db->procSlot);
00244 return data + sizeof(int);
00245 }
00246
00247
00248 void* Chunk::allocateForLargeDataSize(Database *db, size_t size)
00249 {
00250
00251 int multiple = os::floor(size / PAGE_SIZE);
00252 int offset = ((multiple + 1) * PAGE_SIZE);
00253 PageInfo* pageInfo = ((PageInfo*)curPage_);
00254 DbRetVal ret = db->getAllocDatabaseMutex();
00255 if (ret != 0)
00256 {
00257 printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex");
00258 return NULL;
00259 }
00260 pageInfo = (PageInfo*)db->getFreePage(allocSize_);
00261 if (NULL == pageInfo)
00262 {
00263 db->releaseAllocDatabaseMutex();
00264 printError(ErrNoMemory,"No more free pages in the database:Increase db size");
00265 return NULL;
00266 }
00267 printDebug(DM_VarAlloc,"Chunk::allocate Large Data Item id:%d Size:%d curPage:%x ",
00268 chunkID_, size, curPage_);
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279 db->releaseAllocDatabaseMutex();
00280 return NULL;
00281
00282 }
00283
00284
00285
00286 void* Chunk::allocFromNewPageForVarSize(Database *db, size_t size)
00287 {
00288
00289 DbRetVal ret = db->getAllocDatabaseMutex();
00290 if (ret != 0)
00291 {
00292 printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex");
00293 return NULL;
00294 }
00295
00296 void *vnode = varSizeFirstFitAllocate(size);
00297 if (vnode != NULL)
00298 {
00299 db->releaseAllocDatabaseMutex();
00300 return vnode;
00301 }
00302
00303 Page *newPage = db->getFreePage();
00304 db->releaseAllocDatabaseMutex();
00305 if (NULL == newPage)
00306 {
00307 return NULL;
00308 }
00309
00310 printDebug(DM_VarAlloc, "ChunkID:%d New Page: %x ", chunkID_, newPage);
00311 PageInfo *pInfo = (PageInfo*) newPage;
00312 pInfo->setPageAsUsed(0);
00313 createDataBucket(newPage, PAGE_SIZE, size);
00314
00315 ((PageInfo*)curPage_)->nextPage_ = newPage;
00316 curPage_ = newPage;
00317 char *data= ((char*)newPage) + sizeof(PageInfo) + sizeof(VarSizeInfo);
00318 return data;
00319 }
00320
00321
00322
00323 void* Chunk::allocateFromCurPageForVarSize(size_t size)
00324 {
00325
00326 Page *page = ((PageInfo*)curPage_);
00327 printDebug(DM_VarAlloc, "Chunk::allocate Normal Data Item id:%d Size:%d curPage:%x ",
00328 chunkID_, size, curPage_);
00329 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) +
00330 sizeof(PageInfo));
00331 while ((char*) varInfo < ((char*)page + PAGE_SIZE))
00332 {
00333 if (0 == varInfo->isUsed_)
00334 {
00335 if( size + sizeof(VarSizeInfo) < varInfo->size_)
00336 {
00337 splitDataBucket(varInfo, size);
00338 printDebug(DM_VarAlloc, "Chunkid:%d splitDataBucket: Size: %d Item:%x ",
00339 chunkID_, size, varInfo);
00340 return (char*)varInfo + sizeof(VarSizeInfo);
00341 }
00342 else if (size == varInfo->size_) {
00343 varInfo->isUsed_ = 1;
00344 return (char *) varInfo + sizeof(VarSizeInfo);
00345 }
00346
00347 }
00348 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
00349 +varInfo->size_);
00350 }
00351 return NULL;
00352 }
00353
00354
00355 void* Chunk::allocate(Database *db, size_t size, DbRetVal *status)
00356 {
00357 if (0 == size) return NULL;
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 size_t alignedSize = os::align(size);
00371 void *data = NULL;
00372 int ret = getChunkMutex(db->procSlot);
00373 if (ret != 0)
00374 {
00375 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
00376 *status = ErrLockTimeOut;
00377 return NULL;
00378 }
00379 if (alignedSize > PAGE_SIZE)
00380 {
00381 data = allocateForLargeDataSize(db, alignedSize);
00382 }
00383 else
00384 {
00385 data = allocateFromCurPageForVarSize(alignedSize);
00386 if (NULL == data) {
00387
00388
00389 data= allocFromNewPageForVarSize(db, alignedSize);
00390 if (NULL == data) {
00391 printError(ErrNoMemory, "No memory in any of the pages:Increase db size");
00392 if (status != NULL) *status = ErrNoMemory;
00393 }
00394 }
00395 }
00396 releaseChunkMutex(db->procSlot);
00397 return data;
00398 }
00399
00400
00401 void* Chunk::varSizeFirstFitAllocate(size_t size)
00402 {
00403 printDebug(DM_VarAlloc, "Chunk::varSizeFirstFitAllocate size:%d firstPage:%x",
00404 size, firstPage_);
00405
00406 Page *page = ((PageInfo*)firstPage_);
00407 size_t alignedSize = os::align(size);
00408 while(NULL != page)
00409 {
00410 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo));
00411 while ((char*) varInfo < ((char*)page + PAGE_SIZE))
00412 {
00413 if (0 == varInfo->isUsed_)
00414 {
00415 if( alignedSize +sizeof(VarSizeInfo) < varInfo->size_)
00416 {
00417 splitDataBucket(varInfo, alignedSize);
00418 return ((char*)varInfo) + sizeof(VarSizeInfo);
00419 }
00420 else if (alignedSize == varInfo->size_) {
00421 varInfo->isUsed_ = 1;
00422 printDebug(DM_VarAlloc, "VarSizeFirstFitAllocate returning %x", ((char*)varInfo) +sizeof(VarSizeInfo));
00423 return ((char *) varInfo) + sizeof(VarSizeInfo);
00424 }
00425 }
00426 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
00427 +varInfo->size_);
00428 }
00429 printDebug(DM_VarAlloc, "Chunk:This page does not have free data nodes page:%x", page);
00430 page = ((PageInfo*) page)->nextPage_;
00431 }
00432 return NULL;
00433 }
00434
00435 void Chunk::freeForVarSizeAllocator(void *ptr, int pslot)
00436 {
00437 int ret = getChunkMutex(pslot);
00438 if (ret != 0)
00439 {
00440 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
00441 return;
00442 }
00443 VarSizeInfo *varInfo = (VarSizeInfo*)((char*)ptr- sizeof(VarSizeInfo));
00444 varInfo->isUsed_ = 0;
00445 printDebug(DM_VarAlloc,"chunkID:%d Unset isUsed for %x", chunkID_, varInfo);
00446 releaseChunkMutex(pslot);
00447 return;
00448
00449 }
00450
00451 void Chunk::freeForLargeAllocator(void *ptr, int pslot)
00452 {
00453
00454
00455 int ret = getChunkMutex(pslot);
00456 if (ret != 0)
00457 {
00458 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
00459 return;
00460 }
00461 PageInfo *pageInfo = (PageInfo*)(((char*)
00462 ptr) - (sizeof(PageInfo) + sizeof(int)));
00463 PageInfo *pInfo = (PageInfo*)firstPage_, *prev = (PageInfo*)firstPage_;
00464 bool found = false;
00465 while(!found)
00466 {
00467 if (pInfo == pageInfo) {found = true; break; }
00468 prev = pInfo;
00469 pInfo = (PageInfo*)pInfo->nextPage_;
00470 }
00471 if (!found)
00472 {
00473 printError(ErrSysFatal,"Page %x not found in page list:Logical error", pageInfo );
00474 releaseChunkMutex(pslot);
00475 return ;
00476 }
00477 prev->nextPage_ = pageInfo->nextPage_;
00478 pageInfo->nextPageAfterMerge_ = NULL;
00479 pageInfo->isUsed_ = 0;
00480 os::memset(pageInfo, 0 , allocSize_);
00481 pageInfo->hasFreeSpace_ = 1;
00482 releaseChunkMutex(pslot);
00483 return;
00484 }
00485
00486
00487 void Chunk::free(Database *db, void *ptr)
00488 {
00489 if (0 == allocSize_)
00490 {
00491 freeForVarSizeAllocator(ptr, db->procSlot);
00492 return;
00493 }
00494 int noOfDataNodes =os::floor((PAGE_SIZE - sizeof(PageInfo)) / allocSize_);
00495
00496 if (0 == noOfDataNodes)
00497 {
00498 freeForLargeAllocator(ptr, db->procSlot);
00499 return;
00500 }
00501 int ret = getChunkMutex(db->procSlot);
00502 if (ret != 0)
00503 {
00504 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
00505 return;
00506 }
00507
00508
00509
00510 *((int*)ptr -1 ) = 0;
00511 PageInfo *pageInfo;
00512 pageInfo = getPageInfo(db, ptr);
00513 if (NULL == pageInfo)
00514 {
00515 printError(ErrSysFatal,"Probable Data corruption: pageInfo is NULL", pageInfo );
00516 releaseChunkMutex(db->procSlot);
00517 return;
00518 }
00519
00520 pageInfo->hasFreeSpace_ = 1;
00521 releaseChunkMutex(db->procSlot);
00522 return;
00523 }
00524
00525
00526
00527
00528
00529
00530 PageInfo* Chunk::getPageInfo(Database *db, void *ptr)
00531 {
00532 if (allocSize_ < PAGE_SIZE - sizeof(PageInfo)) {
00533 int rem = (long) ptr % 8192;
00534 return (PageInfo*)(((char*)ptr) - rem);
00535 } else {
00536
00537 char *inPtr = (char*)ptr;
00538 PageInfo* pageInfo = ((PageInfo*)firstPage_);
00539
00540 while( pageInfo != NULL )
00541 {
00542 if (inPtr > (char*) pageInfo && pageInfo->nextPageAfterMerge_ >inPtr)
00543 return pageInfo;
00544 pageInfo = (PageInfo*)pageInfo->nextPage_ ;
00545 }
00546 }
00547 return NULL;
00548 }
00549
00550
00551
00552 long Chunk::getTotalDataNodes()
00553 {
00554 long totalNodes =0;
00555 if (0 == allocSize_)
00556 {
00557 Page *page = ((PageInfo*)firstPage_);
00558 while(NULL != page)
00559 {
00560 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo));
00561 while ((char*) varInfo < ((char*)page + PAGE_SIZE))
00562 {
00563 if (1 == varInfo->isUsed_) totalNodes++;
00564 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
00565 +varInfo->size_);
00566 }
00567 page = ((PageInfo*) page)->nextPage_;
00568 }
00569 return totalNodes;
00570 }
00571
00572
00573 if (allocSize_ >PAGE_SIZE)
00574 return 0;
00575
00576 int noOfDataNodes=os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_);
00577 PageInfo* pageInfo = ((PageInfo*)firstPage_);
00578 char *data = ((char*)firstPage_) + sizeof(PageInfo);
00579 int i=0;
00580 while( pageInfo != NULL )
00581 {
00582 data = ((char*)pageInfo) + sizeof(PageInfo);
00583 for (i = 0; i< noOfDataNodes; i++)
00584 {
00585 if (*((int*)data) == 1) { totalNodes++;}
00586 data = data + allocSize_;
00587 }
00588 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
00589 }
00590 return totalNodes;
00591 }
00592
00593
00594 int Chunk::compact()
00595 {
00596 PageInfo* pageInfo = ((PageInfo*)firstPage_);
00597 PageInfo* prevPage = pageInfo;
00598 if (NULL == pageInfo)
00599 {
00600 return 0;
00601 }
00602 pageInfo = (PageInfo*)pageInfo->nextPage_;
00603 if (0 == allocSize_)
00604 {
00605 while( pageInfo != NULL )
00606 {
00607 bool flag = false;
00608 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)pageInfo) +
00609 sizeof(PageInfo));
00610 while ((char*) varInfo < ((char*)pageInfo + PAGE_SIZE))
00611 {
00612 if (1 == varInfo->isUsed_) {flag=true; break;}
00613 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
00614 +varInfo->size_);
00615 }
00616 if (!flag) {
00617 printDebug(DM_VarAlloc,"Freeing unused page in varsize allocator %x\n", pageInfo);
00618 prevPage->nextPage_ = pageInfo->nextPage_;
00619 pageInfo->isUsed_ = 0;
00620 }
00621 prevPage = pageInfo;
00622 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
00623 printDebug(DM_VarAlloc,"compact iter %x\n", pageInfo);
00624 }
00625 }else if (allocSize_ < PAGE_SIZE)
00626 {
00627 while( pageInfo != NULL )
00628 {
00629 bool flag = false;
00630 int noOfDataNodes=os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_);
00631 char *data = ((char*)pageInfo) + sizeof(PageInfo);
00632 for (int i = 0; i< noOfDataNodes -1; i++)
00633 {
00634 if (1 == *((int*)data)) { flag = true; break; }
00635 data = data +allocSize_;
00636 }
00637 if (!flag) {
00638 printDebug(DM_Alloc,"Freeing unused page in fixed allocator %x\n", pageInfo);
00639 prevPage->nextPage_ = pageInfo->nextPage_;
00640 pageInfo->isUsed_ = 0;
00641 }
00642 prevPage = pageInfo;
00643 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
00644 printDebug(DM_Alloc,"compact iter %x\n", pageInfo);
00645 }
00646 }
00647 return 0;
00648 }
00649
00650 int Chunk::totalPages()
00651 {
00652
00653 PageInfo* pageInfo = ((PageInfo*)firstPage_);
00654 int totPages=0;
00655 while( pageInfo != NULL )
00656 {
00657 totPages++;
00658 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
00659 }
00660 return totPages;
00661 }
00662
00663 int Chunk::initMutex()
00664 {
00665 return chunkMutex_.init("Chunk");
00666 }
00667 int Chunk::getChunkMutex(int procSlot)
00668 {
00669 return chunkMutex_.getLock(procSlot);
00670 }
00671 int Chunk::releaseChunkMutex(int procSlot)
00672 {
00673 return chunkMutex_.releaseLock(procSlot);
00674 }
00675 int Chunk::destroyMutex()
00676 {
00677 return chunkMutex_.destroy();
00678 }
00679 void Chunk::splitDataBucket(VarSizeInfo *varInfo, size_t needSize)
00680 {
00681 int remSpace = varInfo->size_ - sizeof(VarSizeInfo) - needSize;
00682 varInfo->isUsed_ = 1;
00683 varInfo->size_ = needSize;
00684 varInfo = (VarSizeInfo*)((char*)varInfo +
00685 sizeof(VarSizeInfo) + varInfo->size_);
00686 varInfo->isUsed_ = 0;
00687 varInfo->size_ = remSpace;
00688 printDebug(DM_VarAlloc, "Remaining space is %d\n", remSpace);
00689 return;
00690 }
00691
00692
00693 void Chunk::createDataBucket(Page *page, size_t totalSize, size_t needSize)
00694 {
00695 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo));
00696 varInfo->isUsed_ = 0;
00697 varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
00698 splitDataBucket(varInfo, needSize);
00699 return;
00700 }
00701
00702
00703