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
);
308 void Chunk::setPageDirty(Database
*db
, void *ptr
)
310 if (chunkID_
< LastCatalogID
) return;
311 PageInfo
*pageInfo
= getPageInfo(db
, ptr
);
312 if (NULL
== pageInfo
)
314 printError(ErrSysFatal
,"Fatal: pageInfo is NULL %x", ptr
);
317 SETBIT(pageInfo
->flags
, IS_DIRTY
);
320 void Chunk::setPageDirty(PageInfo
*pInfo
)
322 if (chunkID_
< LastCatalogID
) return;
323 SETBIT(pInfo
->flags
, IS_DIRTY
);
326 void* Chunk::allocateForLargeDataSize(Database
*db
, size_t size
)
328 //no need to take chunk mutexes for this, as we are taking alloc database mutex
329 int multiple
= (int) os::floor(size
/ PAGE_SIZE
);
330 int offset
= ((multiple
+ 1) * PAGE_SIZE
);
331 PageInfo
* pageInfo
= ((PageInfo
*)curPage_
);
333 pageInfo
= (PageInfo
*)db
->getFreePage(size
);
335 pageInfo
= (PageInfo
*)db
->getFreePage(allocSize_
);
336 if (NULL
== pageInfo
)
338 printError(ErrNoMemory
,"No more free pages in the database:Increase db size");
341 printDebug(DM_VarAlloc
,"Chunk::alnextPageAfterMerge_locate Large Data Item id:%d Size:%d curPage:%x ",
342 chunkID_
, size
, curPage_
);
343 //TODO:: logic pending
345 //large size allocate for FixedSize data
346 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
347 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
348 curPage_
= (Page
*) pageInfo
;
349 char* data
= ((char*)curPage_
) + sizeof(PageInfo
);
350 int ret
= Mutex::CASGen(data
, 0, 1);
352 printError(ErrLockTimeOut
, "Lock Timeout: retry...");
356 InUse oldVal
= pageInfo
->flags
;
357 InUse newVal
= oldVal
;
358 CLEARBIT(newVal
, HAS_SPACE
);
359 setPageDirty(pageInfo
);
360 ret
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
361 if (ret
!=0) printError(ErrSysFatal
, "Unable to set flags");
362 return data
+ sizeof(InUse
);
364 //large size allocate for varSize data
365 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) + sizeof(PageInfo
));
366 pageInfo
->nextPageAfterMerge_
= ((char*)pageInfo
+ offset
);
367 ((PageInfo
*)curPage_
)->nextPage_
= (Page
*) pageInfo
;
368 curPage_
= (Page
*) pageInfo
;
369 varInfo
->size_
= size
;
370 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 1);
372 printError(ErrLockTimeOut
, "Unable to get lock for var alloc. Retry...");
376 setPageDirty(pageInfo
);
377 return (char *) varInfo
+ sizeof(VarSizeInfo
);
379 //REDESIGN MAY BE REQUIRED:Lets us live with this for now.
380 //what happens to the space lets say 10000 bytes is allocated
381 //it needs 2 pages,= 16000 bytes, 6000 bytes should not be wasted
382 //in this case.So need to take of this.
383 //Will be coded at later stage as this is developed to support
384 //undo logging and currently we shall assume that the logs generated
385 //wont be greater than PAGE_SIZE.
391 void* Chunk::allocFromNewPageForVarSize(Database
*db
, size_t size
, int pslot
, DbRetVal
*rv
)
393 //Should be called only for data items <PAGE_SIZE
394 void *vnode
= varSizeFirstFitAllocate(size
, pslot
, rv
);
399 printDebug(DM_Warning
, "No free space in any of the pages already being used");
401 DbRetVal ret
= db
->getAllocDatabaseMutex();
404 printError(ErrLockTimeOut
,"Unable to acquire alloc database Mutex");
407 Page
*newPage
= db
->getFreePage();
410 db
->releaseAllocDatabaseMutex();
414 printDebug(DM_VarAlloc
, "ChunkID:%d New Page: %x ", chunkID_
, newPage
);
415 PageInfo
*pInfo
= (PageInfo
*) newPage
;
416 pInfo
->setPageAsUsed(0);
418 SETBIT(pInfo
->flags
, HAS_SPACE
);
419 if (1 == createDataBucket(newPage
, PAGE_SIZE
, size
, pslot
))
421 printError(ErrSysFatal
, "Split failed in new page...Should never happen");
423 db
->releaseAllocDatabaseMutex();
426 long oldPage
= (long)((PageInfo
*)curPage_
)->nextPage_
;
427 //((PageInfo*)curPage_)->nextPage_ = newPage;
428 int retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
429 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)newPage
);
431 printError(ErrSysFatal
, "Unable to get lock to set chunk next page");
432 pInfo
->setPageAsFree();
433 db
->releaseAllocDatabaseMutex();
437 //curPage_ = newPage;
438 retVal
= Mutex::CASL((long*) &curPage_
, (long)curPage_
, (long)newPage
);
440 printError(ErrSysFatal
, "Unable to get lock to set curPage");
441 retVal
= Mutex::CASL((long*) &(((PageInfo
*)curPage_
)->nextPage_
),
442 (long)(((PageInfo
*)curPage_
)->nextPage_
), (long)oldPage
);
443 if (retVal
!=0 ) printError(ErrSysFatal
, "Unable to reset curPage");
444 pInfo
->setPageAsFree();
445 db
->releaseAllocDatabaseMutex();
449 db
->releaseAllocDatabaseMutex();
450 char *data
= ((char*)newPage
) + sizeof(PageInfo
) + sizeof(VarSizeInfo
);
454 //Allocates from the current page of the chunk.
455 //Scans through the VarSizeInfo objects in the page and gets the free slot
456 void* Chunk::allocateFromCurPageForVarSize(size_t size
, int pslot
, DbRetVal
*rv
)
458 //Should be called only for data items <PAGE_SIZE
459 Page
*page
= ((PageInfo
*)curPage_
);
460 printDebug(DM_VarAlloc
, "Chunk::allocate Normal Data Item id:%d Size:%d curPage:%x ",
461 chunkID_
, size
, curPage_
);
462 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) +
464 if ( 0 != getChunkMutex(pslot
)) { *rv
= ErrLockTimeOut
; return NULL
; }
465 int pageSize
= PAGE_SIZE
;
466 bool hasSpace
= false;
467 while ((char*) varInfo
< ((char*)page
+ pageSize
))
469 if (0 == varInfo
->isUsed_
)
472 if( size
+ sizeof(VarSizeInfo
) < varInfo
->size_
)
474 if (1 == splitDataBucket(varInfo
, size
, pslot
, rv
))
476 printDebug(DM_Warning
, "Unable to split the data bucket");
477 releaseChunkMutex(pslot
);
480 printDebug(DM_VarAlloc
, "Chunkid:%d splitDataBucket: Size: %d Item:%x ",
481 chunkID_
, size
, varInfo
);
482 releaseChunkMutex(pslot
);
483 return (char*)varInfo
+ sizeof(VarSizeInfo
);
485 else if (size
== varInfo
->size_
) {
486 //varInfo->isUsed_ = 1;
487 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
489 printDebug(DM_Warning
, "Unable to get lock for var alloc size:%d ", size
);
490 *rv
= ErrLockTimeOut
;
491 releaseChunkMutex(pslot
);
494 releaseChunkMutex(pslot
);
495 return (char *) varInfo
+ sizeof(VarSizeInfo
);
499 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
502 if (!hasSpace
) CLEARBIT(((PageInfo
*)curPage_
)->flags
, HAS_SPACE
);
503 if (hasSpace
&& size
< MIN_VARCHAR_ALLOC_SIZE
)
504 CLEARBIT(((PageInfo
*)curPage_
)->flags
, HAS_SPACE
);
505 releaseChunkMutex(pslot
);
509 //Allocates memory to store data of variable size
510 void* Chunk::allocate(Database
*db
, size_t size
, DbRetVal
*status
)
512 if (0 == size
) return NULL
;
513 //check if the size is more than PAGE_SIZE
514 //if it is more than the PAGE_SIZE, then allocate new
515 //page using database and then link the curPage to the
516 //newly allocated page
517 //if it is less than PAGE_SIZE, then check the curpage for
518 //free memory of specified size
519 //if not available, then scan from the firstPage for the free
522 //TODO::During the scan, merge nearby nodes if both are free
523 //if not available then allocate new page
525 size_t alignedSize
= os::alignLong(size
);
527 /*int ret = getChunkMutex(db->procSlot);
530 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
531 *status = ErrLockTimeOut;
534 if (alignedSize
> PAGE_SIZE
)
536 data
= allocateForLargeDataSize(db
, alignedSize
);
540 data
= allocateFromCurPageForVarSize(alignedSize
, db
->procSlot
, status
);
543 //No available spaces in the current page.
545 data
= allocFromNewPageForVarSize(db
, alignedSize
, db
->procSlot
, status
);
546 if (NULL
== data
&& *status
!=ErrLockTimeOut
) {
547 printError(ErrNoMemory
, "No memory in any of the pages:Increase db size");
548 *status
= ErrNoMemory
;
552 //releaseChunkMutex(db->procSlot);
556 //Assumes chunk mutex is already taken, before calling this
557 void* Chunk::varSizeFirstFitAllocate(size_t size
, int pslot
, DbRetVal
*rv
)
559 printDebug(DM_VarAlloc
, "Chunk::varSizeFirstFitAllocate size:%d firstPage:%x",
562 Page
*page
= ((PageInfo
*)firstPage_
);
563 size_t alignedSize
= os::alignLong(size
);
564 if ( 0 != getChunkMutex(pslot
)) { *rv
= ErrLockTimeOut
; return NULL
; }
565 int pageSize
= PAGE_SIZE
;
569 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
571 if (BITSET(((PageInfo
*)page
)->flags
, HAS_SPACE
)){
572 while ((char*) varInfo
< ((char*)page
+ pageSize
))
574 if (0 == varInfo
->isUsed_
)
577 if( alignedSize
+sizeof(VarSizeInfo
) < varInfo
->size_
)
579 if( 1 == splitDataBucket(varInfo
, alignedSize
, pslot
, rv
))
581 printDebug(DM_Warning
, "Unable to split the data bucket");
582 releaseChunkMutex(pslot
);
585 releaseChunkMutex(pslot
);
586 return ((char*)varInfo
) + sizeof(VarSizeInfo
);
588 else if (alignedSize
== varInfo
->size_
) {
589 //varInfo->isUsed_ = 1;
590 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
592 printDebug(DM_Warning
,"Unable to get lock to set isUsed flag.");
593 *rv
= ErrLockTimeOut
;
594 releaseChunkMutex(pslot
);
597 printDebug(DM_VarAlloc
, "VarSizeFirstFitAllocate returning %x", ((char*)varInfo
) +sizeof(VarSizeInfo
));
598 releaseChunkMutex(pslot
);
599 return ((char *) varInfo
) + sizeof(VarSizeInfo
);
602 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
605 if (!hasSpace
) CLEARBIT(((PageInfo
*)page
)->flags
, HAS_SPACE
);
606 if (hasSpace
&& size
< MIN_VARCHAR_ALLOC_SIZE
)
607 CLEARBIT(((PageInfo
*)page
)->flags
, HAS_SPACE
);
609 printDebug(DM_VarAlloc
, "Chunk:This page does not have free data nodes page:%x", page
);
610 page
= ((PageInfo
*) page
)->nextPage_
;
612 releaseChunkMutex(pslot
);
616 void Chunk::freeForVarSizeAllocator(Database
*db
, void *ptr
, int pslot
)
618 int ret
= getChunkMutex(pslot
);
621 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
624 VarSizeInfo
*varInfo
= (VarSizeInfo
*)((char*)ptr
- sizeof(VarSizeInfo
));
625 //varInfo->isUsed_ = 0;
626 if(varInfo
->size_
> (PAGE_SIZE
- (sizeof(VarSizeInfo
)+sizeof(PageInfo
)))) {
627 PageInfo
*pageInfo
= (PageInfo
*)((char*)varInfo
- sizeof(PageInfo
));
628 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
632 if(NULL
==pInfo
) break;
633 if (pInfo
== pageInfo
) {found
= true; break; }
635 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
639 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
640 releaseChunkMutex(pslot
);
643 if(curPage_
== pageInfo
) {curPage_
= prev
; }
644 pageInfo
->isUsed_
= 0;
645 pageInfo
->nextPageAfterMerge_
= NULL
;
646 setPageDirty(pageInfo
);
647 SETBIT(pageInfo
->flags
, HAS_SPACE
);
648 prev
->nextPage_
= pageInfo
->nextPage_
;
650 int retVal
= Mutex::CASGen(&varInfo
->isUsed_
, 1, 0);
652 printError(ErrAlready
, "Fatal: Varsize double free for %x", ptr
);
654 PageInfo
*pageInfo
= getPageInfo(db
, ptr
);
655 if (NULL
== pageInfo
)
657 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
658 releaseChunkMutex(db
->procSlot
);
661 SETBIT(pageInfo
->flags
, HAS_SPACE
);
662 SETBIT(pageInfo
->flags
, IS_DIRTY
);
663 printDebug(DM_VarAlloc
,"chunkID:%d Unset isUsed for %x", chunkID_
, varInfo
);
664 releaseChunkMutex(pslot
);
669 void Chunk::freeForLargeAllocator(void *ptr
, int pslot
)
671 //There will be max only one data element in a page.
672 //PageInfo is stored just before the data.
673 int ret
= getChunkMutex(pslot
);
676 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
679 PageInfo
*pageInfo
= (PageInfo
*)(((char*)
680 ptr
) - (sizeof(PageInfo
) + sizeof(InUse
)));
681 PageInfo
*pInfo
= (PageInfo
*)firstPage_
, *prev
= (PageInfo
*)firstPage_
;
685 if (pInfo
== pageInfo
) {found
= true; break; }
687 pInfo
= (PageInfo
*)pInfo
->nextPage_
;
691 printError(ErrSysFatal
,"Page %x not found in page list:Logical error", pageInfo
);
692 releaseChunkMutex(pslot
);
695 os::memset(((char*)pageInfo
+sizeof(PageInfo
)), 0 , allocSize_
);
696 if(((PageInfo
*)firstPage_
)->nextPage_
!= NULL
){
697 pageInfo
->nextPageAfterMerge_
= NULL
;
698 //pageInfo->isUsed_ = 0;
699 ret
= Mutex::CASGen(&pageInfo
->isUsed_
, pageInfo
->isUsed_
, 0);
700 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set isUsed flag");
701 InUse oldVal
= pageInfo
->flags
;
702 InUse newVal
= oldVal
;
703 SETBIT(newVal
, HAS_SPACE
);
704 ret
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
705 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set flags");
706 if(pageInfo
== firstPage_
&& ((PageInfo
*)firstPage_
)->nextPage_
!= NULL
)
708 //firstPage_ = pageInfo->nextPage_ ;
709 ret
= Mutex::CASL((long*)&firstPage_
, (long) firstPage_
,
710 (long)pageInfo
->nextPage_
);
711 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set firstPage");
712 setPageDirty(((PageInfo
*)firstPage_
));
715 //prev->nextPage_ = pageInfo->nextPage_;
716 ret
= Mutex::CASL((long*)&prev
->nextPage_
, (long) prev
->nextPage_
,
717 (long)pageInfo
->nextPage_
);
718 if (ret
!= 0) printError(ErrSysFatal
, "Unable to set nextPage");
722 setPageDirty(pageInfo
);
723 releaseChunkMutex(pslot
);
727 //Frees the memory pointed by ptr
728 void Chunk::free(Database
*db
, void *ptr
)
732 freeForVarSizeAllocator(db
, ptr
, db
->procSlot
);
735 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
)) / allocSize_
);
737 if (0 == noOfDataNodes
)
739 freeForLargeAllocator(ptr
, db
->procSlot
);
742 /*int ret = getChunkMutex(db->procSlot);
745 printError(ErrLockTimeOut,"Unable to acquire chunk Mutex");
748 //unset the used flag
749 //*((int*)ptr -1 ) = 0;
751 if (*((InUse
*)ptr
-1 ) == 0) {
752 printError(ErrSysFatal
, "Fatal:Data node already freed %x Chunk:%d value:%d", ptr
, chunkID_
,
757 int retVal
= Mutex::CASGen(((InUse
*)ptr
-1), oldValue
, 0);
759 printError(ErrSysFatal
, "Unable to get lock to free for %x", ptr
);
760 //releaseChunkMutex(db->procSlot);
764 pageInfo
= getPageInfo(db
, ptr
);
765 if (NULL
== pageInfo
)
767 printError(ErrSysFatal
,"Fatal: pageInfo is NULL", pageInfo
);
768 //releaseChunkMutex(db->procSlot);
771 //set the pageinfo where this ptr points
772 InUse oldVal
= pageInfo
->flags
;
773 InUse newVal
= oldVal
;
774 SETBIT(newVal
, HAS_SPACE
);
775 retVal
= Mutex::CASGen(&pageInfo
->flags
, oldVal
, newVal
);
777 printError(ErrSysFatal
, "Unable to get lock to set flags");
779 setPageDirty(pageInfo
);
780 //releaseChunkMutex(db->procSlot);
784 //returns the pageInfo of the page where this ptr points
785 //This works only if the data size is less than PAGE_SIZE
786 //If ptr points to data which is more than PAGE_SIZE,then
787 //calling this might lead to memory corruption
788 //Note:IMPORTANT::assumes db lock is taken before calling this
789 PageInfo
* Chunk::getPageInfo(Database
*db
, void *ptr
)
791 if (allocSize_
< PAGE_SIZE
- sizeof(PageInfo
)) {
792 int rem
= (long) ptr
% PAGE_SIZE
;
793 return (PageInfo
*)(((char*)ptr
) - rem
);
795 //large size allocator
796 char *inPtr
= (char*)ptr
;
797 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
799 while( pageInfo
!= NULL
)
801 if (inPtr
> (char*) pageInfo
&& pageInfo
->nextPageAfterMerge_
>inPtr
)
803 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
809 //If called on chunk used to store tuples, it returns the total number of rows
810 //present in the table
811 long Chunk::getTotalDataNodes()
814 if (0 == allocSize_
) //->variable size allocator
816 Page
*page
= ((PageInfo
*)firstPage_
);
819 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
820 while ((char*) varInfo
< ((char*)page
+ PAGE_SIZE
))
822 if (1 == varInfo
->isUsed_
) totalNodes
++;
823 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
826 page
= ((PageInfo
*) page
)->nextPage_
;
831 //TODO::for large size allocator
832 if (allocSize_
>PAGE_SIZE
)//->each page has only one data node
834 Page
*page
= ((PageInfo
*)firstPage_
);
837 //current it page wise later this will done
838 if(1==*(int*)(((char*)page
)+sizeof(PageInfo
)))
840 page
= ((PageInfo
*) page
)->nextPage_
;
845 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
846 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
847 char *data
= ((char*)firstPage_
) + sizeof(PageInfo
);
849 while( pageInfo
!= NULL
)
851 data
= ((char*)pageInfo
) + sizeof(PageInfo
);
852 for (i
= 0; i
< noOfDataNodes
; i
++)
854 if (*((InUse
*)data
) == 1) { totalNodes
++;}
855 data
= data
+ allocSize_
;
857 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
862 //TODO::for other type of allocators
863 int Chunk::compact(int procSlot
)
865 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
866 PageInfo
* prevPage
= pageInfo
;
867 if (NULL
== pageInfo
)
871 int ret
= getChunkMutex(procSlot
);
874 printError(ErrLockTimeOut
,"Unable to acquire chunk Mutex");
877 pageInfo
= (PageInfo
*)pageInfo
->nextPage_
;
880 while( pageInfo
!= NULL
)
883 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)pageInfo
) +
885 while ((char*) varInfo
< ((char*)pageInfo
+ PAGE_SIZE
))
887 if (1 == varInfo
->isUsed_
) {flag
=true; break;}
888 varInfo
= (VarSizeInfo
*)((char*)varInfo
+ sizeof(VarSizeInfo
)
892 printDebug(DM_VarAlloc
,"Freeing unused page in varsize allocator %x\n", pageInfo
);
893 prevPage
->nextPage_
= pageInfo
->nextPage_
;
894 pageInfo
->isUsed_
= 0;
897 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
898 printDebug(DM_VarAlloc
,"compact iter %x\n", pageInfo
);
900 }else if (allocSize_
< PAGE_SIZE
)
902 while( pageInfo
!= NULL
)
905 int noOfDataNodes
=(int) os::floor((PAGE_SIZE
- sizeof(PageInfo
))/allocSize_
);
906 char *data
= ((char*)pageInfo
) + sizeof(PageInfo
);
907 for (int i
= 0; i
< noOfDataNodes
; i
++)
909 if (1 == *((InUse
*)data
)) { flag
= true; break; }
910 data
= data
+allocSize_
;
913 printDebug(DM_Alloc
,"Freeing unused page in fixed allocator %x\n", pageInfo
);
914 prevPage
->nextPage_
= pageInfo
->nextPage_
;
915 pageInfo
->isUsed_
= 0;
916 pageInfo
= (PageInfo
*)(((PageInfo
*)prevPage
)->nextPage_
) ;
919 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
921 printDebug(DM_Alloc
,"compact iter %x\n", pageInfo
);
924 releaseChunkMutex(procSlot
);
928 int Chunk::totalPages()
930 //logic is same for variable size and for large data node allocator.
931 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
933 while( pageInfo
!= NULL
)
936 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
940 int Chunk::totalDirtyPages()
942 PageInfo
* pageInfo
= ((PageInfo
*)firstPage_
);
944 while( pageInfo
!= NULL
)
946 if(BITSET(pageInfo
->flags
, IS_DIRTY
)) dirtyPages
++;
947 pageInfo
= (PageInfo
*)(((PageInfo
*)pageInfo
)->nextPage_
) ;
953 int Chunk::initMutex()
955 return chunkMutex_
.init("Chunk");
957 int Chunk::getChunkMutex(int procSlot
)
959 return chunkMutex_
.getLock(procSlot
);
961 int Chunk::releaseChunkMutex(int procSlot
)
963 return chunkMutex_
.releaseLock(procSlot
);
965 int Chunk::destroyMutex()
967 return chunkMutex_
.destroy();
969 int Chunk::splitDataBucket(VarSizeInfo
*varInfo
, size_t needSize
, int pSlot
, DbRetVal
*rv
)
971 InUse remSpace
= varInfo
->size_
- sizeof(VarSizeInfo
) - needSize
;
972 //varInfo->isUsed_ = 1;
973 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, 0, 1);
975 printDebug(DM_Warning
, "Unable to set I isUsed flag");
976 *rv
= ErrLockTimeOut
;
979 //varInfo->size_ = needSize;
980 ret
= Mutex::CASGen(&varInfo
->size_
, varInfo
->size_
, needSize
);
982 printError(ErrSysFatal
, "Unable to set I size flag");
983 ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
984 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
988 VarSizeInfo
*varInfo2
= (VarSizeInfo
*)((char*)varInfo
+
989 sizeof(VarSizeInfo
) + varInfo
->size_
);
990 //varInfo2->isUsed_ = 0;
991 ret
= Mutex::CASGen(&varInfo2
->isUsed_
, varInfo2
->isUsed_
, 0);
993 printError(ErrSysFatal
, "Unable to set II isUsed flag");
994 ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
995 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
999 //varInfo2->size_ = remSpace;
1000 ret
= Mutex::CASGen(&varInfo2
->size_
, varInfo2
->size_
, remSpace
);
1002 printError(ErrSysFatal
, "Unable to set II size flag");
1003 ret
= Mutex::CASGen((int*)&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1004 if (ret
!=0) printError(ErrSysFatal
, "Unable to reset isUsed flag");
1008 printDebug(DM_VarAlloc
, "Remaining space is %d\n", remSpace
);
1013 int Chunk::createDataBucket(Page
*page
, size_t totalSize
, size_t needSize
, int pslot
)
1015 //already db alloc mutex is taken
1016 VarSizeInfo
*varInfo
= (VarSizeInfo
*)(((char*)page
) + sizeof(PageInfo
));
1017 //varInfo->isUsed_ = 0;
1018 int ret
= Mutex::CASGen(&varInfo
->isUsed_
, varInfo
->isUsed_
, 0);
1020 printError(ErrSysFatal
, "Fatal:Unable to get lock to set isUsed flag");
1022 //varInfo->size_ = PAGE_SIZE - sizeof(PageInfo) - sizeof(VarSizeInfo);
1023 ret
= Mutex::CASGen(&varInfo
->size_
, varInfo
->size_
,
1024 PAGE_SIZE
- sizeof(PageInfo
) - sizeof(VarSizeInfo
));
1026 printError(ErrSysFatal
, "Unable to get lock to set size");
1029 return splitDataBucket(varInfo
, needSize
, pslot
, &rv
);
1031 void Chunk::setChunkNameForSystemDB(int id
)
1033 strcpy(chunkName
,ChunkName
[id
]);
1038 printf(" <Chunk Id> %d </Chunk Id> \n",chunkID_
);
1039 printf(" <TotalPages> %d </TotalPages> \n",totalPages());
1040 if (Conf::config
.useDurability())
1041 printf(" <DirtyPages> %d </DirtyPages> \n",totalDirtyPages());
1042 printf(" <ChunkName > %s </ChunkName> \n",getChunkName());
1043 printf(" <TotalDataNodes> %d </TotalDataNodes> \n",getTotalDataNodes());
1044 printf(" <SizeOfDataNodes> %d </SizeOfDataNodes> \n",getSize());
1045 printf(" <Allocation Type> ");
1048 printf("FixedSizeAllocator ");
1049 }else if(allocType_
==1)
1051 printf("VariableSizeAllocator ");
1054 printf("UnknownAllocator ");
1056 printf("</Allocation Type>\n");