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 not required as atomic instructions are instead used.
243 //This improves the 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
)
310 int totalTries
= Conf::config
.getMutexRetries();
312 while (tries
< totalTries
)
315 node
= allocate(db
, status
);
316 if (NULL
!= node
) break;
317 if (*status
!= ErrLockTimeOut
)
319 printError(*status
, "Unable to allocate node");
327 void Chunk::setPageDirty(Database
*db
, void *ptr
)
329 if (chunkID_
< LastCatalogID
) return;
330 PageInfo
*pageInfo
= getPageInfo(db
, ptr
);
331 if (NULL
== pageInfo
)
333 printError(ErrSysFatal
,"Fatal: pageInfo is NULL %x", ptr
);
336 SETBIT(pageInfo
->flags
, IS_DIRTY
);
339 void Chunk::setPageDirty(PageInfo
*pInfo
)
341 if (chunkID_
< LastCatalogID
) return;
342 SETBIT(pInfo
->flags
, IS_DIRTY
);
345 void* Chunk::allocateForLargeDataSize(Database
*db
, size_t size
)
347 //no need to take chunk mutexes for this, as we are taking alloc database mutex
348 int multiple
= (int) os::floor(size
/ PAGE_SIZE
);
349 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
350 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
352 pageInfo
= (PageInfo
*)db
->getFreePage(size
);
354 pageInfo
= (PageInfo
*)db
->getFreePage(allocSize_
);
355 if (NULL
== pageInfo
)
357 printError(ErrNoMemory
,"No more free pages in the database:Increase db size");
360 printDebug(DM_VarAlloc
,"Chunk::alnextPageAfterMerge_locate Large Data Item id:%d Size:%d curPage:%x ",
361 chunkID_
, size
, curPage_
);
362 //TODO:: logic pending
364 //large size allocate for FixedSize data
365 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
366 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
367 curPage_
= (Page
*) pageInfo
;
368 char* data
= ((char*)curPage_
) + sizeof(PageInfo
);
369 int ret
= Mutex::CASGen(data
, 0, 1);
371 printError(ErrLockTimeOut
, "Lock Timeout: retry...");
375 InUse oldVal
= pageInfo
->flags
;
376 InUse newVal
= oldVal
;
377 CLEARBIT(newVal
, HAS_SPACE
);
378 setPageDirty(pageInfo
);
379 ret
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
380 if (ret
!=0) printError(ErrSysFatal
, "Unable to set flags");
381 return data
+ sizeof(InUse
);
383 //large size allocate for varSize data
384 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) + sizeof(PageInfo
));
385 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
386 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
387 curPage_
= (Page
*) pageInfo
;
388 varInfo
->size_
= size
;
389 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 1);
391 printError(ErrLockTimeOut
, "Unable to get lock for var alloc. Retry...");
395 setPageDirty(pageInfo
);
396 return (char *) varInfo
+ sizeof(VarSizeInfo
);
398 //REDESIGN MAY BE REQUIRED:Lets us live with this for now.
399 //what happens to the space lets say 10000 bytes is allocated
400 //it needs 2 pages,= 16000 bytes, 6000 bytes should not be wasted
401 //in this case.So need to take of this.
402 //Will be coded at later stage as this is developed to support
403 //undo logging and currently we shall assume that the logs generated
404 //wont be greater than PAGE_SIZE.
410 void* Chunk::allocFromNewPageForVarSize(Database
*db
, size_t size
, int pslot
, DbRetVal
*rv
)
412 //Should be called only for data items <PAGE_SIZE
413 void *vnode
= varSizeFirstFitAllocate(size
, pslot
, rv
);
418 printDebug(DM_Warning
, "No free space in any of the pages already being used");
420 DbRetVal ret
= db
->getAllocDatabaseMutex();
423 printError(ErrLockTimeOut
,"Unable to acquire alloc database Mutex");
426 Page
*newPage
= db
->getFreePage();
429 db
->releaseAllocDatabaseMutex();
433 printDebug(DM_VarAlloc
, "ChunkID:%d New Page: %x ", chunkID_
, newPage
);
434 PageInfo
*pInfo
= (PageInfo
*) newPage
;
435 pInfo
->setPageAsUsed(0);
437 SETBIT(pInfo
->flags
, HAS_SPACE
);
438 if (1 == createDataBucket(newPage
, PAGE_SIZE
, size
, pslot
))
440 printError(ErrSysFatal
, "Split failed in new page...Should never happen");
442 db
->releaseAllocDatabaseMutex();
445 long oldPage
= (long)((PageInfo
*)curPage_
)->nextPage_
;
446 //((PageInfo*)curPage_)->nextPage_ = newPage;
447 int retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
448 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)newPage
);
450 printError(ErrSysFatal
, "Unable to get lock to set chunk next page");
451 pInfo
->setPageAsFree();
452 db
->releaseAllocDatabaseMutex();
456 //curPage_ = newPage;
457 retVal
= Mutex::CASL((long*) &curPage_
, (long)curPage_
, (long)newPage
);
459 printError(ErrSysFatal
, "Unable to get lock to set curPage");
460 retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
461 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)oldPage
);
462 if (retVal
!=0 ) printError(ErrSysFatal
, "Unable to reset curPage");
463 pInfo
->setPageAsFree();
464 db
->releaseAllocDatabaseMutex();
468 db
->releaseAllocDatabaseMutex();
469 char *data
= ((char*)newPage
) + sizeof(PageInfo
) + sizeof(VarSizeInfo
);
473 //Allocates from the current page of the chunk.
474 //Scans through the VarSizeInfo objects in the page and gets the free slot
475 void* Chunk::allocateFromCurPageForVarSize(size_t size
, int pslot
, DbRetVal
*rv
)
477 //Should be called only for data items <PAGE_SIZE
478 Page
*page
= ((PageInfo
*)curPage_
);
479 printDebug(DM_VarAlloc
, "Chunk::allocate Normal Data Item id:%d Size:%d curPage:%x ",
480 chunkID_
, size
, curPage_
);
481 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) +
483 if ( 0 != getChunkMutex(pslot
)) { *rv
= ErrLockTimeOut
; return NULL
; }
484 int pageSize
= PAGE_SIZE
;
485 bool hasSpace
= false;
486 while ((char*) varInfo
< ((char*)page
+ pageSize
))
488 if (0 == varInfo
->isUsed_
)
491 if( size
+ sizeof(VarSizeInfo
) < varInfo
->size_
)
493 if (1 == splitDataBucket(varInfo
, size
, pslot
, rv
))
495 printDebug(DM_Warning
, "Unable to split the data bucket");
496 releaseChunkMutex(pslot
);
499 printDebug(DM_VarAlloc
, "Chunkid:%d splitDataBucket: Size: %d Item:%x ",
500 chunkID_
, size
, varInfo
);
501 releaseChunkMutex(pslot
);
502 return (char*)varInfo
+ sizeof(VarSizeInfo
);
504 else if (size
== varInfo
->size_
) {
505 //varInfo->isUsed_ = 1;
506 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
508 printDebug(DM_Warning
, "Unable to get lock for var alloc size:%d ", size
);
509 *rv
= ErrLockTimeOut
;
510 releaseChunkMutex(pslot
);
513 releaseChunkMutex(pslot
);
514 return (char *) varInfo
+ sizeof(VarSizeInfo
);
518 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
521 if (!hasSpace
) CLEARBIT(((PageInfo
*)curPage_
)->flags
, HAS_SPACE
);
522 if (hasSpace
&& size
< MIN_VARCHAR_ALLOC_SIZE
)
523 CLEARBIT(((PageInfo
*)curPage_
)->flags
, HAS_SPACE
);
524 releaseChunkMutex(pslot
);
528 //Allocates memory to store data of variable size
529 void* Chunk::allocate(Database
*db
, size_t size
, DbRetVal
*status
)
531 if (0 == size
) return NULL
;
532 //check if the size is more than PAGE_SIZE
533 //if it is more than the PAGE_SIZE, then allocate new
534 //page using database and then link the curPage to the
535 //newly allocated page
536 //if it is less than PAGE_SIZE, then check the curpage for
537 //free memory of specified size
538 //if not available, then scan from the firstPage for the free
541 //TODO::During the scan, merge nearby nodes if both are free
542 //if not available then allocate new page
544 size_t alignedSize
= os::alignLong(size
);
546 /*int ret = getChunkMutex(db->procSlot);
549 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
550 *status = ErrLockTimeOut;
553 if (alignedSize
> PAGE_SIZE
)
555 data
= allocateForLargeDataSize(db
, alignedSize
);
559 data
= allocateFromCurPageForVarSize(alignedSize
, db
->procSlot
, status
);
562 //No available spaces in the current page.
564 data
= allocFromNewPageForVarSize(db
, alignedSize
, db
->procSlot
, status
);
565 if (NULL
== data
&& *status
!=ErrLockTimeOut
) {
566 printError(ErrNoMemory
, "No memory in any of the pages:Increase db size");
567 *status
= ErrNoMemory
;
571 //releaseChunkMutex(db->procSlot);
575 //Assumes chunk mutex is already taken, before calling this
576 void* Chunk::varSizeFirstFitAllocate(size_t size
, int pslot
, DbRetVal
*rv
)
578 printDebug(DM_VarAlloc
, "Chunk::varSizeFirstFitAllocate size:%d firstPage:%x",
581 Page
*page
= ((PageInfo
*)firstPage_
);
582 size_t alignedSize
= os::alignLong(size
);
583 if ( 0 != getChunkMutex(pslot
)) { *rv
= ErrLockTimeOut
; return NULL
; }
584 int pageSize
= PAGE_SIZE
;
588 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
590 if (BITSET(((PageInfo
*)page
)->flags
, HAS_SPACE
)){
591 while ((char*) varInfo
< ((char*)page
+ pageSize
))
593 if (0 == varInfo
->isUsed_
)
596 if( alignedSize
+sizeof(VarSizeInfo
) < varInfo
->size_
)
598 if( 1 == splitDataBucket(varInfo
, alignedSize
, pslot
, rv
))
600 printDebug(DM_Warning
, "Unable to split the data bucket");
601 releaseChunkMutex(pslot
);
604 releaseChunkMutex(pslot
);
605 return ((char*)varInfo
) + sizeof(VarSizeInfo
);
607 else if (alignedSize
== varInfo
->size_
) {
608 //varInfo->isUsed_ = 1;
609 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
611 printDebug(DM_Warning
,"Unable to get lock to set isUsed flag.");
612 *rv
= ErrLockTimeOut
;
613 releaseChunkMutex(pslot
);
616 printDebug(DM_VarAlloc
, "VarSizeFirstFitAllocate returning %x", ((char*)varInfo
) +sizeof(VarSizeInfo
));
617 releaseChunkMutex(pslot
);
618 return ((char *) varInfo
) + sizeof(VarSizeInfo
);
621 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
624 if (!hasSpace
) CLEARBIT(((PageInfo
*)page
)->flags
, HAS_SPACE
);
625 if (hasSpace
&& size
< MIN_VARCHAR_ALLOC_SIZE
)
626 CLEARBIT(((PageInfo
*)page
)->flags
, HAS_SPACE
);
628 printDebug(DM_VarAlloc
, "Chunk:This page does not have free data nodes page:%x", page
);
629 page
= ((PageInfo
*) page
)->nextPage_
;
631 releaseChunkMutex(pslot
);
635 void Chunk::freeForVarSizeAllocator(Database
*db
, void *ptr
, int pslot
)
637 int ret
= getChunkMutex(pslot
);
640 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
643 VarSizeInfo
*varInfo
= (VarSizeInfo
*)((char*)ptr
- sizeof(VarSizeInfo
));
644 //varInfo->isUsed_ = 0;
645 if(varInfo
->size_
> (PAGE_SIZE
- (sizeof(VarSizeInfo
)+sizeof(PageInfo
)))) {
646 PageInfo
*pageInfo
= (PageInfo
*)((char*)varInfo
- sizeof(PageInfo
));
647 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
651 if(NULL
==pInfo
) break;
652 if (pInfo
== pageInfo
) {found
= true; break; }
654 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
658 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
659 releaseChunkMutex(pslot
);
662 if(curPage_
== pageInfo
) {curPage_
= prev
; }
663 pageInfo
->isUsed_
= 0;
664 pageInfo
->nextPageAfterMerge_
= NULL
;
665 setPageDirty(pageInfo
);
666 SETBIT(pageInfo
->flags
, HAS_SPACE
);
667 prev
->nextPage_
= pageInfo
->nextPage_
;
669 int retVal
= Mutex::CASGen(&varInfo
->isUsed_
, 1, 0);
671 printError(ErrAlready
, "Fatal: Varsize double free for %x", ptr
);
673 PageInfo
*pageInfo
= getPageInfo(db
, ptr
);
674 if (NULL
== pageInfo
)
676 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
677 releaseChunkMutex(db
->procSlot
);
680 SETBIT(pageInfo
->flags
, HAS_SPACE
);
681 SETBIT(pageInfo
->flags
, IS_DIRTY
);
682 printDebug(DM_VarAlloc
,"chunkID:%d Unset isUsed for %x", chunkID_
, varInfo
);
683 releaseChunkMutex(pslot
);
688 void Chunk::freeForLargeAllocator(void *ptr
, int pslot
)
690 //There will be max only one data element in a page.
691 //PageInfo is stored just before the data.
692 int ret
= getChunkMutex(pslot
);
695 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
698 PageInfo
*pageInfo
= (PageInfo
*)(((char*)
699 ptr
) - (sizeof(PageInfo
) + sizeof(InUse
)));
700 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
704 if (pInfo
== pageInfo
) {found
= true; break; }
706 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
710 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
711 releaseChunkMutex(pslot
);
714 os::memset(((char*)pageInfo
+sizeof(PageInfo
)), 0 , allocSize_
);
715 if(((PageInfo
*)firstPage_
)->nextPage_
!= NULL
){
716 pageInfo
->nextPageAfterMerge_
= NULL
;
717 //pageInfo->isUsed_ = 0;
718 ret
= Mutex::CASGen(&pageInfo
->isUsed_
, pageInfo
->isUsed_
, 0);
719 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set isUsed flag");
720 InUse oldVal
= pageInfo
->flags
;
721 InUse newVal
= oldVal
;
722 SETBIT(newVal
, HAS_SPACE
);
723 ret
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
724 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set flags");
725 if(pageInfo
== firstPage_
&& ((PageInfo
*)firstPage_
)->nextPage_
!= NULL
)
727 //firstPage_ = pageInfo->nextPage_ ;
728 ret
= Mutex::CASL((long*)&firstPage_
, (long) firstPage_
,
729 (long)pageInfo
->nextPage_
);
730 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set firstPage");
731 setPageDirty(((PageInfo
*)firstPage_
));
734 //prev->nextPage_ = pageInfo->nextPage_;
735 ret
= Mutex::CASL((long*)&prev
->nextPage_
, (long) prev
->nextPage_
,
736 (long)pageInfo
->nextPage_
);
737 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set nextPage");
741 setPageDirty(pageInfo
);
742 releaseChunkMutex(pslot
);
746 //Frees the memory pointed by ptr
747 void Chunk::free(Database
*db
, void *ptr
)
751 freeForVarSizeAllocator(db
, ptr
, db
->procSlot
);
754 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
)) / allocSize_
);
756 if (0 == noOfDataNodes
)
758 freeForLargeAllocator(ptr
, db
->procSlot
);
761 /*int ret = getChunkMutex(db->procSlot);
764 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
767 //unset the used flag
768 //*((int*)ptr -1 ) = 0;
770 if (*((InUse
*)ptr
-1 ) == 0) {
771 printError(ErrSysFatal
, "Fatal:Data node already freed %x Chunk:%d value:%d", ptr
, chunkID_
,
776 int retVal
= Mutex::CASGen(((InUse
*)ptr
-1), oldValue
, 0);
778 printError(ErrSysFatal
, "Unable to get lock to free for %x", ptr
);
779 //releaseChunkMutex(db->procSlot);
783 pageInfo
= getPageInfo(db
, ptr
);
784 if (NULL
== pageInfo
)
786 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
787 //releaseChunkMutex(db->procSlot);
790 //set the pageinfo where this ptr points
791 InUse oldVal
= pageInfo
->flags
;
792 InUse newVal
= oldVal
;
793 SETBIT(newVal
, HAS_SPACE
);
794 retVal
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
796 printError(ErrSysFatal
, "Unable to get lock to set flags");
798 setPageDirty(pageInfo
);
799 //releaseChunkMutex(db->procSlot);
803 //returns the pageInfo of the page where this ptr points
804 //This works only if the data size is less than PAGE_SIZE
805 //If ptr points to data which is more than PAGE_SIZE,then
806 //calling this might lead to memory corruption
807 //Note:IMPORTANT::assumes db lock is taken before calling this
808 PageInfo
* Chunk::getPageInfo(Database
*db
, void *ptr
)
810 if (allocSize_
< PAGE_SIZE
- sizeof(PageInfo
)) {
811 int rem
= (long) ptr
% PAGE_SIZE
;
812 return (PageInfo
*)(((char*)ptr
) - rem
);
814 //large size allocator
815 char *inPtr
= (char*)ptr
;
816 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
818 while( pageInfo
!= NULL
)
820 if (inPtr
> (char*) pageInfo
&& pageInfo
->nextPageAfterMerge_
>inPtr
)
822 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
828 //If called on chunk used to store tuples, it returns the total number of rows
829 //present in the table
830 long Chunk::getTotalDataNodes()
833 if (0 == allocSize_
) //->variable size allocator
835 Page
*page
= ((PageInfo
*)firstPage_
);
838 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
839 while ((char*) varInfo
< ((char*)page
+ PAGE_SIZE
))
841 if (1 == varInfo
->isUsed_
) totalNodes
++;
842 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
845 page
= ((PageInfo
*) page
)->nextPage_
;
850 //TODO::for large size allocator
851 if (allocSize_
>PAGE_SIZE
)//->each page has only one data node
853 Page
*page
= ((PageInfo
*)firstPage_
);
856 //current it page wise later this will done
857 if(1==*(int*)(((char*)page
)+sizeof(PageInfo
)))
859 page
= ((PageInfo
*) page
)->nextPage_
;
864 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
865 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
866 char *data
= ((char*)firstPage_
) + sizeof(PageInfo
);
868 while( pageInfo
!= NULL
)
870 data
= ((char*)pageInfo
) + sizeof(PageInfo
);
871 for (i
= 0; i
< noOfDataNodes
; i
++)
873 if (*((InUse
*)data
) == 1) { totalNodes
++;}
874 data
= data
+ allocSize_
;
876 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
881 //TODO::for other type of allocators
882 int Chunk::compact(int procSlot
)
884 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
885 PageInfo
* prevPage
= pageInfo
;
886 if (NULL
== pageInfo
)
890 int ret
= getChunkMutex(procSlot
);
893 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
896 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
899 while( pageInfo
!= NULL
)
902 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) +
904 while ((char*) varInfo
< ((char*)pageInfo
+ PAGE_SIZE
))
906 if (1 == varInfo
->isUsed_
) {flag
=true; break;}
907 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
911 printDebug(DM_VarAlloc
,"Freeing unused page in varsize allocator %x\n", pageInfo
);
912 prevPage
->nextPage_
= pageInfo
->nextPage_
;
913 pageInfo
->isUsed_
= 0;
916 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
917 printDebug(DM_VarAlloc
,"compact iter %x\n", pageInfo
);
919 }else if (allocSize_
< PAGE_SIZE
)
921 while( pageInfo
!= NULL
)
924 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
925 char *data
= ((char*)pageInfo
) + sizeof(PageInfo
);
926 for (int i
= 0; i
< noOfDataNodes
; i
++)
928 if (1 == *((InUse
*)data
)) { flag
= true; break; }
929 data
= data
+allocSize_
;
932 printDebug(DM_Alloc
,"Freeing unused page in fixed allocator %x\n", pageInfo
);
933 prevPage
->nextPage_
= pageInfo
->nextPage_
;
934 pageInfo
->isUsed_
= 0;
935 pageInfo
= (PageInfo
*)(((PageInfo
*)prevPage
)->nextPage_
) ;
938 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
940 printDebug(DM_Alloc
,"compact iter %x\n", pageInfo
);
943 releaseChunkMutex(procSlot
);
947 int Chunk::totalPages()
949 //logic is same for variable size and for large data node allocator.
950 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
952 while( pageInfo
!= NULL
)
955 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
959 int Chunk::totalDirtyPages()
961 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
963 while( pageInfo
!= NULL
)
965 if(BITSET(pageInfo
->flags
, IS_DIRTY
)) dirtyPages
++;
966 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
972 int Chunk::initMutex()
974 return chunkMutex_
.init("Chunk");
976 int Chunk::getChunkMutex(int procSlot
)
978 return chunkMutex_
.getLock(procSlot
);
980 int Chunk::releaseChunkMutex(int procSlot
)
982 return chunkMutex_
.releaseLock(procSlot
);
984 int Chunk::destroyMutex()
986 return chunkMutex_
.destroy();
988 int Chunk::splitDataBucket(VarSizeInfo
*varInfo
, size_t needSize
, int pSlot
, DbRetVal
*rv
)
990 InUse remSpace
= varInfo
->size_
- sizeof(VarSizeInfo
) - needSize
;
991 //varInfo->isUsed_ = 1;
992 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
994 printDebug(DM_Warning
, "Unable to set I isUsed flag");
995 *rv
= ErrLockTimeOut
;
998 //varInfo->size_ = needSize;
999 ret
= Mutex::CASGen(&varInfo
->size_
, varInfo
->size_
, needSize
);
1001 printError(ErrSysFatal
, "Unable to set I size flag");
1002 ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1003 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
1007 VarSizeInfo
*varInfo2
= (VarSizeInfo
*)((char*)varInfo
+
1008 sizeof(VarSizeInfo
) + varInfo
->size_
);
1009 //varInfo2->isUsed_ = 0;
1010 ret
= Mutex::CASGen(&varInfo2
->isUsed_
, varInfo2
->isUsed_
, 0);
1012 printError(ErrSysFatal
, "Unable to set II isUsed flag");
1013 ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1014 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
1018 //varInfo2->size_ = remSpace;
1019 ret
= Mutex::CASGen(&varInfo2
->size_
, varInfo2
->size_
, remSpace
);
1021 printError(ErrSysFatal
, "Unable to set II size flag");
1022 ret
= Mutex::CASGen((int*)&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1023 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
1027 printDebug(DM_VarAlloc
, "Remaining space is %d\n", remSpace
);
1032 int Chunk::createDataBucket(Page
*page
, size_t totalSize
, size_t needSize
, int pslot
)
1034 //already db alloc mutex is taken
1035 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
1036 //varInfo->isUsed_ = 0;
1037 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1039 printError(ErrSysFatal
, "Fatal:Unable to get lock to set isUsed flag");
1041 //varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
1042 ret
= Mutex::CASGen(&varInfo
->size_
, varInfo
->size_
,
1043 PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
));
1045 printError(ErrSysFatal
, "Unable to get lock to set size");
1048 return splitDataBucket(varInfo
, needSize
, pslot
, &rv
);
1050 void Chunk::setChunkNameForSystemDB(int id
)
1052 strcpy(chunkName
,ChunkName
[id
]);
1057 printf(" <Chunk Id> %d </Chunk Id> \n",chunkID_
);
1058 printf(" <TotalPages> %d </TotalPages> \n",totalPages());
1059 if (Conf::config
.useDurability())
1060 printf(" <DirtyPages> %d </DirtyPages> \n",totalDirtyPages());
1061 printf(" <ChunkName > %s </ChunkName> \n",getChunkName());
1062 printf(" <TotalDataNodes> %d </TotalDataNodes> \n",getTotalDataNodes());
1063 printf(" <SizeOfDataNodes> %d </SizeOfDataNodes> \n",getSize());
1064 printf(" <Allocation Type> ");
1067 printf("FixedSizeAllocator ");
1068 }else if(allocType_
==1)
1070 printf("VariableSizeAllocator ");
1073 printf("UnknownAllocator ");
1075 printf("</Allocation Type>\n");