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 (BITSET(pageInfo
->flags
, HAS_SPACE
))
53 char *data
= ((char*)curPage_
) + sizeof(PageInfo
);
54 int oldVal
= pageInfo
->flags
;
56 CLEARBIT(newVal
, HAS_SPACE
);
57 int retVal
= Mutex::CAS(&pageInfo
->flags
, oldVal
, newVal
);
58 if (retVal
!=0) printError(ErrSysFatal
, "Unable to set flags");
60 //Mutex::CAS((InUse*)data , 0, 1);
61 db
->releaseAllocDatabaseMutex();
62 return data
+ sizeof(InUse
);
65 //no space in curpage , get new page from database
66 pageInfo
= (PageInfo
*)db
->getFreePage(allocSize_
);
69 db
->releaseAllocDatabaseMutex();
70 printError(ErrNoMemory
,"No more free pages in the database");
73 printDebug(DM_Alloc
, "Chunk ID:%d Large Data Item newPage:%x",
75 int multiple
= (int) os::floor(allocSize_
/ PAGE_SIZE
);
76 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
78 pageInfo
->setPageAsUsed(offset
);
79 setPageDirty(pageInfo
);
83 //((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo;
84 int retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
85 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)pageInfo
);
87 printError(ErrLockTimeOut
, "Fatal: Unable to create page link.");
90 //Make this as current page
91 //curPage_ = (Page*) pageInfo;
92 retVal
= Mutex::CASL((long*) &curPage_
, (long)curPage_
, (long)pageInfo
);
94 printError(ErrLockTimeOut
, "Fatal:Unable to set current page");
97 char* data
= ((char*)curPage_
) + sizeof(PageInfo
);
98 int oldVal
= pageInfo
->flags
;
100 CLEARBIT(newVal
, HAS_SPACE
);
101 retVal
= Mutex::CAS(&pageInfo
->flags
, oldVal
, newVal
);
103 printError(ErrLockTimeOut
, "Fatal:Unable to set flags");
106 //Mutex::CASL((InUse*)data , 0, 1);
107 db
->releaseAllocDatabaseMutex();
108 return data
+ sizeof(InUse
);
112 void* Chunk::allocateFromFirstPage(Database
*db
, int noOfDataNodes
, DbRetVal
*status
)
114 PageInfo
*pageIter
= ((PageInfo
*)firstPage_
);
115 printDebug(DM_Alloc
, "Chunk ID:%d. No free page in database",
117 printDebug(DM_Alloc
, "Scan from firstPage:%x for free nodes",
121 //scan from first page to locate a free node available
122 while(NULL
!= pageIter
)
124 data
= ((char*)pageIter
) + sizeof(PageInfo
);
125 if (BITSET(pageIter
->flags
, HAS_SPACE
))
127 for (i
= 0; i
< noOfDataNodes
; i
++)
129 if (1 == *((InUse
*)data
))
130 data
= data
+ allocSize_
;
133 if (i
!= noOfDataNodes
) break;
135 printDebug(DM_Alloc
, "Chunk ID: %d Page :%x does not have free nodes",
137 pageIter
= (PageInfo
*)((PageInfo
*) pageIter
)->nextPage_
;
139 if (NULL
== pageIter
) {
140 *status
= ErrNoMemory
;
143 printDebug(DM_Alloc
,"ChunkID:%d Scan for free node End:Page :%x",
145 //*((InUse*)data) = 1;
146 #if defined(__sparcv9)
147 int ret
= Mutex::CASL((InUse
*)data
, 0, 1);
149 int ret
= Mutex::CAS((InUse
*)data
, 0, 1);
152 *status
= ErrLockTimeOut
;
153 //printError(ErrLockTimeOut, "Unable to allocate from first page. Retry...");
156 return data
+ sizeof(InUse
);
159 void* Chunk::allocateFromNewPage(Database
*db
, DbRetVal
*status
)
161 DbRetVal ret
= db
->getAllocDatabaseMutex();
164 printDebug(DM_Warning
,"Unable to acquire alloc database Mutex Chunkid:%d", chunkID_
);
165 *status
= ErrLockTimeOut
;
168 //get a new page from db
169 Page
*page
= db
->getFreePage();
171 printError(ErrNoMemory
, "Unable to allocate page");
172 db
->releaseAllocDatabaseMutex();
173 *status
= ErrNoMemory
;
176 printDebug(DM_Alloc
, "ChunkID:%d Normal Data Item newPage:%x",
178 //Initialize pageInfo for this new page
179 PageInfo
*pInfo
= (PageInfo
*)page
;
180 pInfo
->setPageAsUsed(0);
183 char* data
= ((char*)page
) + sizeof(PageInfo
);
185 //Mutex::CAS((int*)data , 0, 1);
187 //create the link between old page and the newly created page
188 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
190 long oldPage
= (long)pageInfo
->nextPage_
;
191 //pageInfo->nextPage_ = page;
192 int retVal
= Mutex::CASL((long*)&pageInfo
->nextPage_
, (long)pageInfo
->nextPage_
, (long)page
);
195 pInfo
->setPageAsFree();
196 printDebug(DM_Warning
, "Unable to get lock to set chunk list.");
197 *status
= ErrLockTimeOut
;
201 //make this new page as the current page
203 retVal
= Mutex::CASL((long*)&curPage_
, (long)curPage_
, (long)page
);
206 pInfo
->setPageAsFree();
207 retVal
= Mutex::CASL((long*)&pageInfo
->nextPage_
, (long)pageInfo
->nextPage_
, (long)oldPage
);
208 if (retVal
!=0) printError(ErrSysFatal
, "Fatal: Unable to reset the nextPage");
209 printDebug(DM_Warning
, "Unable to get lock to set curPage");
210 *status
= ErrLockTimeOut
;
214 db
->releaseAllocDatabaseMutex();
215 return data
+ sizeof(InUse
);
218 //Allocates memory to store data
219 //TODO::check whether it is locked before allocating.
220 //delete tuple will set the usedflag to true, but locks will be held
221 //till commit and it shall be rolledback.So make sure that it does not
222 //allocate deleted tuple which is yet to be commited.
224 void* Chunk::allocate(Database
*db
, DbRetVal
*status
)
226 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
228 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
229 char *data
= ((char*)curPage_
) + sizeof(PageInfo
);
230 printDebug(DM_Alloc
, "Chunk::allocate id:%d curPage:%x noOfDataNodes:%d",
231 chunkID_
, curPage_
, noOfDataNodes
);
233 //1.scan through data list and find if any is free to use in current page
234 //2.If there is none then
235 // a) get new free page from db. set the prev->next to point
237 //4. b) initialize the free page to zero and get first data ptr.
238 //5.If there is one, return that
240 //For allocation more than PAGE_SIZE
241 if (0 == noOfDataNodes
)
243 data
= (char*) allocateForLargeDataSize(db
);
247 /*int ret = getChunkMutex(db->procSlot);
250 if (status != NULL) *status = ErrLockTimeOut;
251 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
254 int i
= noOfDataNodes
;
255 if (BITSET(pageInfo
->flags
, HAS_SPACE
))
257 for (i
= 1; i
< noOfDataNodes
; i
++)
259 if (*((InUse
*)data
) == 1) data
= data
+ allocSize_
;
264 printDebug(DM_Alloc
, "ChunkID:%d Node which might be free is %d",
266 //It comes here if the pageInfo hasFreeSpace
267 //or there are no free data space in this page
268 if (i
== noOfDataNodes
&& *((InUse
*)data
) == 1)
271 printDebug(DM_Alloc
, "ChunkID:%d curPage does not have free nodes.", chunkID_
);
272 //there are no free data space in this page
273 int oldVal
= pageInfo
->flags
;
275 CLEARBIT(newVal
, HAS_SPACE
);
276 int ret
= Mutex::CAS(&pageInfo
->flags
, oldVal
, newVal
);
278 *status
= ErrLockTimeOut
;
279 printDebug(DM_Warning
, "Unable to set hasFreespace");
283 data
= (char*) allocateFromFirstPage(db
, noOfDataNodes
, status
);
284 if (NULL
== data
&& *status
!= ErrLockTimeOut
)
287 data
= (char*) allocateFromNewPage(db
, status
);
288 if (data
== NULL
&& *status
!= ErrLockTimeOut
)
290 printError(ErrNoMemory
, "No memory in any of the pages:Increase db size");
291 *status
= ErrNoMemory
;
294 setPageDirty(db
, data
);
297 //*((InUse*)data) = 1;
298 #if defined(__sparcv9)
299 int ret
= Mutex::CASL((InUse
*)data
, 0, 1);
301 int ret
= Mutex::CAS((InUse
*)data
, 0, 1);
304 *status
= ErrLockTimeOut
;
305 printDebug(DM_Warning
, "Unable to set isUsed : retry...");
308 setPageDirty(db
, data
);
309 return data
+ sizeof(InUse
);
312 void Chunk::setPageDirty(Database
*db
, void *ptr
)
314 if (chunkID_
< LastCatalogID
) return;
315 PageInfo
*pageInfo
= getPageInfo(db
, ptr
);
316 if (NULL
== pageInfo
)
318 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
321 SETBIT(pageInfo
->flags
, IS_DIRTY
);
324 void Chunk::setPageDirty(PageInfo
*pInfo
)
326 if (chunkID_
< LastCatalogID
) return;
327 SETBIT(pInfo
->flags
, IS_DIRTY
);
330 void* Chunk::allocateForLargeDataSize(Database
*db
, size_t size
)
332 //no need to take chunk mutexes for this, as we are taking alloc database mutex
333 int multiple
= (int) os::floor(size
/ PAGE_SIZE
);
334 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
335 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
337 pageInfo
= (PageInfo
*)db
->getFreePage(size
);
339 pageInfo
= (PageInfo
*)db
->getFreePage(allocSize_
);
340 if (NULL
== pageInfo
)
342 printError(ErrNoMemory
,"No more free pages in the database:Increase db size");
345 printDebug(DM_VarAlloc
,"Chunk::alnextPageAfterMerge_locate Large Data Item id:%d Size:%d curPage:%x ",
346 chunkID_
, size
, curPage_
);
347 //TODO:: logic pending
349 //large size allocate for FixedSize data
350 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
351 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
352 curPage_
= (Page
*) pageInfo
;
353 char* data
= ((char*)curPage_
) + sizeof(PageInfo
);
354 //*((InUse*)data) = 1;
355 #if defined(__sparcv9)
356 int ret
= Mutex::CASL((InUse
*)data
, 0, 1);
358 int ret
= Mutex::CAS((InUse
*)data
, 0, 1);
361 printError(ErrLockTimeOut
, "Lock Timeout: retry...");
365 int oldVal
= pageInfo
->flags
;
367 CLEARBIT(newVal
, HAS_SPACE
);
368 SETBIT(newVal
, IS_DIRTY
);
369 ret
= Mutex::CAS(&pageInfo
->flags
, oldVal
, newVal
);
370 if (ret
!=0) printError(ErrSysFatal
, "Unable to set flags");
371 return data
+ sizeof(InUse
);
373 //large size allocate for varSize data
374 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) + sizeof(PageInfo
));
375 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
376 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
377 curPage_
= (Page
*) pageInfo
;
378 varInfo
->size_
= size
;
379 int ret
= Mutex::CAS(&varInfo
->isUsed_
, varInfo
->isUsed_
, 1);
381 printError(ErrLockTimeOut
, "Unable to get lock for var alloc. Retry...");
385 SETBIT(pageInfo
->flags
, IS_DIRTY
);
386 return (char *) varInfo
+ sizeof(VarSizeInfo
);
388 //REDESIGN MAY BE REQUIRED:Lets us live with this for now.
389 //what happens to the space lets say 10000 bytes is allocated
390 //it needs 2 pages,= 16000 bytes, 6000 bytes should not be wasted
391 //in this case.So need to take of this.
392 //Will be coded at later stage as this is developed to support
393 //undo logging and currently we shall assume that the logs generated
394 //wont be greater than PAGE_SIZE.
400 void* Chunk::allocFromNewPageForVarSize(Database
*db
, size_t size
, int pslot
, DbRetVal
*rv
)
402 //Should be called only for data items <PAGE_SIZE
403 void *vnode
= varSizeFirstFitAllocate(size
, pslot
, rv
);
408 printDebug(DM_Warning
, "No free space in any of the pages already being used");
410 DbRetVal ret
= db
->getAllocDatabaseMutex();
413 printError(ErrLockTimeOut
,"Unable to acquire alloc database Mutex");
416 Page
*newPage
= db
->getFreePage();
419 db
->releaseAllocDatabaseMutex();
423 printDebug(DM_VarAlloc
, "ChunkID:%d New Page: %x ", chunkID_
, newPage
);
424 PageInfo
*pInfo
= (PageInfo
*) newPage
;
425 pInfo
->setPageAsUsed(0);
427 if (1 == createDataBucket(newPage
, PAGE_SIZE
, size
, pslot
))
429 printError(ErrSysFatal
, "Split failed in new page...Should never happen");
431 db
->releaseAllocDatabaseMutex();
434 long oldPage
= (long)((PageInfo
*)curPage_
)->nextPage_
;
435 //((PageInfo*)curPage_)->nextPage_ = newPage;
436 int retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
437 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)newPage
);
439 printError(ErrSysFatal
, "Unable to get lock to set chunk next page");
440 pInfo
->setPageAsFree();
441 db
->releaseAllocDatabaseMutex();
445 //curPage_ = newPage;
446 retVal
= Mutex::CASL((long*) &curPage_
, (long)curPage_
, (long)newPage
);
448 printError(ErrSysFatal
, "Unable to get lock to set curPage");
449 retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
450 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)oldPage
);
451 if (retVal
!=0 ) printError(ErrSysFatal
, "Unable to reset curPage");
452 pInfo
->setPageAsFree();
453 db
->releaseAllocDatabaseMutex();
457 db
->releaseAllocDatabaseMutex();
458 char *data
= ((char*)newPage
) + sizeof(PageInfo
) + sizeof(VarSizeInfo
);
462 //Allocates from the current page of the chunk.
463 //Scans through the VarSizeInfo objects in the page and gets the free slot
464 void* Chunk::allocateFromCurPageForVarSize(size_t size
, int pslot
, DbRetVal
*rv
)
466 //Should be called only for data items <PAGE_SIZE
467 Page
*page
= ((PageInfo
*)curPage_
);
468 printDebug(DM_VarAlloc
, "Chunk::allocate Normal Data Item id:%d Size:%d curPage:%x ",
469 chunkID_
, size
, curPage_
);
470 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) +
472 if ( 0 != getChunkMutex(pslot
)) { *rv
= ErrLockTimeOut
; return NULL
; }
473 while ((char*) varInfo
< ((char*)page
+ PAGE_SIZE
))
475 if (0 == varInfo
->isUsed_
)
477 if( size
+ sizeof(VarSizeInfo
) < varInfo
->size_
)
479 if (1 == splitDataBucket(varInfo
, size
, pslot
, rv
))
481 printDebug(DM_Warning
, "Unable to split the data bucket");
482 releaseChunkMutex(pslot
);
485 printDebug(DM_VarAlloc
, "Chunkid:%d splitDataBucket: Size: %d Item:%x ",
486 chunkID_
, size
, varInfo
);
487 releaseChunkMutex(pslot
);
488 return (char*)varInfo
+ sizeof(VarSizeInfo
);
490 else if (size
== varInfo
->size_
) {
491 //varInfo->isUsed_ = 1;
492 int ret
= Mutex::CAS(&varInfo
->isUsed_
, 0, 1);
494 printDebug(DM_Warning
, "Unable to get lock for var alloc size:%d ", size
);
495 *rv
= ErrLockTimeOut
;
496 releaseChunkMutex(pslot
);
499 releaseChunkMutex(pslot
);
500 return (char *) varInfo
+ sizeof(VarSizeInfo
);
504 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
507 releaseChunkMutex(pslot
);
511 //Allocates memory to store data of variable size
512 void* Chunk::allocate(Database
*db
, size_t size
, DbRetVal
*status
)
514 if (0 == size
) return NULL
;
515 //check if the size is more than PAGE_SIZE
516 //if it is more than the PAGE_SIZE, then allocate new
517 //page using database and then link the curPage to the
518 //newly allocated page
519 //if it is less than PAGE_SIZE, then check the curpage for
520 //free memory of specified size
521 //if not available, then scan from the firstPage for the free
524 //TODO::During the scan, merge nearby nodes if both are free
525 //if not available then allocate new page
527 size_t alignedSize
= os::alignLong(size
);
529 /*int ret = getChunkMutex(db->procSlot);
532 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
533 *status = ErrLockTimeOut;
536 if (alignedSize
> PAGE_SIZE
)
538 data
= allocateForLargeDataSize(db
, alignedSize
);
542 data
= allocateFromCurPageForVarSize(alignedSize
, db
->procSlot
, status
);
545 //No available spaces in the current page.
547 data
= allocFromNewPageForVarSize(db
, alignedSize
, db
->procSlot
, status
);
548 if (NULL
== data
&& *status
!=ErrLockTimeOut
) {
549 printError(ErrNoMemory
, "No memory in any of the pages:Increase db size");
550 *status
= ErrNoMemory
;
554 //releaseChunkMutex(db->procSlot);
558 //Assumes chunk mutex is already taken, before calling this
559 void* Chunk::varSizeFirstFitAllocate(size_t size
, int pslot
, DbRetVal
*rv
)
561 printDebug(DM_VarAlloc
, "Chunk::varSizeFirstFitAllocate size:%d firstPage:%x",
564 Page
*page
= ((PageInfo
*)firstPage_
);
565 size_t alignedSize
= os::alignLong(size
);
566 if ( 0 != getChunkMutex(pslot
)) { *rv
= ErrLockTimeOut
; return NULL
; }
569 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
570 while ((char*) varInfo
< ((char*)page
+ PAGE_SIZE
))
572 if (0 == varInfo
->isUsed_
)
574 if( alignedSize
+sizeof(VarSizeInfo
) < varInfo
->size_
)
576 if( 1 == splitDataBucket(varInfo
, alignedSize
, pslot
, rv
))
578 printDebug(DM_Warning
, "Unable to split the data bucket");
579 releaseChunkMutex(pslot
);
582 releaseChunkMutex(pslot
);
583 return ((char*)varInfo
) + sizeof(VarSizeInfo
);
585 else if (alignedSize
== varInfo
->size_
) {
586 //varInfo->isUsed_ = 1;
587 int ret
= Mutex::CAS((int*)&varInfo
->isUsed_
, 0, 1);
589 printDebug(DM_Warning
,"Unable to get lock to set isUsed flag.");
590 *rv
= ErrLockTimeOut
;
591 releaseChunkMutex(pslot
);
594 printDebug(DM_VarAlloc
, "VarSizeFirstFitAllocate returning %x", ((char*)varInfo
) +sizeof(VarSizeInfo
));
595 releaseChunkMutex(pslot
);
596 return ((char *) varInfo
) + sizeof(VarSizeInfo
);
599 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
602 printDebug(DM_VarAlloc
, "Chunk:This page does not have free data nodes page:%x", page
);
603 page
= ((PageInfo
*) page
)->nextPage_
;
605 releaseChunkMutex(pslot
);
609 void Chunk::freeForVarSizeAllocator(void *ptr
, int pslot
)
611 /*int ret = getChunkMutex(pslot);
614 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
617 VarSizeInfo
*varInfo
= (VarSizeInfo
*)((char*)ptr
- sizeof(VarSizeInfo
));
618 //varInfo->isUsed_ = 0;
619 if(varInfo
->size_
> (PAGE_SIZE
- (sizeof(VarSizeInfo
)+sizeof(PageInfo
)))) {
620 PageInfo
*pageInfo
= (PageInfo
*)((char*)varInfo
- sizeof(PageInfo
));
621 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
625 if(NULL
==pInfo
) break;
626 if (pInfo
== pageInfo
) {found
= true; break; }
628 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
632 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
635 if(curPage_
== pageInfo
) {curPage_
= prev
; }
636 pageInfo
->isUsed_
= 0;
637 pageInfo
->nextPageAfterMerge_
= NULL
;
638 CLEARBIT(pageInfo
->flags
, IS_DIRTY
);
639 SETBIT(pageInfo
->flags
, HAS_SPACE
);
640 prev
->nextPage_
= pageInfo
->nextPage_
;
642 int ret
= Mutex::CAS((int*)&varInfo
->isUsed_
, 1, 0);
644 printError(ErrAlready
, "Fatal: Varsize double free for %x", ptr
);
648 printDebug(DM_VarAlloc
,"chunkID:%d Unset isUsed for %x", chunkID_
, varInfo
);
649 //releaseChunkMutex(pslot);
654 void Chunk::freeForLargeAllocator(void *ptr
, int pslot
)
656 //There will be max only one data element in a page.
657 //PageInfo is stored just before the data.
658 int ret
= getChunkMutex(pslot
);
661 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
664 PageInfo
*pageInfo
= (PageInfo
*)(((char*)
665 ptr
) - (sizeof(PageInfo
) + sizeof(InUse
)));
666 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
670 if (pInfo
== pageInfo
) {found
= true; break; }
672 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
676 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
677 releaseChunkMutex(pslot
);
680 os::memset(((char*)pageInfo
+sizeof(PageInfo
)), 0 , allocSize_
);
681 if(((PageInfo
*)firstPage_
)->nextPage_
!= NULL
){
682 pageInfo
->nextPageAfterMerge_
= NULL
;
683 //pageInfo->isUsed_ = 0;
684 ret
= Mutex::CAS((int*)&pageInfo
->isUsed_
, pageInfo
->isUsed_
, 0);
685 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set isUsed flag");
686 int oldVal
= pageInfo
->flags
;
688 SETBIT(newVal
, HAS_SPACE
);
689 ret
= Mutex::CAS((int*)&pageInfo
->flags
, oldVal
, newVal
);
690 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set flags");
691 if(pageInfo
== firstPage_
&& ((PageInfo
*)firstPage_
)->nextPage_
!= NULL
)
693 //firstPage_ = pageInfo->nextPage_ ;
694 ret
= Mutex::CASL((long*)&firstPage_
, (long) firstPage_
,
695 (long)pageInfo
->nextPage_
);
696 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set firstPage");
697 SETBIT(((PageInfo
*)firstPage_
)->flags
, IS_DIRTY
);
700 //prev->nextPage_ = pageInfo->nextPage_;
701 ret
= Mutex::CASL((long*)&prev
->nextPage_
, (long) prev
->nextPage_
,
702 (long)pageInfo
->nextPage_
);
703 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set nextPage");
704 SETBIT(prev
->flags
, IS_DIRTY
);
707 SETBIT(pageInfo
->flags
, IS_DIRTY
);
708 releaseChunkMutex(pslot
);
712 //Frees the memory pointed by ptr
713 void Chunk::free(Database
*db
, void *ptr
)
717 freeForVarSizeAllocator(ptr
, db
->procSlot
);
720 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
)) / allocSize_
);
722 if (0 == noOfDataNodes
)
724 freeForLargeAllocator(ptr
, db
->procSlot
);
727 /*int ret = getChunkMutex(db->procSlot);
730 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
733 //below is the code for freeing in fixed size allocator
735 //unset the used flag
736 //*((int*)ptr -1 ) = 0;
737 if (*((InUse
*)ptr
-1 ) == 0) {
738 printError(ErrSysFatal
, "Fatal:Data node already freed %x Chunk:%d", ptr
, chunkID_
);
741 #if defined(__sparcv9)
742 int ret
= Mutex::CASL(((InUse
*)ptr
-1), 1, 0);
744 int ret
= Mutex::CAS(((InUse
*)ptr
-1), 1, 0);
747 printError(ErrSysFatal
, "Unable to get lock to free for %x", ptr
);
751 pageInfo
= getPageInfo(db
, ptr
);
752 if (NULL
== pageInfo
)
754 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
755 //releaseChunkMutex(db->procSlot);
758 //set the pageinfo where this ptr points
759 int oldVal
= pageInfo
->flags
;
761 SETBIT(newVal
, HAS_SPACE
);
762 SETBIT(newVal
, IS_DIRTY
);
763 ret
= Mutex::CAS((int*)&pageInfo
->flags
, oldVal
, newVal
);
765 printError(ErrSysFatal
, "Unable to get lock to set flags");
767 //releaseChunkMutex(db->procSlot);
771 //returns the pageInfo of the page where this ptr points
772 //This works only if the data size is less than PAGE_SIZE
773 //If ptr points to data which is more than PAGE_SIZE,then
774 //calling this might lead to memory corruption
775 //Note:IMPORTANT::assumes db lock is taken before calling this
776 PageInfo
* Chunk::getPageInfo(Database
*db
, void *ptr
)
778 if (allocSize_
< PAGE_SIZE
- sizeof(PageInfo
)) {
779 int rem
= (long) ptr
% PAGE_SIZE
;
780 return (PageInfo
*)(((char*)ptr
) - rem
);
782 //large size allocator
783 char *inPtr
= (char*)ptr
;
784 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
786 while( pageInfo
!= NULL
)
788 if (inPtr
> (char*) pageInfo
&& pageInfo
->nextPageAfterMerge_
>inPtr
)
790 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
796 //If called on chunk used to store tuples, it returns the total number of rows
797 //present in the table
798 long Chunk::getTotalDataNodes()
801 if (0 == allocSize_
) //->variable size allocator
803 Page
*page
= ((PageInfo
*)firstPage_
);
806 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
807 while ((char*) varInfo
< ((char*)page
+ PAGE_SIZE
))
809 if (1 == varInfo
->isUsed_
) totalNodes
++;
810 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
813 page
= ((PageInfo
*) page
)->nextPage_
;
818 //TODO::for large size allocator
819 if (allocSize_
>PAGE_SIZE
)//->each page has only one data node
821 Page
*page
= ((PageInfo
*)firstPage_
);
824 //current it page wise later this will done
825 if(1==*(int*)(((char*)page
)+sizeof(PageInfo
)))
827 page
= ((PageInfo
*) page
)->nextPage_
;
832 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
833 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
834 char *data
= ((char*)firstPage_
) + sizeof(PageInfo
);
836 while( pageInfo
!= NULL
)
838 data
= ((char*)pageInfo
) + sizeof(PageInfo
);
839 for (i
= 0; i
< noOfDataNodes
; i
++)
841 if (*((InUse
*)data
) == 1) { totalNodes
++;}
842 data
= data
+ allocSize_
;
844 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
849 //TODO::for other type of allocators
850 int Chunk::compact(int procSlot
)
852 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
853 PageInfo
* prevPage
= pageInfo
;
854 if (NULL
== pageInfo
)
858 int ret
= getChunkMutex(procSlot
);
861 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
864 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
867 while( pageInfo
!= NULL
)
870 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) +
872 while ((char*) varInfo
< ((char*)pageInfo
+ PAGE_SIZE
))
874 if (1 == varInfo
->isUsed_
) {flag
=true; break;}
875 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
879 printDebug(DM_VarAlloc
,"Freeing unused page in varsize allocator %x\n", pageInfo
);
880 prevPage
->nextPage_
= pageInfo
->nextPage_
;
881 pageInfo
->isUsed_
= 0;
884 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
885 printDebug(DM_VarAlloc
,"compact iter %x\n", pageInfo
);
887 }else if (allocSize_
< PAGE_SIZE
)
889 while( pageInfo
!= NULL
)
892 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
893 char *data
= ((char*)pageInfo
) + sizeof(PageInfo
);
894 for (int i
= 0; i
< noOfDataNodes
; i
++)
896 if (1 == *((InUse
*)data
)) { flag
= true; break; }
897 data
= data
+allocSize_
;
900 printDebug(DM_Alloc
,"Freeing unused page in fixed allocator %x\n", pageInfo
);
901 prevPage
->nextPage_
= pageInfo
->nextPage_
;
902 pageInfo
->isUsed_
= 0;
903 pageInfo
= (PageInfo
*)(((PageInfo
*)prevPage
)->nextPage_
) ;
906 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
908 printDebug(DM_Alloc
,"compact iter %x\n", pageInfo
);
911 releaseChunkMutex(procSlot
);
915 int Chunk::totalPages()
917 //logic is same for variable size and for large data node allocator.
918 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
920 while( pageInfo
!= NULL
)
923 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
927 int Chunk::totalDirtyPages()
929 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
931 while( pageInfo
!= NULL
)
933 if(BITSET(pageInfo
->flags
, IS_DIRTY
)) dirtyPages
++;
934 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
940 int Chunk::initMutex()
942 return chunkMutex_
.init("Chunk");
944 int Chunk::getChunkMutex(int procSlot
)
946 return chunkMutex_
.getLock(procSlot
);
948 int Chunk::releaseChunkMutex(int procSlot
)
950 return chunkMutex_
.releaseLock(procSlot
);
952 int Chunk::destroyMutex()
954 return chunkMutex_
.destroy();
956 int Chunk::splitDataBucket(VarSizeInfo
*varInfo
, size_t needSize
, int pSlot
, DbRetVal
*rv
)
958 int remSpace
= varInfo
->size_
- sizeof(VarSizeInfo
) - needSize
;
959 //varInfo->isUsed_ = 1;
960 int ret
= Mutex::CAS((int*)&varInfo
->isUsed_
, 0, 1);
962 printDebug(DM_Warning
, "Unable to set I isUsed flag");
963 *rv
= ErrLockTimeOut
;
966 //varInfo->size_ = needSize;
967 ret
= Mutex::CAS((int*)&varInfo
->size_
, varInfo
->size_
, needSize
);
969 printError(ErrSysFatal
, "Unable to set I size flag");
970 ret
= Mutex::CAS((int*)&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
971 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
975 VarSizeInfo
*varInfo2
= (VarSizeInfo
*)((char*)varInfo
+
976 sizeof(VarSizeInfo
) + varInfo
->size_
);
977 //varInfo2->isUsed_ = 0;
978 ret
= Mutex::CAS((int*)&varInfo2
->isUsed_
, varInfo2
->isUsed_
, 0);
980 printError(ErrSysFatal
, "Unable to set II isUsed flag");
981 ret
= Mutex::CAS((int*)&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
982 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
986 //varInfo2->size_ = remSpace;
987 ret
= Mutex::CAS((int*)&varInfo2
->size_
, varInfo2
->size_
, remSpace
);
989 printError(ErrSysFatal
, "Unable to set II size flag");
990 ret
= Mutex::CAS((int*)&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
991 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
995 printDebug(DM_VarAlloc
, "Remaining space is %d\n", remSpace
);
1000 int Chunk::createDataBucket(Page
*page
, size_t totalSize
, size_t needSize
, int pslot
)
1002 //already db alloc mutex is taken
1003 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
1004 //varInfo->isUsed_ = 0;
1005 int ret
= Mutex::CAS((int*)&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1007 printError(ErrSysFatal
, "Fatal:Unable to get lock to set isUsed flag");
1009 //varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
1010 ret
= Mutex::CAS((int*)&varInfo
->size_
, varInfo
->size_
,
1011 PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
));
1013 printError(ErrSysFatal
, "Unable to get lock to set size");
1016 return splitDataBucket(varInfo
, needSize
, pslot
, &rv
);
1018 void Chunk::setChunkNameForSystemDB(int id
)
1020 strcpy(chunkName
,ChunkName
[id
]);
1025 printf(" <Chunk Id> %d </Chunk Id> \n",chunkID_
);
1026 printf(" <TotalPages> %d </TotalPages> \n",totalPages());
1027 if (Conf::config
.useDurability())
1028 printf(" <DirtyPages> %d </DirtyPages> \n",totalDirtyPages());
1029 printf(" <ChunkName > %s </ChunkName> \n",getChunkName());
1030 printf(" <TotalDataNodes> %d </TotalDataNodes> \n",getTotalDataNodes());
1031 printf(" <SizeOfDataNodes> %d </SizeOfDataNodes> \n",getSize());
1032 printf(" <Allocation Type> ");
1035 printf("FixedSizeAllocator ");
1036 }else if(allocType_
==1)
1038 printf("VariableSizeAllocator ");
1041 printf("UnknownAllocator ");
1043 printf("</Allocation Type>\n");