1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
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 ***************************************************************************/
21 #include<CatalogTables.h>
23 // sets the size of the Chunk allocator for fixed size
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);
35 allocSize_
= needSize
;
37 allocSize_
= (multiple
+ 1) * sizeof(size_t);
40 void* Chunk::allocateForLargeDataSize(Database
*db
)
42 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
43 DbRetVal ret
= db
->getAllocDatabaseMutex();
46 printError(ErrLockTimeOut
,"Unable to acquire alloc database Mutex");
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");
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_
);
67 db
->releaseAllocDatabaseMutex();
68 printError(ErrNoMemory
,"No more free pages in the database");
71 printDebug(DM_Alloc
, "Chunk ID:%d Large Data Item newPage:%x",
73 int multiple
= (int) os::floor(allocSize_
/ PAGE_SIZE
);
74 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
76 pageInfo
->setPageAsUsed(offset
);
79 //((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo;
80 int retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
81 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)pageInfo
);
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
);
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);
96 printError(ErrLockTimeOut
, "Fatal:Unable to set hasFreeSpace");
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",
110 printDebug(DM_Alloc
, "Scan from firstPage:%x for free nodes",
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_
;
126 if (i
!= noOfDataNodes
) break;
128 printDebug(DM_Alloc
, "Chunk ID: %d Page :%x does not have free nodes",
130 pageIter
= (PageInfo
*)((PageInfo
*) pageIter
)->nextPage_
;
132 if (NULL
== pageIter
) {
133 *status
= ErrNoMemory
;
136 printDebug(DM_Alloc
,"ChunkID:%d Scan for free node End:Page :%x",
138 //*((InUse*)data) = 1;
139 #if defined(__sparcv9)
140 int ret
= Mutex::CASL((InUse
*)data
, 0, 1);
142 int ret
= Mutex::CAS((InUse
*)data
, 0, 1);
145 *status
= ErrLockTimeOut
;
146 //printError(ErrLockTimeOut, "Unable to allocate from first page. Retry...");
149 return data
+ sizeof(InUse
);
152 void* Chunk::allocateFromNewPage(Database
*db
, DbRetVal
*status
)
154 DbRetVal ret
= db
->getAllocDatabaseMutex();
157 printDebug(DM_Warning
,"Unable to acquire alloc database Mutex Chunkid:%d", chunkID_
);
158 *status
= ErrLockTimeOut
;
161 //get a new page from db
162 Page
*page
= db
->getFreePage();
164 printError(ErrNoMemory
, "Unable to allocate page");
165 db
->releaseAllocDatabaseMutex();
166 *status
= ErrNoMemory
;
169 printDebug(DM_Alloc
, "ChunkID:%d Normal Data Item newPage:%x",
171 //Initialize pageInfo for this new page
172 PageInfo
*pInfo
= (PageInfo
*)page
;
173 pInfo
->setPageAsUsed(0);
175 char* data
= ((char*)page
) + sizeof(PageInfo
);
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
);
187 pInfo
->setPageAsFree();
188 printDebug(DM_Warning
, "Unable to get lock to set chunk list.");
189 *status
= ErrLockTimeOut
;
193 //make this new page as the current page
195 retVal
= Mutex::CASL((long*)&curPage_
, (long)curPage_
, (long)page
);
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
;
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
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
);
239 /*int ret = getChunkMutex(db->procSlot);
242 if (status != NULL) *status = ErrLockTimeOut;
243 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
246 int i
= noOfDataNodes
;
247 if (pageInfo
->hasFreeSpace_
== 1)
249 for (i
= 1; i
< noOfDataNodes
; i
++)
251 if (*((InUse
*)data
) == 1) data
= data
+ allocSize_
;
256 printDebug(DM_Alloc
, "ChunkID:%d Node which might be free is %d",
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);
268 *status
= ErrLockTimeOut
;
269 printDebug(DM_Warning
, "Unable to set hasFreespace");
272 //if (chunkID_ == LockTableId || chunkID_ == TransHasTableId)
275 data
= (char*) allocateFromFirstPage(db
, noOfDataNodes
, status
);
276 if (NULL
== data
&& *status
!= ErrLockTimeOut
)
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
;
289 data = (char*) allocateFromNewPage(db, status);
290 if (NULL == data && *status != ErrLockTimeOut)
292 data = (char*) allocateFromFirstPage(db, noOfDataNodes);
295 printError(ErrNoMemory, "No memory in any of the pages:Increase db size");
296 *status = ErrNoMemory;
300 //releaseChunkMutex(db->procSlot);
303 //*((InUse*)data) = 1;
304 #if defined(__sparcv9)
305 int ret
= Mutex::CASL((InUse
*)data
, 0, 1);
307 int ret
= Mutex::CAS((InUse
*)data
, 0, 1);
310 *status
= ErrLockTimeOut
;
311 printDebug(DM_Warning
, "Unable to set isUsed : retry...");
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_
);
326 pageInfo
= (PageInfo
*)db
->getFreePage(size
);
328 pageInfo
= (PageInfo
*)db
->getFreePage(allocSize_
);
329 if (NULL
== pageInfo
)
331 printError(ErrNoMemory
,"No more free pages in the database:Increase db size");
334 printDebug(DM_VarAlloc
,"Chunk::alnextPageAfterMerge_locate Large Data Item id:%d Size:%d curPage:%x ",
335 chunkID_
, size
, curPage_
);
336 //TODO:: logic pending
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);
347 int ret
= Mutex::CAS((InUse
*)data
, 0, 1);
350 printError(ErrLockTimeOut
, "Lock Timeout: retry...");
354 ret
= Mutex::CAS(&pageInfo
->hasFreeSpace_
, pageInfo
->hasFreeSpace_
, 0);
355 if (ret
!=0) printError(ErrSysFatal
, "Unable to set hashFreeSpace");
356 return data
+ sizeof(InUse
);
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);
366 printError(ErrLockTimeOut
, "Unable to get lock for var alloc. Retry...");
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.
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
);
393 printDebug(DM_Warning
, "No free space in any of the pages already being used");
395 DbRetVal ret
= db
->getAllocDatabaseMutex();
398 printError(ErrLockTimeOut
,"Unable to acquire alloc database Mutex");
401 Page
*newPage
= db
->getFreePage();
404 db
->releaseAllocDatabaseMutex();
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");
415 db
->releaseAllocDatabaseMutex();
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
);
423 printError(ErrSysFatal
, "Unable to get lock to set chunk next page");
424 pInfo
->setPageAsFree();
425 db
->releaseAllocDatabaseMutex();
429 //curPage_ = newPage;
430 retVal
= Mutex::CASL((long*) &curPage_
, (long)curPage_
, (long)newPage
);
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();
441 db
->releaseAllocDatabaseMutex();
442 char *data
= ((char*)newPage
) + sizeof(PageInfo
) + sizeof(VarSizeInfo
);
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
) +
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
);
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);
478 printDebug(DM_Warning
, "Unable to get lock for var alloc size:%d ", size
);
479 *rv
= ErrLockTimeOut
;
480 releaseChunkMutex(pslot
);
483 releaseChunkMutex(pslot
);
484 return (char *) varInfo
+ sizeof(VarSizeInfo
);
488 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
491 releaseChunkMutex(pslot
);
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
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
);
513 /*int ret = getChunkMutex(db->procSlot);
516 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
517 *status = ErrLockTimeOut;
520 if (alignedSize
> PAGE_SIZE
)
522 data
= allocateForLargeDataSize(db
, alignedSize
);
526 data
= allocateFromCurPageForVarSize(alignedSize
, db
->procSlot
, status
);
529 //No available spaces in the current 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);
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",
548 Page
*page
= ((PageInfo
*)firstPage_
);
549 size_t alignedSize
= os::alignLong(size
);
550 if ( 0 != getChunkMutex(pslot
)) { *rv
= ErrLockTimeOut
; return NULL
; }
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
);
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);
573 printDebug(DM_Warning
,"Unable to get lock to set isUsed flag.");
574 *rv
= ErrLockTimeOut
;
575 releaseChunkMutex(pslot
);
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
)
586 printDebug(DM_VarAlloc
, "Chunk:This page does not have free data nodes page:%x", page
);
587 page
= ((PageInfo
*) page
)->nextPage_
;
589 releaseChunkMutex(pslot
);
593 void Chunk::freeForVarSizeAllocator(void *ptr
, int pslot
)
595 /*int ret = getChunkMutex(pslot);
598 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
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_
;
609 if(NULL
==pInfo
) break;
610 if (pInfo
== pageInfo
) {found
= true; break; }
612 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
616 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
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);
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);
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
);
642 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
645 PageInfo
*pageInfo
= (PageInfo
*)(((char*)
646 ptr
) - (sizeof(PageInfo
) + sizeof(InUse
)));
647 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
651 if (pInfo
== pageInfo
) {found
= true; break; }
653 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
657 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
658 releaseChunkMutex(pslot
);
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");
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
);
686 //Frees the memory pointed by ptr
687 void Chunk::free(Database
*db
, void *ptr
)
691 freeForVarSizeAllocator(ptr
, db
->procSlot
);
694 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
)) / allocSize_
);
696 if (0 == noOfDataNodes
)
698 freeForLargeAllocator(ptr
, db
->procSlot
);
701 /*int ret = getChunkMutex(db->procSlot);
704 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
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_
);
715 #if defined(__sparcv9)
716 int ret
= Mutex::CASL(((InUse
*)ptr
-1), 1, 0);
718 int ret
= Mutex::CAS(((InUse
*)ptr
-1), 1, 0);
721 printError(ErrSysFatal
, "Unable to get lock to free for %x", ptr
);
725 pageInfo
= getPageInfo(db
, ptr
);
726 if (NULL
== pageInfo
)
728 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
729 //releaseChunkMutex(db->procSlot);
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
);
738 ret
= Mutex::CAS((int*)&pageInfo
->hasFreeSpace_
, pageInfo
->hasFreeSpace_
, 1);
740 printError(ErrSysFatal
, "Unable to get lock to set hasFreeSpace");
742 //releaseChunkMutex(db->procSlot);
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
);
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
)
765 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
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()
776 if (0 == allocSize_
) //->variable size allocator
778 Page
*page
= ((PageInfo
*)firstPage_
);
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
)
788 page
= ((PageInfo
*) page
)->nextPage_
;
793 //TODO::for large size allocator
794 if (allocSize_
>PAGE_SIZE
)//->each page has only one data node
796 Page
*page
= ((PageInfo
*)firstPage_
);
799 //current it page wise later this will done
800 if(1==*(int*)(((char*)page
)+sizeof(PageInfo
)))
802 page
= ((PageInfo
*) page
)->nextPage_
;
807 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
808 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
809 char *data
= ((char*)firstPage_
) + sizeof(PageInfo
);
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_
) ;
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
)
833 int ret
= getChunkMutex(procSlot
);
836 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
839 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
842 while( pageInfo
!= NULL
)
845 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) +
847 while ((char*) varInfo
< ((char*)pageInfo
+ PAGE_SIZE
))
849 if (1 == varInfo
->isUsed_
) {flag
=true; break;}
850 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
854 printDebug(DM_VarAlloc
,"Freeing unused page in varsize allocator %x\n", pageInfo
);
855 prevPage
->nextPage_
= pageInfo
->nextPage_
;
856 pageInfo
->isUsed_
= 0;
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
)
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_
;
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_
) ;
881 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
883 printDebug(DM_Alloc
,"compact iter %x\n", pageInfo
);
886 releaseChunkMutex(procSlot
);
890 int Chunk::totalPages()
892 //logic is same for variable size and for large data node allocator.
893 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
895 while( pageInfo
!= NULL
)
898 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
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);
925 printDebug(DM_Warning
, "Unable to set I isUsed flag");
926 *rv
= ErrLockTimeOut
;
929 //varInfo->size_ = needSize;
930 ret
= Mutex::CAS((int*)&varInfo
->size_
, varInfo
->size_
, needSize
);
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");
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);
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");
949 //varInfo2->size_ = remSpace;
950 ret
= Mutex::CAS((int*)&varInfo2
->size_
, varInfo2
->size_
, remSpace
);
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");
958 printDebug(DM_VarAlloc
, "Remaining space is %d\n", remSpace
);
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);
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
));
976 printError(ErrSysFatal
, "Unable to get lock to set size");
979 return splitDataBucket(varInfo
, needSize
, pslot
, &rv
);
981 void Chunk::setChunkNameForSystemDB(int id
)
983 strcpy(chunkName
,ChunkName
[id
]);
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> ");
996 printf("FixedSizeAllocator ");
997 }else if(allocType_
==1)
999 printf("VariableSizeAllocator ");
1002 printf("UnknownAllocator ");
1005 printf("</Allocation Type>\n");