solaris 64 changes
[csql.git] / src / storage / Chunk.cxx
blob5605fc27af082563bbb0d43150d6a593c73a1baf
1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
4 * *
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. *
9 * *
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. *
14 * *
15 ***************************************************************************/
16 #include<Allocator.h>
17 #include<Database.h>
18 #include<os.h>
19 #include<Debug.h>
20 #include<Config.h>
21 #include<CatalogTables.h>
23 // sets the size of the Chunk allocator for fixed size
24 // allocator
25 // we need one integer to store book keeping information
26 // whether the storage allocation unit is used of not
27 // when it is deleted this flag is only set to unused
28 void Chunk::setSize(size_t size)
31 size_t needSize = size + sizeof(InUse);
32 size_t multiple = (size_t) os::floor(needSize / sizeof(size_t));
33 size_t rem = needSize % sizeof(size_t);
34 if (0 == rem)
35 allocSize_ = needSize;
36 else
37 allocSize_ = (multiple + 1) * sizeof(size_t);
40 void* Chunk::allocateForLargeDataSize(Database *db)
42 PageInfo* pageInfo = ((PageInfo*)curPage_);
43 DbRetVal ret = db->getAllocDatabaseMutex();
44 if (ret != 0)
46 printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex");
47 return NULL;
50 //check whether we have space in curPage
51 if (pageInfo->hasFreeSpace_ == 1)
53 char *data = ((char*)curPage_) + sizeof(PageInfo);
54 //pageInfo->hasFreeSpace_ =0;
55 int retVal = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0);
56 if (retVal !=0) printError(ErrSysFatal, "Unable to set hashFreeSpace flag");
57 *((InUse*)data) = 1;
58 //Mutex::CAS((InUse*)data , 0, 1);
59 db->releaseAllocDatabaseMutex();
60 return data + sizeof(InUse);
63 //no space in curpage , get new page from database
64 pageInfo = (PageInfo*)db->getFreePage(allocSize_);
65 if (NULL == pageInfo)
67 db->releaseAllocDatabaseMutex();
68 printError(ErrNoMemory,"No more free pages in the database");
69 return NULL;
71 printDebug(DM_Alloc, "Chunk ID:%d Large Data Item newPage:%x",
72 chunkID_, pageInfo);
73 int multiple = (int) os::floor(allocSize_ / PAGE_SIZE);
74 int offset = ((multiple + 1) * PAGE_SIZE);
76 pageInfo->setPageAsUsed(offset);
78 //create the link
79 //((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo;
80 int retVal = Mutex::CASL((long*) &(((PageInfo*)curPage_)->nextPage_),
81 (long)(((PageInfo*)curPage_)->nextPage_), (long)pageInfo);
82 if(retVal !=0) {
83 printError(ErrLockTimeOut, "Fatal: Unable to create page link.");
86 //Make this as current page
87 //curPage_ = (Page*) pageInfo;
88 retVal = Mutex::CASL((long*) &curPage_, (long)curPage_, (long)pageInfo);
89 if(retVal !=0) {
90 printError(ErrLockTimeOut, "Fatal:Unable to set current page");
93 char* data = ((char*)curPage_) + sizeof(PageInfo);
94 retVal = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0);
95 if(retVal !=0) {
96 printError(ErrLockTimeOut, "Fatal:Unable to set hasFreeSpace");
98 *((InUse*)data) = 1;
99 //Mutex::CASL((InUse*)data , 0, 1);
100 db->releaseAllocDatabaseMutex();
101 return data + sizeof(InUse);
105 void* Chunk::allocateFromFirstPage(Database *db, int noOfDataNodes, DbRetVal *status)
107 PageInfo *pageIter = ((PageInfo*)firstPage_);
108 printDebug(DM_Alloc, "Chunk ID:%d. No free page in database",
109 chunkID_);
110 printDebug(DM_Alloc, "Scan from firstPage:%x for free nodes",
111 firstPage_);
112 char *data = NULL;
113 int i = 0;
114 //scan from first page to locate a free node available
115 while(NULL != pageIter)
117 data = ((char*)pageIter) + sizeof(PageInfo);
118 if (pageIter->hasFreeSpace_ == 1)
120 for (i = 0; i< noOfDataNodes ; i++)
122 if (1 == *((InUse*)data))
123 data = data + allocSize_;
124 else break;
126 if (i != noOfDataNodes) break;
128 printDebug(DM_Alloc, "Chunk ID: %d Page :%x does not have free nodes",
129 chunkID_, pageIter);
130 pageIter = (PageInfo*)((PageInfo*) pageIter)->nextPage_;
132 if (NULL == pageIter) {
133 *status = ErrNoMemory;
134 return NULL;
136 printDebug(DM_Alloc,"ChunkID:%d Scan for free node End:Page :%x",
137 chunkID_, pageIter);
138 //*((InUse*)data) = 1;
139 #if defined(__sparcv9)
140 int ret = Mutex::CASL((InUse*)data , 0, 1);
141 #else
142 int ret = Mutex::CAS((InUse*)data , 0, 1);
143 #endif
144 if(ret !=0) {
145 *status = ErrLockTimeOut;
146 //printError(ErrLockTimeOut, "Unable to allocate from first page. Retry...");
147 return NULL;
149 return data + sizeof(InUse);
152 void* Chunk::allocateFromNewPage(Database *db, DbRetVal *status)
154 DbRetVal ret = db->getAllocDatabaseMutex();
155 if (ret != 0)
157 printDebug(DM_Warning,"Unable to acquire alloc database Mutex Chunkid:%d", chunkID_);
158 *status = ErrLockTimeOut;
159 return NULL;
161 //get a new page from db
162 Page *page = db->getFreePage();
163 if (page == NULL) {
164 printError(ErrNoMemory, "Unable to allocate page");
165 db->releaseAllocDatabaseMutex();
166 *status = ErrNoMemory;
167 return NULL;
169 printDebug(DM_Alloc, "ChunkID:%d Normal Data Item newPage:%x",
170 chunkID_, page);
171 //Initialize pageInfo for this new page
172 PageInfo *pInfo = (PageInfo*)page;
173 pInfo->setPageAsUsed(0);
175 char* data = ((char*)page) + sizeof(PageInfo);
176 *((InUse*)data) = 1;
177 //Mutex::CAS((int*)data , 0, 1);
179 //create the link between old page and the newly created page
180 PageInfo* pageInfo = ((PageInfo*)curPage_);
182 long oldPage = (long)pageInfo->nextPage_;
183 //pageInfo->nextPage_ = page;
184 int retVal = Mutex::CASL((long*)&pageInfo->nextPage_ , (long)pageInfo->nextPage_, (long)page);
185 if(retVal !=0) {
186 *((InUse*)data) = 0;
187 pInfo->setPageAsFree();
188 printDebug(DM_Warning, "Unable to get lock to set chunk list.");
189 *status = ErrLockTimeOut;
190 return NULL;
193 //make this new page as the current page
194 //curPage_ = page;
195 retVal = Mutex::CASL((long*)&curPage_ , (long)curPage_, (long)page);
196 if(retVal !=0) {
197 *((InUse*)data) = 0;
198 pInfo->setPageAsFree();
199 retVal = Mutex::CASL((long*)&pageInfo->nextPage_ , (long)pageInfo->nextPage_, (long)oldPage);
200 if (retVal !=0) printError(ErrSysFatal, "Fatal: Unable to reset the nextPage");
201 printDebug(DM_Warning, "Unable to get lock to set curPage");
202 *status = ErrLockTimeOut;
203 return NULL;
206 db->releaseAllocDatabaseMutex();
207 return data + sizeof(InUse);
210 //Allocates memory to store data
211 //TODO::check whether it is locked before allocating.
212 //delete tuple will set the usedflag to true, but locks will be held
213 //till commit and it shall be rolledback.So make sure that it does not
214 //allocate deleted tuple which is yet to be commited.
216 void* Chunk::allocate(Database *db, DbRetVal *status)
218 PageInfo* pageInfo = ((PageInfo*)curPage_);
220 int noOfDataNodes=(int) os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_);
221 char *data = ((char*)curPage_) + sizeof(PageInfo);
222 printDebug(DM_Alloc, "Chunk::allocate id:%d curPage:%x noOfDataNodes:%d",
223 chunkID_, curPage_, noOfDataNodes);
225 //1.scan through data list and find if any is free to use in current page
226 //2.If there is none then
227 // a) get new free page from db. set the prev->next to point
228 // to this new page
229 //4. b) initialize the free page to zero and get first data ptr.
230 //5.If there is one, return that
232 //For allocation more than PAGE_SIZE
233 if (0 == noOfDataNodes)
235 data = (char*) allocateForLargeDataSize(db);
236 return data;
239 /*int ret = getChunkMutex(db->procSlot);
240 if (ret != 0)
242 if (status != NULL) *status = ErrLockTimeOut;
243 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
244 return NULL;
246 int i = noOfDataNodes;
247 if (pageInfo->hasFreeSpace_ == 1)
249 for (i = 1; i< noOfDataNodes; i++)
251 if (*((InUse*)data) == 1) data = data + allocSize_;
252 else break;
256 printDebug(DM_Alloc, "ChunkID:%d Node which might be free is %d",
257 chunkID_, i);
258 //It comes here if the pageInfo->hasFreeSpace ==0
259 //or there are no free data space in this page
260 if (i == noOfDataNodes && *((InUse*)data) == 1)
263 printDebug(DM_Alloc, "ChunkID:%d curPage does not have free nodes.", chunkID_);
264 //there are no free data space in this page
265 //pageInfo->hasFreeSpace_ = 0;
266 int ret = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0);
267 if(ret !=0) {
268 *status = ErrLockTimeOut;
269 printDebug(DM_Warning, "Unable to set hasFreespace");
270 return NULL;
272 //if (chunkID_ == LockTableId || chunkID_ == TransHasTableId)
274 *status = OK;
275 data = (char*) allocateFromFirstPage(db, noOfDataNodes, status);
276 if (NULL == data && *status != ErrLockTimeOut)
278 *status = OK;
279 data = (char*) allocateFromNewPage(db, status);
280 if (data == NULL && *status != ErrLockTimeOut)
282 printError(ErrNoMemory, "No memory in any of the pages:Increase db size");
283 *status = ErrNoMemory;
287 /*else
289 data = (char*) allocateFromNewPage(db, status);
290 if (NULL == data && *status != ErrLockTimeOut)
292 data = (char*) allocateFromFirstPage(db, noOfDataNodes);
293 if (data == NULL)
295 printError(ErrNoMemory, "No memory in any of the pages:Increase db size");
296 *status = ErrNoMemory;
300 //releaseChunkMutex(db->procSlot);
301 return data;
303 //*((InUse*)data) = 1;
304 #if defined(__sparcv9)
305 int ret = Mutex::CASL((InUse*)data , 0, 1);
306 #else
307 int ret = Mutex::CAS((InUse*)data , 0, 1);
308 #endif
309 if(ret !=0) {
310 *status = ErrLockTimeOut;
311 printDebug(DM_Warning, "Unable to set isUsed : retry...");
312 return NULL;
314 //releaseChunkMutex(db->procSlot);
315 return data + sizeof(InUse);
319 void* Chunk::allocateForLargeDataSize(Database *db, size_t size)
321 //no need to take chunk mutexes for this, as we are taking alloc database mutex
322 int multiple = (int) os::floor(size / PAGE_SIZE);
323 int offset = ((multiple + 1) * PAGE_SIZE);
324 PageInfo* pageInfo = ((PageInfo*)curPage_);
325 if(0==allocSize_)
326 pageInfo = (PageInfo*)db->getFreePage(size);
327 else
328 pageInfo = (PageInfo*)db->getFreePage(allocSize_);
329 if (NULL == pageInfo)
331 printError(ErrNoMemory,"No more free pages in the database:Increase db size");
332 return NULL;
334 printDebug(DM_VarAlloc,"Chunk::alnextPageAfterMerge_locate Large Data Item id:%d Size:%d curPage:%x ",
335 chunkID_, size, curPage_);
336 //TODO:: logic pending
337 if(allocSize_!=0){
338 //large size allocate for FixedSize data
339 pageInfo->nextPageAfterMerge_ = ((char*)pageInfo + offset);
340 ((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo;
341 curPage_ = (Page*) pageInfo;
342 char* data = ((char*)curPage_) + sizeof(PageInfo);
343 //*((InUse*)data) = 1;
344 #if defined(__sparcv9)
345 int ret = Mutex::CASL((InUse*)data , 0, 1);
346 #else
347 int ret = Mutex::CAS((InUse*)data , 0, 1);
348 #endif
349 if(ret !=0) {
350 printError(ErrLockTimeOut, "Lock Timeout: retry...");
351 return NULL;
353 pageInfo->isUsed_=1;
354 ret = Mutex::CAS(&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 0);
355 if (ret !=0) printError(ErrSysFatal, "Unable to set hashFreeSpace");
356 return data + sizeof(InUse);
357 }else{
358 //large size allocate for varSize data
359 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)pageInfo) + sizeof(PageInfo));
360 pageInfo->nextPageAfterMerge_ = ((char*)pageInfo + offset);
361 ((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo;
362 curPage_ = (Page*) pageInfo;
363 varInfo->size_= size;
364 int ret = Mutex::CAS(&varInfo->isUsed_ , varInfo->isUsed_, 1);
365 if(ret !=0) {
366 printError(ErrLockTimeOut, "Unable to get lock for var alloc. Retry...");
367 return NULL;
369 pageInfo->isUsed_=1;
370 return (char *) varInfo + sizeof(VarSizeInfo);
372 //REDESIGN MAY BE REQUIRED:Lets us live with this for now.
373 //what happens to the space lets say 10000 bytes is allocated
374 //it needs 2 pages,= 16000 bytes, 6000 bytes should not be wasted
375 //in this case.So need to take of this.
376 //Will be coded at later stage as this is developed to support
377 //undo logging and currently we shall assume that the logs generated
378 //wont be greater than PAGE_SIZE.
379 return NULL;
385 void* Chunk::allocFromNewPageForVarSize(Database *db, size_t size, int pslot, DbRetVal *rv)
387 //Should be called only for data items <PAGE_SIZE
388 void *vnode = varSizeFirstFitAllocate(size, pslot, rv);
389 if (vnode != NULL)
391 return vnode;
393 printDebug(DM_Warning, "No free space in any of the pages already being used");
394 *rv =OK;
395 DbRetVal ret = db->getAllocDatabaseMutex();
396 if (ret != 0)
398 printError(ErrLockTimeOut,"Unable to acquire alloc database Mutex");
399 return NULL;
401 Page *newPage = db->getFreePage();
402 if (NULL == newPage)
404 db->releaseAllocDatabaseMutex();
405 return NULL;
408 printDebug(DM_VarAlloc, "ChunkID:%d New Page: %x ", chunkID_, newPage);
409 PageInfo *pInfo = (PageInfo*) newPage;
410 pInfo->setPageAsUsed(0);
411 if (1 == createDataBucket(newPage, PAGE_SIZE, size, pslot))
413 printError(ErrSysFatal, "Split failed in new page...Should never happen");
414 *rv = ErrSysFatal;
415 db->releaseAllocDatabaseMutex();
416 return NULL;
418 long oldPage = (long)((PageInfo*)curPage_)->nextPage_;
419 //((PageInfo*)curPage_)->nextPage_ = newPage;
420 int retVal = Mutex::CASL((long*) &(((PageInfo*)curPage_)->nextPage_),
421 (long)(((PageInfo*)curPage_)->nextPage_), (long)newPage);
422 if(retVal !=0) {
423 printError(ErrSysFatal, "Unable to get lock to set chunk next page");
424 pInfo->setPageAsFree();
425 db->releaseAllocDatabaseMutex();
426 *rv = ErrSysFatal;
427 return NULL;
429 //curPage_ = newPage;
430 retVal = Mutex::CASL((long*) &curPage_, (long)curPage_, (long)newPage);
431 if(retVal !=0) {
432 printError(ErrSysFatal, "Unable to get lock to set curPage");
433 retVal = Mutex::CASL((long*) &(((PageInfo*)curPage_)->nextPage_),
434 (long)(((PageInfo*)curPage_)->nextPage_), (long)oldPage);
435 if (retVal !=0 ) printError(ErrSysFatal, "Unable to reset curPage");
436 pInfo->setPageAsFree();
437 db->releaseAllocDatabaseMutex();
438 *rv = ErrSysFatal;
439 return NULL;
441 db->releaseAllocDatabaseMutex();
442 char *data= ((char*)newPage) + sizeof(PageInfo) + sizeof(VarSizeInfo);
443 return data;
446 //Allocates from the current page of the chunk.
447 //Scans through the VarSizeInfo objects in the page and gets the free slot
448 void* Chunk::allocateFromCurPageForVarSize(size_t size, int pslot, DbRetVal *rv)
450 //Should be called only for data items <PAGE_SIZE
451 Page *page = ((PageInfo*)curPage_);
452 printDebug(DM_VarAlloc, "Chunk::allocate Normal Data Item id:%d Size:%d curPage:%x ",
453 chunkID_, size, curPage_);
454 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) +
455 sizeof(PageInfo));
456 if ( 0 != getChunkMutex(pslot)) { *rv = ErrLockTimeOut; return NULL; }
457 while ((char*) varInfo < ((char*)page + PAGE_SIZE))
459 if (0 == varInfo->isUsed_)
461 if( size + sizeof(VarSizeInfo) < varInfo->size_)
463 if (1 == splitDataBucket(varInfo, size, pslot, rv))
465 printDebug(DM_Warning, "Unable to split the data bucket");
466 releaseChunkMutex(pslot);
467 return NULL;
469 printDebug(DM_VarAlloc, "Chunkid:%d splitDataBucket: Size: %d Item:%x ",
470 chunkID_, size, varInfo);
471 releaseChunkMutex(pslot);
472 return (char*)varInfo + sizeof(VarSizeInfo);
474 else if (size == varInfo->size_) {
475 //varInfo->isUsed_ = 1;
476 int ret = Mutex::CAS(&varInfo->isUsed_ , 0, 1);
477 if(ret !=0) {
478 printDebug(DM_Warning, "Unable to get lock for var alloc size:%d ", size);
479 *rv = ErrLockTimeOut;
480 releaseChunkMutex(pslot);
481 return NULL;
483 releaseChunkMutex(pslot);
484 return (char *) varInfo + sizeof(VarSizeInfo);
488 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
489 +varInfo->size_);
491 releaseChunkMutex(pslot);
492 return NULL;
495 //Allocates memory to store data of variable size
496 void* Chunk::allocate(Database *db, size_t size, DbRetVal *status)
498 if (0 == size) return NULL;
499 //check if the size is more than PAGE_SIZE
500 //if it is more than the PAGE_SIZE, then allocate new
501 //page using database and then link the curPage to the
502 //newly allocated page
503 //if it is less than PAGE_SIZE, then check the curpage for
504 //free memory of specified size
505 //if not available, then scan from the firstPage for the free
506 //space
508 //TODO::During the scan, merge nearby nodes if both are free
509 //if not available then allocate new page
511 size_t alignedSize = os::alignLong(size);
512 void *data = NULL;
513 /*int ret = getChunkMutex(db->procSlot);
514 if (ret != 0)
516 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
517 *status = ErrLockTimeOut;
518 return NULL;
520 if (alignedSize > PAGE_SIZE )
522 data = allocateForLargeDataSize(db, alignedSize);
524 else
526 data = allocateFromCurPageForVarSize(alignedSize, db->procSlot, status);
527 if (NULL == data) {
528 *status = OK;
529 //No available spaces in the current page.
530 //allocate new page
531 data= allocFromNewPageForVarSize(db, alignedSize, db->procSlot, status);
532 if (NULL == data && *status !=ErrLockTimeOut) {
533 printError(ErrNoMemory, "No memory in any of the pages:Increase db size");
534 *status = ErrNoMemory;
538 //releaseChunkMutex(db->procSlot);
539 return data;
542 //Assumes chunk mutex is already taken, before calling this
543 void* Chunk::varSizeFirstFitAllocate(size_t size, int pslot, DbRetVal *rv)
545 printDebug(DM_VarAlloc, "Chunk::varSizeFirstFitAllocate size:%d firstPage:%x",
546 size, firstPage_);
548 Page *page = ((PageInfo*)firstPage_);
549 size_t alignedSize = os::alignLong(size);
550 if ( 0 != getChunkMutex(pslot)) { *rv = ErrLockTimeOut; return NULL; }
551 while(NULL != page)
553 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo));
554 while ((char*) varInfo < ((char*)page + PAGE_SIZE))
556 if (0 == varInfo->isUsed_)
558 if( alignedSize +sizeof(VarSizeInfo) < varInfo->size_)
560 if( 1 == splitDataBucket(varInfo, alignedSize, pslot, rv))
562 printDebug(DM_Warning, "Unable to split the data bucket");
563 releaseChunkMutex(pslot);
564 return NULL;
566 releaseChunkMutex(pslot);
567 return ((char*)varInfo) + sizeof(VarSizeInfo);
569 else if (alignedSize == varInfo->size_) {
570 //varInfo->isUsed_ = 1;
571 int ret = Mutex::CAS((int*)&varInfo->isUsed_, 0, 1);
572 if(ret !=0) {
573 printDebug(DM_Warning,"Unable to get lock to set isUsed flag.");
574 *rv = ErrLockTimeOut;
575 releaseChunkMutex(pslot);
576 return NULL;
578 printDebug(DM_VarAlloc, "VarSizeFirstFitAllocate returning %x", ((char*)varInfo) +sizeof(VarSizeInfo));
579 releaseChunkMutex(pslot);
580 return ((char *) varInfo) + sizeof(VarSizeInfo);
583 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
584 +varInfo->size_);
586 printDebug(DM_VarAlloc, "Chunk:This page does not have free data nodes page:%x", page);
587 page = ((PageInfo*) page)->nextPage_;
589 releaseChunkMutex(pslot);
590 return NULL;
593 void Chunk::freeForVarSizeAllocator(void *ptr, int pslot)
595 /*int ret = getChunkMutex(pslot);
596 if (ret != 0)
598 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
599 return;
601 VarSizeInfo *varInfo = (VarSizeInfo*)((char*)ptr- sizeof(VarSizeInfo));
602 //varInfo->isUsed_ = 0;
603 if(varInfo->size_ > (PAGE_SIZE - (sizeof(VarSizeInfo)+sizeof(PageInfo)))) {
604 PageInfo *pageInfo = (PageInfo*)((char*)varInfo - sizeof(PageInfo));
605 PageInfo *pInfo = (PageInfo*)firstPage_, *prev = (PageInfo*)firstPage_;
606 bool found = false;
607 while(!found)
609 if(NULL==pInfo) break;
610 if (pInfo == pageInfo) {found = true; break; }
611 prev = pInfo;
612 pInfo = (PageInfo*)pInfo->nextPage_;
614 if (!found)
616 printError(ErrSysFatal,"Page %x not found in page list:Logical error", pageInfo );
617 return ;
619 if(curPage_== pageInfo) {curPage_ = prev ; }
620 pageInfo->isUsed_ = 0;
621 pageInfo->nextPageAfterMerge_ = NULL;
622 pageInfo->hasFreeSpace_ = 1;
623 prev->nextPage_ = pageInfo->nextPage_;
625 int ret = Mutex::CAS((int*)&varInfo->isUsed_, 1, 0);
626 if(ret !=0) {
627 printError(ErrAlready, "Fatal: Varsize double free for %x", ptr);
629 printDebug(DM_VarAlloc,"chunkID:%d Unset isUsed for %x", chunkID_, varInfo);
630 //releaseChunkMutex(pslot);
631 return;
635 void Chunk::freeForLargeAllocator(void *ptr, int pslot)
637 //There will be max only one data element in a page.
638 //PageInfo is stored just before the data.
639 int ret = getChunkMutex(pslot);
640 if (ret != 0)
642 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
643 return;
645 PageInfo *pageInfo = (PageInfo*)(((char*)
646 ptr) - (sizeof(PageInfo) + sizeof(InUse)));
647 PageInfo *pInfo = (PageInfo*)firstPage_, *prev = (PageInfo*)firstPage_;
648 bool found = false;
649 while(!found)
651 if (pInfo == pageInfo) {found = true; break; }
652 prev = pInfo;
653 pInfo = (PageInfo*)pInfo->nextPage_;
655 if (!found)
657 printError(ErrSysFatal,"Page %x not found in page list:Logical error", pageInfo );
658 releaseChunkMutex(pslot);
659 return ;
661 os::memset(((char*)pageInfo+sizeof(PageInfo)), 0 , allocSize_);
662 if(((PageInfo*)firstPage_)->nextPage_ != NULL){
663 pageInfo->nextPageAfterMerge_ = NULL;
664 //pageInfo->isUsed_ = 0;
665 ret = Mutex::CAS((int*)&pageInfo->isUsed_, pageInfo->isUsed_, 0);
666 if (ret != 0) printError(ErrSysFatal, "Unable to set isUsed flag");
667 //pageInfo->hasFreeSpace_ = 1;
668 ret = Mutex::CAS((int*)&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 1);
669 if (ret != 0) printError(ErrSysFatal, "Unable to set hasFreeSpace flag");
670 if(pageInfo == firstPage_ && ((PageInfo*)firstPage_)->nextPage_ != NULL)
671 //firstPage_ = pageInfo->nextPage_ ;
672 ret = Mutex::CASL((long*)&firstPage_, (long) firstPage_,
673 (long)pageInfo->nextPage_);
674 if (ret != 0) printError(ErrSysFatal, "Unable to set firstPage");
675 else {
676 //prev->nextPage_ = pageInfo->nextPage_;
677 ret = Mutex::CASL((long*)&prev->nextPage_, (long) prev->nextPage_,
678 (long)pageInfo->nextPage_);
679 if (ret != 0) printError(ErrSysFatal, "Unable to set nextPage");
682 releaseChunkMutex(pslot);
683 return;
686 //Frees the memory pointed by ptr
687 void Chunk::free(Database *db, void *ptr)
689 if (0 == allocSize_)
691 freeForVarSizeAllocator(ptr, db->procSlot);
692 return;
694 int noOfDataNodes =(int) os::floor((PAGE_SIZE - sizeof(PageInfo)) / allocSize_);
696 if (0 == noOfDataNodes)
698 freeForLargeAllocator(ptr, db->procSlot);
699 return;
701 /*int ret = getChunkMutex(db->procSlot);
702 if (ret != 0)
704 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
705 return;
707 //below is the code for freeing in fixed size allocator
709 //unset the used flag
710 //*((int*)ptr -1 ) = 0;
711 if (*((InUse*)ptr -1 ) == 0) {
712 printError(ErrSysFatal, "Fatal:Data node already freed %x Chunk:%d", ptr, chunkID_);
713 //return;
715 #if defined(__sparcv9)
716 int ret = Mutex::CASL(((InUse*)ptr -1), 1, 0);
717 #else
718 int ret = Mutex::CAS(((InUse*)ptr -1), 1, 0);
719 #endif
720 if(ret !=0) {
721 printError(ErrSysFatal, "Unable to get lock to free for %x", ptr);
722 return;
724 PageInfo *pageInfo;
725 pageInfo = getPageInfo(db, ptr);
726 if (NULL == pageInfo)
728 printError(ErrSysFatal,"Fatal: pageInfo is NULL", pageInfo );
729 //releaseChunkMutex(db->procSlot);
730 return;
732 //set the pageinfo where this ptr points
733 //pageInfo->hasFreeSpace_ = 1;
734 if (! (pageInfo->hasFreeSpace_ == 0 || pageInfo->hasFreeSpace_ == 1)) {
735 printError(ErrSysFatal, "Fatal: hasFreeSpace has invalid value:%d for page %x", pageInfo->hasFreeSpace_, pageInfo);
736 return;
738 ret = Mutex::CAS((int*)&pageInfo->hasFreeSpace_, pageInfo->hasFreeSpace_, 1);
739 if(ret !=0) {
740 printError(ErrSysFatal, "Unable to get lock to set hasFreeSpace");
742 //releaseChunkMutex(db->procSlot);
743 return;
746 //returns the pageInfo of the page where this ptr points
747 //This works only if the data size is less than PAGE_SIZE
748 //If ptr points to data which is more than PAGE_SIZE,then
749 //calling this might lead to memory corruption
750 //Note:IMPORTANT::assumes db lock is taken before calling this
751 PageInfo* Chunk::getPageInfo(Database *db, void *ptr)
753 if (allocSize_ < PAGE_SIZE - sizeof(PageInfo)) {
754 int rem = (long) ptr % PAGE_SIZE;
755 return (PageInfo*)(((char*)ptr) - rem);
756 } else {
757 //large size allocator
758 char *inPtr = (char*)ptr;
759 PageInfo* pageInfo = ((PageInfo*)firstPage_);
761 while( pageInfo != NULL )
763 if (inPtr > (char*) pageInfo && pageInfo->nextPageAfterMerge_ >inPtr)
764 return pageInfo;
765 pageInfo = (PageInfo*)pageInfo->nextPage_ ;
768 return NULL;
771 //If called on chunk used to store tuples, it returns the total number of rows
772 //present in the table
773 long Chunk::getTotalDataNodes()
775 long totalNodes =0;
776 if (0 == allocSize_) //->variable size allocator
778 Page *page = ((PageInfo*)firstPage_);
779 while(NULL != page)
781 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo));
782 while ((char*) varInfo < ((char*)page + PAGE_SIZE))
784 if (1 == varInfo->isUsed_) totalNodes++;
785 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
786 +varInfo->size_);
788 page = ((PageInfo*) page)->nextPage_;
790 return totalNodes;
793 //TODO::for large size allocator
794 if (allocSize_ >PAGE_SIZE)//->each page has only one data node
796 Page *page = ((PageInfo*)firstPage_);
797 while(NULL != page)
799 //current it page wise later this will done
800 if(1==*(int*)(((char*)page)+sizeof(PageInfo)))
801 totalNodes++;
802 page = ((PageInfo*) page)->nextPage_;
804 return totalNodes;
807 int noOfDataNodes=(int) os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_);
808 PageInfo* pageInfo = ((PageInfo*)firstPage_);
809 char *data = ((char*)firstPage_) + sizeof(PageInfo);
810 int i=0;
811 while( pageInfo != NULL )
813 data = ((char*)pageInfo) + sizeof(PageInfo);
814 for (i = 0; i< noOfDataNodes; i++)
816 if (*((InUse*)data) == 1) { totalNodes++;}
817 data = data + allocSize_;
819 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
821 return totalNodes;
824 //TODO::for other type of allocators
825 int Chunk::compact(int procSlot)
827 PageInfo* pageInfo = ((PageInfo*)firstPage_);
828 PageInfo* prevPage = pageInfo;
829 if (NULL == pageInfo)
831 return 0;
833 int ret = getChunkMutex(procSlot);
834 if (ret != 0)
836 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
837 return ret;
839 pageInfo = (PageInfo*)pageInfo->nextPage_;
840 if (0 == allocSize_)
842 while( pageInfo != NULL )
844 bool flag = false;
845 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)pageInfo) +
846 sizeof(PageInfo));
847 while ((char*) varInfo < ((char*)pageInfo + PAGE_SIZE))
849 if (1 == varInfo->isUsed_) {flag=true; break;}
850 varInfo = (VarSizeInfo*)((char*)varInfo + sizeof(VarSizeInfo)
851 +varInfo->size_);
853 if (!flag) {
854 printDebug(DM_VarAlloc,"Freeing unused page in varsize allocator %x\n", pageInfo);
855 prevPage->nextPage_ = pageInfo->nextPage_;
856 pageInfo->isUsed_ = 0;
858 prevPage = pageInfo;
859 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
860 printDebug(DM_VarAlloc,"compact iter %x\n", pageInfo);
862 }else if (allocSize_ < PAGE_SIZE)
864 while( pageInfo != NULL )
866 bool flag = false;
867 int noOfDataNodes=(int) os::floor((PAGE_SIZE - sizeof(PageInfo))/allocSize_);
868 char *data = ((char*)pageInfo) + sizeof(PageInfo);
869 for (int i = 0; i< noOfDataNodes ; i++)
871 if (1 == *((InUse*)data)) { flag = true; break; }
872 data = data +allocSize_;
874 if (!flag) {
875 printDebug(DM_Alloc,"Freeing unused page in fixed allocator %x\n", pageInfo);
876 prevPage->nextPage_ = pageInfo->nextPage_;
877 pageInfo->isUsed_ = 0;
878 pageInfo = (PageInfo*)(((PageInfo*)prevPage)->nextPage_) ;
879 }else{
880 prevPage = pageInfo;
881 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
883 printDebug(DM_Alloc,"compact iter %x\n", pageInfo);
886 releaseChunkMutex(procSlot);
887 return 0;
890 int Chunk::totalPages()
892 //logic is same for variable size and for large data node allocator.
893 PageInfo* pageInfo = ((PageInfo*)firstPage_);
894 int totPages=0;
895 while( pageInfo != NULL )
897 totPages++;
898 pageInfo = (PageInfo*)(((PageInfo*)pageInfo)->nextPage_) ;
900 return totPages;
903 int Chunk::initMutex()
905 return chunkMutex_.init("Chunk");
907 int Chunk::getChunkMutex(int procSlot)
909 return chunkMutex_.getLock(procSlot);
911 int Chunk::releaseChunkMutex(int procSlot)
913 return chunkMutex_.releaseLock(procSlot);
915 int Chunk::destroyMutex()
917 return chunkMutex_.destroy();
919 int Chunk::splitDataBucket(VarSizeInfo *varInfo, size_t needSize, int pSlot, DbRetVal *rv)
921 int remSpace = varInfo->size_ - sizeof(VarSizeInfo) - needSize;
922 //varInfo->isUsed_ = 1;
923 int ret = Mutex::CAS((int*)&varInfo->isUsed_ , 0, 1);
924 if(ret !=0) {
925 printDebug(DM_Warning, "Unable to set I isUsed flag");
926 *rv = ErrLockTimeOut;
927 return 1;
929 //varInfo->size_ = needSize;
930 ret = Mutex::CAS((int*)&varInfo->size_, varInfo->size_ , needSize);
931 if(ret !=0) {
932 printError(ErrSysFatal, "Unable to set I size flag");
933 ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0);
934 if (ret !=0) printError(ErrSysFatal, "Unable to reset isUsed flag");
935 *rv = ErrSysFatal;
936 return 1;
938 VarSizeInfo *varInfo2 = (VarSizeInfo*)((char*)varInfo +
939 sizeof(VarSizeInfo) + varInfo->size_);
940 //varInfo2->isUsed_ = 0;
941 ret = Mutex::CAS((int*)&varInfo2->isUsed_ , varInfo2->isUsed_, 0);
942 if(ret !=0) {
943 printError(ErrSysFatal, "Unable to set II isUsed flag");
944 ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0);
945 if (ret !=0) printError(ErrSysFatal, "Unable to reset isUsed flag");
946 *rv = ErrSysFatal;
947 return 1;
949 //varInfo2->size_ = remSpace;
950 ret = Mutex::CAS((int*)&varInfo2->size_, varInfo2->size_ , remSpace);
951 if(ret !=0) {
952 printError(ErrSysFatal, "Unable to set II size flag");
953 ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0);
954 if (ret !=0) printError(ErrSysFatal, "Unable to reset isUsed flag");
955 *rv = ErrSysFatal;
956 return 1;
958 printDebug(DM_VarAlloc, "Remaining space is %d\n", remSpace);
959 return 0;
963 int Chunk::createDataBucket(Page *page, size_t totalSize, size_t needSize, int pslot)
965 //already db alloc mutex is taken
966 VarSizeInfo *varInfo = (VarSizeInfo*)(((char*)page) + sizeof(PageInfo));
967 //varInfo->isUsed_ = 0;
968 int ret = Mutex::CAS((int*)&varInfo->isUsed_ , varInfo->isUsed_, 0);
969 if(ret !=0) {
970 printError(ErrSysFatal, "Fatal:Unable to get lock to set isUsed flag");
972 //varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
973 ret = Mutex::CAS((int*)&varInfo->size_, varInfo->size_ ,
974 PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo));
975 if(ret !=0) {
976 printError(ErrSysFatal, "Unable to get lock to set size");
978 DbRetVal rv =OK;
979 return splitDataBucket(varInfo, needSize, pslot, &rv);
981 void Chunk::setChunkNameForSystemDB(int id)
983 strcpy(chunkName,ChunkName[id]);
986 void Chunk::print()
988 printf(" <Chunk Id> %d </Chunk Id> \n",chunkID_);
989 printf(" <TotalPages> %d </TotalPages> \n",totalPages());
990 printf(" <ChunkName > %s </ChunkName> \n",getChunkName());
991 printf(" <TotalDataNodes> %d </TotalDataNodes> \n",getTotalDataNodes());
992 printf(" <SizeOfDataNodes> %d </SizeOfDataNodes> \n",getSize());
993 printf(" <Allocation Type> ");
994 if(allocType_==0)
996 printf("FixedSizeAllocator ");
997 }else if(allocType_==1)
999 printf("VariableSizeAllocator ");
1000 }else
1002 printf("UnknownAllocator ");
1005 printf("</Allocation Type>\n");