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 InUse oldVal
= pageInfo
->flags
;
55 InUse newVal
= oldVal
;
56 CLEARBIT(newVal
, HAS_SPACE
);
57 int retVal
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
58 if (retVal
!=0) printError(ErrSysFatal
, "Unable to set flags");
60 db
->releaseAllocDatabaseMutex();
61 return data
+ sizeof(InUse
);
64 //no space in curpage , get new page from database
65 pageInfo
= (PageInfo
*)db
->getFreePage(allocSize_
);
68 db
->releaseAllocDatabaseMutex();
69 printError(ErrNoMemory
,"No more free pages in the database");
72 printDebug(DM_Alloc
, "Chunk ID:%d Large Data Item newPage:%x",
74 int multiple
= (int) os::floor(allocSize_
/ PAGE_SIZE
);
75 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
77 pageInfo
->setPageAsUsed(offset
);
78 setPageDirty(pageInfo
);
82 //((PageInfo*)curPage_)->nextPage_ = (Page*) pageInfo;
83 int retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
84 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)pageInfo
);
86 printError(ErrLockTimeOut
, "Fatal: Unable to create page link.");
89 //Make this as current page
90 //curPage_ = (Page*) pageInfo;
91 retVal
= Mutex::CASL((long*) &curPage_
, (long)curPage_
, (long)pageInfo
);
93 printError(ErrLockTimeOut
, "Fatal:Unable to set current page");
96 char* data
= ((char*)curPage_
) + sizeof(PageInfo
);
97 InUse oldVal
= pageInfo
->flags
;
98 InUse newVal
= oldVal
;
99 CLEARBIT(newVal
, HAS_SPACE
);
100 retVal
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
102 printError(ErrLockTimeOut
, "Fatal:Unable to set flags");
105 db
->releaseAllocDatabaseMutex();
106 return data
+ sizeof(InUse
);
110 void* Chunk::allocateFromFirstPage(Database
*db
, int noOfDataNodes
, DbRetVal
*status
)
112 PageInfo
*pageIter
= ((PageInfo
*)firstPage_
);
113 printDebug(DM_Alloc
, "Chunk ID:%d. No free page in database",
115 printDebug(DM_Alloc
, "Scan from firstPage:%x for free nodes",
119 //scan from first page to locate a free node available
120 while(NULL
!= pageIter
)
122 data
= ((char*)pageIter
) + sizeof(PageInfo
);
123 if (BITSET(pageIter
->flags
, HAS_SPACE
))
125 for (i
= 0; i
< noOfDataNodes
; i
++)
127 if (1 == *((InUse
*)data
))
128 data
= data
+ allocSize_
;
131 if (i
!= noOfDataNodes
) break;
133 printDebug(DM_Alloc
, "Chunk ID: %d Page :%x does not have free nodes",
135 pageIter
= (PageInfo
*)((PageInfo
*) pageIter
)->nextPage_
;
137 if (NULL
== pageIter
) {
138 *status
= ErrNoMemory
;
141 printDebug(DM_Alloc
,"ChunkID:%d Scan for free node End:Page :%x",
143 int ret
= Mutex::CASGen(data
, 0, 1);
145 *status
= ErrLockTimeOut
;
146 //printError(ErrLockTimeOut, "Unable to allocate from first page. Retry...");
149 setPageDirty(pageIter
);
150 return data
+ sizeof(InUse
);
153 void* Chunk::allocateFromNewPage(Database
*db
, DbRetVal
*status
)
155 DbRetVal ret
= db
->getAllocDatabaseMutex();
158 printDebug(DM_Warning
,"Unable to acquire alloc database Mutex Chunkid:%d", chunkID_
);
159 *status
= ErrLockTimeOut
;
162 //get a new page from db
163 Page
*page
= db
->getFreePage();
165 printError(ErrNoMemory
, "Unable to allocate page");
166 db
->releaseAllocDatabaseMutex();
167 *status
= ErrNoMemory
;
170 printDebug(DM_Alloc
, "ChunkID:%d Normal Data Item newPage:%x",
172 //Initialize pageInfo for this new page
173 PageInfo
*pInfo
= (PageInfo
*)page
;
174 pInfo
->setPageAsUsed(0);
177 char* data
= ((char*)page
) + sizeof(PageInfo
);
180 //create the link between old page and the newly created page
181 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
183 long oldPage
= (long)pageInfo
->nextPage_
;
184 //pageInfo->nextPage_ = page;
185 int retVal
= Mutex::CASL((long*)&pageInfo
->nextPage_
, (long)pageInfo
->nextPage_
, (long)page
);
188 pInfo
->setPageAsFree();
189 printDebug(DM_Warning
, "Unable to get lock to set chunk list.");
190 *status
= ErrLockTimeOut
;
191 db
->releaseAllocDatabaseMutex();
195 //make this new page as the current page
197 retVal
= Mutex::CASL((long*)&curPage_
, (long)curPage_
, (long)page
);
200 pInfo
->setPageAsFree();
201 retVal
= Mutex::CASL((long*)&pageInfo
->nextPage_
, (long)pageInfo
->nextPage_
, (long)oldPage
);
202 if (retVal
!=0) printError(ErrSysFatal
, "Fatal: Unable to reset the nextPage");
203 printDebug(DM_Warning
, "Unable to get lock to set curPage");
204 *status
= ErrLockTimeOut
;
205 db
->releaseAllocDatabaseMutex();
209 db
->releaseAllocDatabaseMutex();
210 return data
+ sizeof(InUse
);
213 //Allocates memory to store data
214 //TODO::check whether it is locked before allocating.
215 //delete tuple will set the usedflag to true, but locks will be held
216 //till commit and it shall be rolledback.So make sure that it does not
217 //allocate deleted tuple which is yet to be commited.
219 void* Chunk::allocate(Database
*db
, DbRetVal
*status
)
221 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
223 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
224 char *data
= ((char*)curPage_
) + sizeof(PageInfo
);
225 printDebug(DM_Alloc
, "Chunk::allocate id:%d curPage:%x noOfDataNodes:%d",
226 chunkID_
, curPage_
, noOfDataNodes
);
228 //1.scan through data list and find if any is free to use in current page
229 //2.If there is none then
230 // a) get new free page from db. set the prev->next to point
232 //4. b) initialize the free page to zero and get first data ptr.
233 //5.If there is one, return that
235 //For allocation more than PAGE_SIZE
236 if (0 == noOfDataNodes
)
238 data
= (char*) allocateForLargeDataSize(db
);
242 //Chunk Mutex is required as atomic instructions are not giving
243 // consistent results. Need more investigation to improve concurrency
244 int ret
= getChunkMutex(db
->procSlot
);
247 if (status
!= NULL
) *status
= ErrLockTimeOut
;
248 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
251 int i
= noOfDataNodes
;
252 if (BITSET(pageInfo
->flags
, HAS_SPACE
))
254 for (i
= 1; i
< noOfDataNodes
; i
++)
256 if (*((InUse
*)data
) == 1) data
= data
+ allocSize_
;
261 printDebug(DM_Alloc
, "ChunkID:%d Node which might be free is %d",
263 //It comes here if the pageInfo hasFreeSpace
264 //or there are no free data space in this page
265 if (i
== noOfDataNodes
&& *((InUse
*)data
) == 1)
268 printDebug(DM_Alloc
, "ChunkID:%d curPage does not have free nodes.", chunkID_
);
269 //there are no free data space in this page
270 InUse oldVal
= pageInfo
->flags
;
271 InUse newVal
= oldVal
;
272 CLEARBIT(newVal
, HAS_SPACE
);
273 int ret
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
275 *status
= ErrLockTimeOut
;
276 printDebug(DM_Warning
, "Unable to set hasFreespace");
277 releaseChunkMutex(db
->procSlot
);
281 data
= (char*) allocateFromFirstPage(db
, noOfDataNodes
, status
);
282 releaseChunkMutex(db
->procSlot
);
283 if (NULL
== data
&& *status
!= ErrLockTimeOut
)
286 data
= (char*) allocateFromNewPage(db
, status
);
287 if (data
== NULL
&& *status
!= ErrLockTimeOut
)
289 printError(ErrNoMemory
, "No memory in any of the pages:Increase db size");
290 *status
= ErrNoMemory
;
293 if (*status
== OK
) setPageDirty(db
, data
);
296 int retVal
= Mutex::CASGen(data
, 0, 1);
298 *status
= ErrLockTimeOut
;
299 releaseChunkMutex(db
->procSlot
);
300 printDebug(DM_Warning
, "Unable to set isUsed : retry...");
303 setPageDirty(db
, data
);
304 releaseChunkMutex(db
->procSlot
);
305 return data
+ sizeof(InUse
);
307 void* Chunk::tryAllocate(Database
*db
, DbRetVal
*status
, int totalTries
)
311 while (tries
< totalTries
)
314 node
= allocate(db
, status
);
315 if (NULL
!= node
) break;
316 if (*status
!= ErrLockTimeOut
)
318 printError(*status
, "Unable to allocate node");
323 printError(ErrWarning
, "Unable to allocate after %d tries", tries
);
328 void Chunk::setPageDirty(Database
*db
, void *ptr
)
330 if (chunkID_
< LastCatalogID
) return;
331 PageInfo
*pageInfo
= getPageInfo(db
, ptr
);
332 if (NULL
== pageInfo
)
334 printError(ErrSysFatal
,"Fatal: pageInfo is NULL %x", ptr
);
337 SETBIT(pageInfo
->flags
, IS_DIRTY
);
340 void Chunk::setPageDirty(PageInfo
*pInfo
)
342 if (chunkID_
< LastCatalogID
) return;
343 SETBIT(pInfo
->flags
, IS_DIRTY
);
346 void* Chunk::allocateForLargeDataSize(Database
*db
, size_t size
)
348 //no need to take chunk mutexes for this, as we are taking alloc database mutex
349 int multiple
= (int) os::floor(size
/ PAGE_SIZE
);
350 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
351 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
353 pageInfo
= (PageInfo
*)db
->getFreePage(size
);
355 pageInfo
= (PageInfo
*)db
->getFreePage(allocSize_
);
356 if (NULL
== pageInfo
)
358 printError(ErrNoMemory
,"No more free pages in the database:Increase db size");
361 printDebug(DM_VarAlloc
,"Chunk::Large Data Item id:%d Size:%d curPage:%x ",
362 chunkID_
, size
, curPage_
);
363 //TODO:: logic pending
365 //large size allocate for FixedSize data
366 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
367 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
368 curPage_
= (Page
*) pageInfo
;
369 char* data
= ((char*)curPage_
) + sizeof(PageInfo
);
370 int ret
= Mutex::CASGen(data
, 0, 1);
372 printError(ErrLockTimeOut
, "Lock Timeout: retry...");
376 InUse oldVal
= pageInfo
->flags
;
377 InUse newVal
= oldVal
;
378 CLEARBIT(newVal
, HAS_SPACE
);
379 setPageDirty(pageInfo
);
380 ret
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
381 if (ret
!=0) printError(ErrSysFatal
, "Unable to set flags");
382 return data
+ sizeof(InUse
);
384 //large size allocate for varSize data
385 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) + sizeof(PageInfo
));
386 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
387 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
388 curPage_
= (Page
*) pageInfo
;
389 varInfo
->size_
= size
;
390 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 1);
392 printError(ErrLockTimeOut
, "Unable to get lock for var alloc. Retry...");
396 setPageDirty(pageInfo
);
397 return (char *) varInfo
+ sizeof(VarSizeInfo
);
399 //REDESIGN MAY BE REQUIRED:Lets us live with this for now.
400 //what happens to the space lets say 10000 bytes is allocated
401 //it needs 2 pages,= 16000 bytes, 6000 bytes should not be wasted
402 //in this case.So need to take of this.
403 //Will be coded at later stage as this is developed to support
404 //undo logging and currently we shall assume that the logs generated
405 //wont be greater than PAGE_SIZE.
410 //Will check from first page to current page and do first fit allocate
411 //if no space available, allocates new page
412 void* Chunk::allocFromNewPageForVarSize(Database
*db
, size_t size
, int pslot
, DbRetVal
*rv
)
414 //Should be called only for data items <PAGE_SIZE
415 void *vnode
= varSizeFirstFitAllocate(size
, pslot
, rv
);
420 printDebug(DM_Warning
, "No free space in any of the pages already being used");
422 DbRetVal ret
= db
->getAllocDatabaseMutex();
425 printError(ErrLockTimeOut
,"Unable to acquire alloc database Mutex");
428 Page
*newPage
= db
->getFreePage();
431 db
->releaseAllocDatabaseMutex();
435 printDebug(DM_VarAlloc
, "ChunkID:%d New Page: %x ", chunkID_
, newPage
);
436 PageInfo
*pInfo
= (PageInfo
*) newPage
;
437 pInfo
->setPageAsUsed(0);
439 SETBIT(pInfo
->flags
, HAS_SPACE
);
440 if (1 == createDataBucket(newPage
, PAGE_SIZE
, size
, pslot
))
442 printError(ErrSysFatal
, "Split failed in new page...Should never happen");
444 db
->releaseAllocDatabaseMutex();
447 long oldPage
= (long)((PageInfo
*)curPage_
)->nextPage_
;
448 //((PageInfo*)curPage_)->nextPage_ = newPage;
449 int retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
450 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)newPage
);
452 printError(ErrSysFatal
, "Unable to get lock to set chunk next page");
453 pInfo
->setPageAsFree();
454 db
->releaseAllocDatabaseMutex();
458 //curPage_ = newPage;
459 retVal
= Mutex::CASL((long*) &curPage_
, (long)curPage_
, (long)newPage
);
461 printError(ErrSysFatal
, "Unable to get lock to set curPage");
462 retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
463 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)oldPage
);
464 if (retVal
!=0 ) printError(ErrSysFatal
, "Unable to reset curPage");
465 pInfo
->setPageAsFree();
466 db
->releaseAllocDatabaseMutex();
470 db
->releaseAllocDatabaseMutex();
471 char *data
= ((char*)newPage
) + sizeof(PageInfo
) + sizeof(VarSizeInfo
);
475 //Allocates from the current page of the chunk.
476 //Scans through the VarSizeInfo objects in the page and gets the free slot
477 void* Chunk::allocateFromCurPageForVarSize(size_t size
, int pslot
, DbRetVal
*rv
)
479 //Should be called only for data items <PAGE_SIZE
480 Page
*page
= ((PageInfo
*)curPage_
);
481 printDebug(DM_VarAlloc
, "Chunk::allocate Normal Data Item id:%d Size:%d curPage:%x ",
482 chunkID_
, size
, curPage_
);
483 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) +
485 //if ( 0 != getChunkMutex(pslot)) { *rv = ErrLockTimeOut; return NULL; }
486 int pageSize
= PAGE_SIZE
;
487 bool hasSpace
= false;
488 while ((char*) varInfo
< ((char*)page
+ pageSize
))
490 if (0 == varInfo
->isUsed_
)
493 if( size
+ sizeof(VarSizeInfo
) < varInfo
->size_
)
495 if (1 == splitDataBucket(varInfo
, size
, pslot
, rv
))
497 printDebug(DM_Warning
, "Unable to split the data bucket");
498 //releaseChunkMutex(pslot);
501 printDebug(DM_VarAlloc
, "Chunkid:%d splitDataBucket: Size: %d Item:%x ",
502 chunkID_
, size
, varInfo
);
503 //releaseChunkMutex(pslot);
504 return (char*)varInfo
+ sizeof(VarSizeInfo
);
506 else if (size
== varInfo
->size_
) {
507 //varInfo->isUsed_ = 1;
508 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
510 printDebug(DM_Warning
, "Unable to get lock for var alloc size:%d ", size
);
511 *rv
= ErrLockTimeOut
;
512 //releaseChunkMutex(pslot);
515 //releaseChunkMutex(pslot);
516 return (char *) varInfo
+ sizeof(VarSizeInfo
);
520 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
523 if (!hasSpace
) CLEARBIT(((PageInfo
*)curPage_
)->flags
, HAS_SPACE
);
524 if (hasSpace
&& size
< MIN_VARCHAR_ALLOC_SIZE
)
525 CLEARBIT(((PageInfo
*)curPage_
)->flags
, HAS_SPACE
);
526 //releaseChunkMutex(pslot);
530 //Allocates memory to store data of variable size
531 void* Chunk::allocate(Database
*db
, size_t size
, DbRetVal
*status
)
533 if (0 == size
) return NULL
;
534 //check if the size is more than PAGE_SIZE
535 //if it is more than the PAGE_SIZE, then allocate new
536 //page using database and then link the curPage to the
537 //newly allocated page
538 //if it is less than PAGE_SIZE, then check the curpage for
539 //free memory of specified size
540 //if not available, then scan from the firstPage for the free
543 //TODO::During the scan, merge nearby nodes if both are free
544 //if not available then allocate new page
546 size_t alignedSize
= os::alignLong(size
);
548 int ret
= getChunkMutex(db
->procSlot
);
551 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
552 *status
= ErrLockTimeOut
;
555 if (alignedSize
> PAGE_SIZE
)
557 data
= allocateForLargeDataSize(db
, alignedSize
);
561 data
= allocateFromCurPageForVarSize(alignedSize
, db
->procSlot
, status
);
564 //No available spaces in the current page.
566 data
= allocFromNewPageForVarSize(db
, alignedSize
, db
->procSlot
, status
);
567 if (NULL
== data
&& *status
!=ErrLockTimeOut
) {
568 printError(ErrNoMemory
, "No memory in any of the pages:Increase db size");
569 *status
= ErrNoMemory
;
573 releaseChunkMutex(db
->procSlot
);
577 //Assumes chunk mutex is already taken, before calling this
578 void* Chunk::varSizeFirstFitAllocate(size_t size
, int pslot
, DbRetVal
*rv
)
580 printDebug(DM_VarAlloc
, "Chunk::varSizeFirstFitAllocate size:%d firstPage:%x",
583 Page
*page
= ((PageInfo
*)firstPage_
);
584 size_t alignedSize
= os::alignLong(size
);
585 //if ( 0 != getChunkMutex(pslot)) { *rv = ErrLockTimeOut; return NULL; }
586 int pageSize
= PAGE_SIZE
;
590 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
592 if (BITSET(((PageInfo
*)page
)->flags
, HAS_SPACE
)){
593 while ((char*) varInfo
< ((char*)page
+ pageSize
))
595 if (0 == varInfo
->isUsed_
)
598 if( alignedSize
+sizeof(VarSizeInfo
) < varInfo
->size_
)
600 if( 1 == splitDataBucket(varInfo
, alignedSize
, pslot
, rv
))
602 printDebug(DM_Warning
, "Unable to split the data bucket");
603 //releaseChunkMutex(pslot);
606 //releaseChunkMutex(pslot);
607 return ((char*)varInfo
) + sizeof(VarSizeInfo
);
609 else if (alignedSize
== varInfo
->size_
) {
610 //varInfo->isUsed_ = 1;
611 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
613 printDebug(DM_Warning
,"Unable to get lock to set isUsed flag.");
614 *rv
= ErrLockTimeOut
;
615 //releaseChunkMutex(pslot);
618 printDebug(DM_VarAlloc
, "VarSizeFirstFitAllocate returning %x", ((char*)varInfo
) +sizeof(VarSizeInfo
));
619 //releaseChunkMutex(pslot);
620 return ((char *) varInfo
) + sizeof(VarSizeInfo
);
623 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
626 if (!hasSpace
) CLEARBIT(((PageInfo
*)page
)->flags
, HAS_SPACE
);
627 if (hasSpace
&& size
< MIN_VARCHAR_ALLOC_SIZE
)
628 CLEARBIT(((PageInfo
*)page
)->flags
, HAS_SPACE
);
630 printDebug(DM_VarAlloc
, "Chunk:This page does not have free data nodes page:%x", page
);
631 page
= ((PageInfo
*) page
)->nextPage_
;
633 //releaseChunkMutex(pslot);
637 void Chunk::freeForVarSizeAllocator(Database
*db
, void *ptr
, int pslot
)
639 int ret
= getChunkMutex(pslot
);
642 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
645 VarSizeInfo
*varInfo
= (VarSizeInfo
*)((char*)ptr
- sizeof(VarSizeInfo
));
646 //varInfo->isUsed_ = 0;
647 if(varInfo
->size_
> (PAGE_SIZE
- (sizeof(VarSizeInfo
)+sizeof(PageInfo
)))) {
648 PageInfo
*pageInfo
= (PageInfo
*)((char*)varInfo
- sizeof(PageInfo
));
649 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
653 if(NULL
==pInfo
) break;
654 if (pInfo
== pageInfo
) {found
= true; break; }
656 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
660 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
661 releaseChunkMutex(pslot
);
664 if(curPage_
== pageInfo
) {curPage_
= prev
; }
665 pageInfo
->isUsed_
= 0;
666 pageInfo
->nextPageAfterMerge_
= NULL
;
667 setPageDirty(pageInfo
);
668 SETBIT(pageInfo
->flags
, HAS_SPACE
);
669 prev
->nextPage_
= pageInfo
->nextPage_
;
671 int retVal
= Mutex::CASGen(&varInfo
->isUsed_
, 1, 0);
673 printError(ErrAlready
, "Fatal: Varsize double free for %x", ptr
);
675 PageInfo
*pageInfo
= getPageInfo(db
, ptr
);
676 if (NULL
== pageInfo
)
678 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
679 releaseChunkMutex(db
->procSlot
);
682 SETBIT(pageInfo
->flags
, HAS_SPACE
);
683 SETBIT(pageInfo
->flags
, IS_DIRTY
);
684 printDebug(DM_VarAlloc
,"chunkID:%d Unset isUsed for %x", chunkID_
, varInfo
);
685 releaseChunkMutex(pslot
);
690 void Chunk::freeForLargeAllocator(void *ptr
, int pslot
)
692 //There will be max only one data element in a page.
693 //PageInfo is stored just before the data.
694 int ret
= getChunkMutex(pslot
);
697 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
700 PageInfo
*pageInfo
= (PageInfo
*)(((char*)
701 ptr
) - (sizeof(PageInfo
) + sizeof(InUse
)));
702 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
706 if (pInfo
== pageInfo
) {found
= true; break; }
708 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
712 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
713 releaseChunkMutex(pslot
);
716 os::memset(((char*)pageInfo
+sizeof(PageInfo
)), 0 , allocSize_
);
717 if(((PageInfo
*)firstPage_
)->nextPage_
!= NULL
){
718 pageInfo
->nextPageAfterMerge_
= NULL
;
719 //pageInfo->isUsed_ = 0;
720 ret
= Mutex::CASGen(&pageInfo
->isUsed_
, pageInfo
->isUsed_
, 0);
721 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set isUsed flag");
722 InUse oldVal
= pageInfo
->flags
;
723 InUse newVal
= oldVal
;
724 SETBIT(newVal
, HAS_SPACE
);
725 ret
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
726 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set flags");
727 if(pageInfo
== firstPage_
&& ((PageInfo
*)firstPage_
)->nextPage_
!= NULL
)
729 //firstPage_ = pageInfo->nextPage_ ;
730 ret
= Mutex::CASL((long*)&firstPage_
, (long) firstPage_
,
731 (long)pageInfo
->nextPage_
);
732 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set firstPage");
733 setPageDirty(((PageInfo
*)firstPage_
));
736 //prev->nextPage_ = pageInfo->nextPage_;
737 ret
= Mutex::CASL((long*)&prev
->nextPage_
, (long) prev
->nextPage_
,
738 (long)pageInfo
->nextPage_
);
739 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set nextPage");
743 setPageDirty(pageInfo
);
744 releaseChunkMutex(pslot
);
748 //Frees the memory pointed by ptr
749 void Chunk::free(Database
*db
, void *ptr
)
753 freeForVarSizeAllocator(db
, ptr
, db
->procSlot
);
756 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
)) / allocSize_
);
758 if (0 == noOfDataNodes
)
760 freeForLargeAllocator(ptr
, db
->procSlot
);
763 int ret
= getChunkMutex(db
->procSlot
);
766 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
769 //unset the used flag
770 //*((int*)ptr -1 ) = 0;
772 if (*((InUse
*)ptr
-1 ) == 0) {
773 printError(ErrSysFatal
, "Fatal:Data node already freed %x Chunk:%d value:%d", ptr
, chunkID_
,
778 int retVal
= Mutex::CASGen(((InUse
*)ptr
-1), oldValue
, 0);
780 printError(ErrSysFatal
, "Unable to get lock to free for %x", ptr
);
781 releaseChunkMutex(db
->procSlot
);
785 pageInfo
= getPageInfo(db
, ptr
);
786 if (NULL
== pageInfo
)
788 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
789 releaseChunkMutex(db
->procSlot
);
792 //set the pageinfo where this ptr points
793 InUse oldVal
= pageInfo
->flags
;
794 InUse newVal
= oldVal
;
795 SETBIT(newVal
, HAS_SPACE
);
796 retVal
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
798 printError(ErrSysFatal
, "Unable to get lock to set flags");
800 setPageDirty(pageInfo
);
801 releaseChunkMutex(db
->procSlot
);
805 //returns the pageInfo of the page where this ptr points
806 //This works only if the data size is less than PAGE_SIZE
807 //If ptr points to data which is more than PAGE_SIZE,then
808 //calling this might lead to memory corruption
809 //Note:IMPORTANT::assumes db lock is taken before calling this
810 PageInfo
* Chunk::getPageInfo(Database
*db
, void *ptr
)
812 if (allocSize_
< PAGE_SIZE
- sizeof(PageInfo
)) {
813 int rem
= (long) ptr
% PAGE_SIZE
;
814 return (PageInfo
*)(((char*)ptr
) - rem
);
816 //large size allocator
817 char *inPtr
= (char*)ptr
;
818 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
820 while( pageInfo
!= NULL
)
822 if (inPtr
> (char*) pageInfo
&& pageInfo
->nextPageAfterMerge_
>inPtr
)
824 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
830 //If called on chunk used to store tuples, it returns the total number of rows
831 //present in the table
832 long Chunk::getTotalDataNodes()
835 if (0 == allocSize_
) //->variable size allocator
837 Page
*page
= ((PageInfo
*)firstPage_
);
840 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
841 while ((char*) varInfo
< ((char*)page
+ PAGE_SIZE
))
843 if (1 == varInfo
->isUsed_
) totalNodes
++;
844 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
847 page
= ((PageInfo
*) page
)->nextPage_
;
852 //TODO::for large size allocator
853 if (allocSize_
>PAGE_SIZE
)//->each page has only one data node
855 Page
*page
= ((PageInfo
*)firstPage_
);
858 //current it page wise later this will done
859 if(1==*(int*)(((char*)page
)+sizeof(PageInfo
)))
861 page
= ((PageInfo
*) page
)->nextPage_
;
866 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
867 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
868 char *data
= ((char*)firstPage_
) + sizeof(PageInfo
);
870 while( pageInfo
!= NULL
)
872 data
= ((char*)pageInfo
) + sizeof(PageInfo
);
873 for (i
= 0; i
< noOfDataNodes
; i
++)
875 if (*((InUse
*)data
) == 1) { totalNodes
++;}
876 data
= data
+ allocSize_
;
878 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
883 //TODO::for other type of allocators
884 int Chunk::compact(int procSlot
)
886 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
887 PageInfo
* prevPage
= pageInfo
;
888 if (NULL
== pageInfo
)
892 int ret
= getChunkMutex(procSlot
);
895 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
898 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
901 while( pageInfo
!= NULL
)
904 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) +
906 while ((char*) varInfo
< ((char*)pageInfo
+ PAGE_SIZE
))
908 if (1 == varInfo
->isUsed_
) {flag
=true; break;}
909 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
913 printDebug(DM_VarAlloc
,"Freeing unused page in varsize allocator %x\n", pageInfo
);
914 prevPage
->nextPage_
= pageInfo
->nextPage_
;
915 pageInfo
->isUsed_
= 0;
918 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
919 printDebug(DM_VarAlloc
,"compact iter %x\n", pageInfo
);
921 }else if (allocSize_
< PAGE_SIZE
)
923 while( pageInfo
!= NULL
)
926 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
927 char *data
= ((char*)pageInfo
) + sizeof(PageInfo
);
928 for (int i
= 0; i
< noOfDataNodes
; i
++)
930 if (1 == *((InUse
*)data
)) { flag
= true; break; }
931 data
= data
+allocSize_
;
934 printDebug(DM_Alloc
,"Freeing unused page in fixed allocator %x\n", pageInfo
);
935 prevPage
->nextPage_
= pageInfo
->nextPage_
;
936 pageInfo
->isUsed_
= 0;
937 pageInfo
= (PageInfo
*)(((PageInfo
*)prevPage
)->nextPage_
) ;
940 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
942 printDebug(DM_Alloc
,"compact iter %x\n", pageInfo
);
945 releaseChunkMutex(procSlot
);
949 int Chunk::totalPages()
951 //logic is same for variable size and for large data node allocator.
952 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
954 while( pageInfo
!= NULL
)
957 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
961 int Chunk::totalDirtyPages()
963 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
965 while( pageInfo
!= NULL
)
967 if(BITSET(pageInfo
->flags
, IS_DIRTY
)) dirtyPages
++;
968 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
974 int Chunk::initMutex(int id
)
976 char mutName
[IDENTIFIER_LENGTH
];
978 sprintf(mutName
, "Chunk");
980 sprintf(mutName
, "Chunk:%d",id
);
981 return chunkMutex_
.init(mutName
);
983 int Chunk::getChunkMutex(int procSlot
)
985 return chunkMutex_
.getLock(procSlot
);
987 int Chunk::releaseChunkMutex(int procSlot
)
989 return chunkMutex_
.releaseLock(procSlot
);
991 int Chunk::destroyMutex()
993 return chunkMutex_
.destroy();
995 int Chunk::splitDataBucket(VarSizeInfo
*varInfo
, size_t needSize
, int pSlot
, DbRetVal
*rv
)
997 InUse remSpace
= varInfo
->size_
- sizeof(VarSizeInfo
) - needSize
;
998 //varInfo->isUsed_ = 1;
999 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
1001 printDebug(DM_Warning
, "Unable to set I isUsed flag");
1002 *rv
= ErrLockTimeOut
;
1005 //varInfo->size_ = needSize;
1006 ret
= Mutex::CASGen(&varInfo
->size_
, varInfo
->size_
, needSize
);
1008 printError(ErrSysFatal
, "Unable to set I size flag");
1009 ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1010 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
1014 VarSizeInfo
*varInfo2
= (VarSizeInfo
*)((char*)varInfo
+
1015 sizeof(VarSizeInfo
) + varInfo
->size_
);
1016 //varInfo2->isUsed_ = 0;
1017 ret
= Mutex::CASGen(&varInfo2
->isUsed_
, varInfo2
->isUsed_
, 0);
1019 printError(ErrSysFatal
, "Unable to set II isUsed flag");
1020 ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1021 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
1025 //varInfo2->size_ = remSpace;
1026 ret
= Mutex::CASGen(&varInfo2
->size_
, varInfo2
->size_
, remSpace
);
1028 printError(ErrSysFatal
, "Unable to set II size flag");
1029 ret
= Mutex::CASGen((int*)&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1030 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
1034 printDebug(DM_VarAlloc
, "Remaining space is %d\n", remSpace
);
1039 int Chunk::createDataBucket(Page
*page
, size_t totalSize
, size_t needSize
, int pslot
)
1041 //already db alloc mutex is taken
1042 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
1043 //varInfo->isUsed_ = 0;
1044 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1046 printError(ErrSysFatal
, "Fatal:Unable to get lock to set isUsed flag");
1048 //varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
1049 ret
= Mutex::CASGen(&varInfo
->size_
, varInfo
->size_
,
1050 PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
));
1052 printError(ErrSysFatal
, "Unable to get lock to set size");
1055 return splitDataBucket(varInfo
, needSize
, pslot
, &rv
);
1057 void Chunk::setChunkNameForSystemDB(int id
)
1059 strcpy(chunkName
,ChunkName
[id
]);
1064 printf(" <Chunk Id> %d </Chunk Id> \n",chunkID_
);
1065 printf(" <TotalPages> %d </TotalPages> \n",totalPages());
1066 if (Conf::config
.useDurability())
1067 printf(" <DirtyPages> %d </DirtyPages> \n",totalDirtyPages());
1068 printf(" <ChunkName > %s </ChunkName> \n",getChunkName());
1069 printf(" <TotalDataNodes> %d </TotalDataNodes> \n",getTotalDataNodes());
1070 printf(" <SizeOfDataNodes> %d </SizeOfDataNodes> \n",getSize());
1071 printf(" <Allocation Type> ");
1074 printf("FixedSizeAllocator ");
1075 }else if(allocType_
==1)
1077 printf("VariableSizeAllocator ");
1080 printf("UnknownAllocator ");
1082 printf("</Allocation Type>\n");