Dushan Silva
asked on
Database Buffer Manager
Hi Experts,
I want to write database buffer manager with following requirements using Visual C++ 6.0 platform.
The buffer manager should:
*Flushes a page to the disk, if required
*Pins a page to the buffer, bringing a page from the disk, if necessary.
*Unpins a page in the buffer by reducing the pin counter for that page.
*Frees up space that is allocated to a given page on the disk.
*Allocates one or more frames and brings the requested pages from the disk.
*Keeps track of statistics of operations on buffer pool.
BR Dushan
I want to write database buffer manager with following requirements using Visual C++ 6.0 platform.
The buffer manager should:
*Flushes a page to the disk, if required
*Pins a page to the buffer, bringing a page from the disk, if necessary.
*Unpins a page in the buffer by reducing the pin counter for that page.
*Frees up space that is allocated to a given page on the disk.
*Allocates one or more frames and brings the requested pages from the disk.
*Keeps track of statistics of operations on buffer pool.
BR Dushan
And what's the question ?
ASKER
I want VC++ source code for DB buffer manager.
BR Dushan
BR Dushan
You're not gonna find anyone here that is gonna code that for you.
If you don't know how to start, we can get you started.
If you have specific issues, we can help you find a solution.
If you don't know how to start, we can get you started.
If you have specific issues, we can help you find a solution.
What you are looking for is a caching algorithm. Frankly, those take quite a bit of time to code and debug. If you don't know how to do it, I would advise hiring someone to do it for you. This algorithm is not the place to cut costs. Even the slightest bug here could have disasterous consequences for any application that uses it.
Bill
Bill
Every OS in use has a disk vbuffer cache manager, over which the world's best programmers have already pored over for hundreds of hours.
Then the OS's file system driver has it's own cache of important blocks, like directories and indirect file table blocks.
Then in addition most databases have their OWN internal caches, intelligently fetching frequently used and important blocks.
Similarly many disk controller cards, especially RAID or SCSI ones do this too.
And the newer disk drives themselves have up to 128 MB of internal cache.
It's really unlikely you can do better, especially since your code would be running in series or in competition with all those other caching levels.
You might try writing a test program that does typical database actions while it tunes the various system cache parameters. Now THAT would be useful.
Then the OS's file system driver has it's own cache of important blocks, like directories and indirect file table blocks.
Then in addition most databases have their OWN internal caches, intelligently fetching frequently used and important blocks.
Similarly many disk controller cards, especially RAID or SCSI ones do this too.
And the newer disk drives themselves have up to 128 MB of internal cache.
It's really unlikely you can do better, especially since your code would be running in series or in competition with all those other caching levels.
You might try writing a test program that does typical database actions while it tunes the various system cache parameters. Now THAT would be useful.
Hello!
You can have a look at the open source databases source code, like FastDB or GigaBASE...
http://www.garret.ru/~knizhnik
You can have a look at the open source databases source code, like FastDB or GigaBASE...
http://www.garret.ru/~knizhnik
ASKER
Hi All,
I camed with my own following solution.
#include <stdlib.h>
#include "bufmgr.h"
//------------------------ ---------- ---------- ---------- ---------- ----
// Enumuration for BufMgr Error Handling
//
// Input : None
// Output : None
//------------------------ ---------- ---------- ---------- ---------- ----
enum bufErrCodes { HASHTBLERROR, HASHNOTFOUND, BUFFEREXCEEDED, INVALIDBUFFERSIZE,
PAGENOTPINNED, PINCOUNTNOTONE, PINCOUNTNOTZERO, INVALIDPAGEID,
PAGEWRITEERROR, DEALLOCATERROR, ALLOCATERROR1 };
//------------------------ ---------- ---------- ---------- ---------- ----
// Constructor for BufMgr
//
// Input : bufSize - number of pages in the this buffer manager
// Output : None
// PostCond: All frames are empty.
//------------------------ ---------- ---------- ---------- ---------- ----
BufMgr::BufMgr( int bufSize )
{
if (bufSize < 0)
{
MINIBASE_FIRST_ERROR(BUFMG R, INVALIDBUFFERSIZE);
return;
}
numBuffers=bufSize;
bufferPool=new frame[numBuffers]; //alloacte a array of frames
pagePool=new Page[numBuffers]; //alloacte a array of pages
for(int i=0; i<numBuffers; i++){
bufferPool[i].setFrameNo(i );
}
}
//------------------------ ---------- ---------- ---------- ---------- ----
// Destructor for BufMgr
//
// Input : None
// Output : None
//------------------------ ---------- ---------- ---------- ---------- ----
BufMgr::~BufMgr()
{
FlushAllPages();
delete [] bufferPool;
delete [] pagePool;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::FlushAllPages
//
// Input : None
// Output : None
// Purpose : Flush all pages in the buffer pool to disk.
// Condition: None of the pages in the buffer pool should be pinned.
// PostCond : All dirty pages in the buffer pool are written to
// disk (even if some pages are pinned). All frames are empty.
// Return : OK if operation is successful. FAIL otherwise.
// Note : If some pages in the buffer are pinned, this procedure should
// flush them to the disk and return FAIL
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::FlushAllPages()
{
int frameNumber =-1;
frame *chkFrame = 0;
for(int i=0; i< numBuffers; i++)
{
frameNumber=bufferPool[i]. getFrameNo ();
if(frameNumber==bufferPool [i].getPin Count() == 1)
{
MINIBASE_DB->WritePage(fra meNumber, chkFrame->getPage()); // Write the pages to MINIBASE
}
else{
return FAIL;
}
}
return OK;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::FlushPage
//
// Input : pid - page id of a particular page
// Output : None
// Purpose : Flush the page with the given pid to disk.
// Condition: The page with page id = pid must be in the buffer,
// and should not be pinned. pid cannot be INVALID_PAGE.
// PostCond : The page with page id = pid is written to disk if it is dirty.
// The frame where the page resides is empty.
// Return : OK if operation is successful. FAIL otherwise.
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::FlushPage(PageID pid)
{
int frameNo =-1;
frame *checkFrame = 0;
frameNo=bufferPool[pid].ge tFrameNo() ;
if(frameNo==bufferPool[pid ].getPinCo unt() == 1)
{
MINIBASE_DB->WritePage(fra meNo, checkFrame->getPage()); // Write the pages to MINIBASE
return OK;
}
else{
return FAIL;
}
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::PinPage
//
// Input : pid - page id of a particular page
// isEmpty - (optional, default to FALSE) if true indicate
// that the page to be pinned is an empty page.
// Output : page - a pointer to a page in the buffer pool. (NULL
// if fail)
// Purpose : Pin the page with page id = pid to the buffer.
// Read the page from disk unless isEmpty is TRUE or
// the page is already in the buffer.
// Condition: Either the page is already in the buffer, or there is at
// least one frame available in the buffer pool for the
// page.
// PostCond : The page with page id = pid resides in the buffer and
// is pinned. The number of pins on the page increase by
// one.
// Return : OK if operation is successful. FAIL otherwise.
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::PinPage(PageID pid, Page*& page, bool isEmpty)
{
int frameNo=-1,a=0;
frame *checkFrame = 0;
PageID pageId;
bool dirty = false;
Page tempPage;
//check the page is in the buffer pool
for(int i=0; i< numBuffers; i++){
if(pid==bufferPool[i].getP ageID()){
numPinRequests++;
frameNo=bufferPool[i].getF rameNo();
break;
}
}
if(frameNo != 1)
{
// Get the frame
checkFrame = &bufferPool[frameNo];
// Pin the page to this frame
checkFrame->pin();
// Retrieve page data
page = checkFrame->getPage();
}
else {
numPageMisses++;
// Check if buffer pool can handle more pages
for(int i=0; i<numBuffers; i++)
{
if(bufferPool[i].getPinCou nt() == 0)
a++;
if (a == 0 )
{
page = NULL;
MINIBASE_FIRST_ERROR(BUFMG R, BUFFEREXCEEDED);
return FAIL;
}
}
// Get frame from buffer pool
checkFrame = &bufferPool[frameNo];
// Get the page id
pageId = checkFrame->getPageID();
// Check to see if the frame is dirty. In which case it'll be written back out.
dirty = checkFrame->getDirtyBit();
if (dirty)
{
// Write the page
MINIBASE_DB->WritePage(pag eId, checkFrame->getPage());
// Increase dirty page written count
numDirtyPagesWritten++;
}
if (!isEmpty)
{
MINIBASE_DB->ReadPage(pid, &tempPage);
}
checkFrame->setAndPinPage( pid);
// Retrieve page data
checkFrame->setPage(tempPa ge);
page = checkFrame->getPage();
}
return OK;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::UnpinPage
//
// Input : pid - page id of a particular page
// dirty - indicate whether the page with page id = pid
// is dirty or not. (Optional, default to FALSE)
// Output : None
// Purpose : Unpin the page with page id = pid in the buffer. Mark
// the page dirty if dirty is TRUE.
// Condition: The page is already in the buffer and is pinned.
// PostCond : The page is unpinned and the number of pin on the
// page decrease by one.
// Return : OK if operation is successful. FAIL otherwise.
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::UnpinPage(PageID pid, Bool dirty)
{
int frameNo = -1;
frame *checkFrame = 0;
frameNo=bufferPool[pid].ge tFrameNo() ;
if (frameNo == -1)
{
return FAIL;
}
// Get frame from buffer pool
checkFrame = &bufferPool[frameNo];
// Set dirty flag if dirty == TRUE
if (dirty)
{
checkFrame->setDirtyBit();
}
checkFrame->unpin();
return OK;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::FreePage
//
// Input : pid - page id of a particular page
// Output : None
// Purpose : Free the memory allocated for the page with
// page id = pid
// Condition: Either the page is already in the buffer and is pinned
// no more than once, or the page is not in the buffer.
// PostCond : The page is unpinned, and the frame where it resides in
// the buffer pool is freed. Also the page is deallocated
// from the database.
// Return : OK if operation is successful. FAIL otherwise.
// Note : You can call MINIBASE_DB->DeallocatePag e(pid) to
// deallocate a page.
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::FreePage(PageID pid)
{
return OK;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::NewPage
//
// Input : howMany - (optional, default to 1) how many pages to
// allocate.
// Output : pid - the page id of the first page (as output by
// DB::AllocatePage) allocated.
// page - a pointer to the page in memory.
// Purpose : Allocate howMany number of pages, and pin the first page
// into the buffer.
// Condition: howMany > 0 and there is at least one free buffer space
// to hold a page.
// PostCond : The page with page id = pid is pinned into the buffer.
// Return : OK if operation is successful. FAIL otherwise.
// Note : You can call MINIBASE_DB->AllocatePage( ) to allocate a page.
// You should call MINIBASE_DB->DeallocatePag e() to deallocate the
// pages you allocate if you failed to pin the page in the
// buffer.
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::NewPage (int& pid, Page*& page, int howMany)
{
Status stat;
stat = MINIBASE_DB->AllocatePage( pid, howMany);
if (stat != OK)
{
MINIBASE_FIRST_ERROR(BUFMG R, ALLOCATERROR1);
return FAIL;
}
// Try to pin the first page allocated
stat = PinPage(pid, page);
if (stat != OK)
{
// Deallocate page
if (MINIBASE_DB->DeallocatePa ge(pid, howMany) != OK)
{
MINIBASE_FIRST_ERROR(BUFMG R, DEALLOCATERROR);
return FAIL;
}
}
return OK;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::GetNumOfUnpinnedBu ffers
//
// Input : None
// Output : None
// Purpose : Find out how many unpinned locations are in the buffer
// pool.
// Condition: None
// PostCond : None
// Return : The number of unpinned buffers in the buffer pool.
//------------------------ ---------- ---------- ---------- ---------- ----
unsigned int BufMgr::GetNumOfUnpinnedBu ffers()
{
return 0;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::GetNumOfBuffers
//
// Input : None
// Output : None
// Purpose : Find out how many buffers are there in the buffer pool.
// PreCond : None
// PostCond : None
// Return : The number of buffers in the buffer pool.
//------------------------ ---------- ---------- ---------- ---------- ----
unsigned int BufMgr::GetNumOfBuffers()
{
return 0;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::ResetStat
//
// Input : None
// Output : None
// Purpose : Reset the statistic variables
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::ResetStat( )
{
return OK;
}
//------------------------ ---------- ---------- ---------- ---------- ----
// BufMgr::PrintStat
//
// Input : None
// Output : None
// Purpose : Print the statistic variables
//------------------------ ---------- ---------- ---------- ---------- ----
Status BufMgr::PrintStat( )
{
return OK;
}
I camed with my own following solution.
#include <stdlib.h>
#include "bufmgr.h"
//------------------------
// Enumuration for BufMgr Error Handling
//
// Input : None
// Output : None
//------------------------
enum bufErrCodes { HASHTBLERROR, HASHNOTFOUND, BUFFEREXCEEDED, INVALIDBUFFERSIZE,
PAGENOTPINNED, PINCOUNTNOTONE, PINCOUNTNOTZERO, INVALIDPAGEID,
PAGEWRITEERROR, DEALLOCATERROR, ALLOCATERROR1 };
//------------------------
// Constructor for BufMgr
//
// Input : bufSize - number of pages in the this buffer manager
// Output : None
// PostCond: All frames are empty.
//------------------------
BufMgr::BufMgr( int bufSize )
{
if (bufSize < 0)
{
MINIBASE_FIRST_ERROR(BUFMG
return;
}
numBuffers=bufSize;
bufferPool=new frame[numBuffers]; //alloacte a array of frames
pagePool=new Page[numBuffers]; //alloacte a array of pages
for(int i=0; i<numBuffers; i++){
bufferPool[i].setFrameNo(i
}
}
//------------------------
// Destructor for BufMgr
//
// Input : None
// Output : None
//------------------------
BufMgr::~BufMgr()
{
FlushAllPages();
delete [] bufferPool;
delete [] pagePool;
}
//------------------------
// BufMgr::FlushAllPages
//
// Input : None
// Output : None
// Purpose : Flush all pages in the buffer pool to disk.
// Condition: None of the pages in the buffer pool should be pinned.
// PostCond : All dirty pages in the buffer pool are written to
// disk (even if some pages are pinned). All frames are empty.
// Return : OK if operation is successful. FAIL otherwise.
// Note : If some pages in the buffer are pinned, this procedure should
// flush them to the disk and return FAIL
//------------------------
Status BufMgr::FlushAllPages()
{
int frameNumber =-1;
frame *chkFrame = 0;
for(int i=0; i< numBuffers; i++)
{
frameNumber=bufferPool[i].
if(frameNumber==bufferPool
{
MINIBASE_DB->WritePage(fra
}
else{
return FAIL;
}
}
return OK;
}
//------------------------
// BufMgr::FlushPage
//
// Input : pid - page id of a particular page
// Output : None
// Purpose : Flush the page with the given pid to disk.
// Condition: The page with page id = pid must be in the buffer,
// and should not be pinned. pid cannot be INVALID_PAGE.
// PostCond : The page with page id = pid is written to disk if it is dirty.
// The frame where the page resides is empty.
// Return : OK if operation is successful. FAIL otherwise.
//------------------------
Status BufMgr::FlushPage(PageID pid)
{
int frameNo =-1;
frame *checkFrame = 0;
frameNo=bufferPool[pid].ge
if(frameNo==bufferPool[pid
{
MINIBASE_DB->WritePage(fra
return OK;
}
else{
return FAIL;
}
}
//------------------------
// BufMgr::PinPage
//
// Input : pid - page id of a particular page
// isEmpty - (optional, default to FALSE) if true indicate
// that the page to be pinned is an empty page.
// Output : page - a pointer to a page in the buffer pool. (NULL
// if fail)
// Purpose : Pin the page with page id = pid to the buffer.
// Read the page from disk unless isEmpty is TRUE or
// the page is already in the buffer.
// Condition: Either the page is already in the buffer, or there is at
// least one frame available in the buffer pool for the
// page.
// PostCond : The page with page id = pid resides in the buffer and
// is pinned. The number of pins on the page increase by
// one.
// Return : OK if operation is successful. FAIL otherwise.
//------------------------
Status BufMgr::PinPage(PageID pid, Page*& page, bool isEmpty)
{
int frameNo=-1,a=0;
frame *checkFrame = 0;
PageID pageId;
bool dirty = false;
Page tempPage;
//check the page is in the buffer pool
for(int i=0; i< numBuffers; i++){
if(pid==bufferPool[i].getP
numPinRequests++;
frameNo=bufferPool[i].getF
break;
}
}
if(frameNo != 1)
{
// Get the frame
checkFrame = &bufferPool[frameNo];
// Pin the page to this frame
checkFrame->pin();
// Retrieve page data
page = checkFrame->getPage();
}
else {
numPageMisses++;
// Check if buffer pool can handle more pages
for(int i=0; i<numBuffers; i++)
{
if(bufferPool[i].getPinCou
a++;
if (a == 0 )
{
page = NULL;
MINIBASE_FIRST_ERROR(BUFMG
return FAIL;
}
}
// Get frame from buffer pool
checkFrame = &bufferPool[frameNo];
// Get the page id
pageId = checkFrame->getPageID();
// Check to see if the frame is dirty. In which case it'll be written back out.
dirty = checkFrame->getDirtyBit();
if (dirty)
{
// Write the page
MINIBASE_DB->WritePage(pag
// Increase dirty page written count
numDirtyPagesWritten++;
}
if (!isEmpty)
{
MINIBASE_DB->ReadPage(pid,
}
checkFrame->setAndPinPage(
// Retrieve page data
checkFrame->setPage(tempPa
page = checkFrame->getPage();
}
return OK;
}
//------------------------
// BufMgr::UnpinPage
//
// Input : pid - page id of a particular page
// dirty - indicate whether the page with page id = pid
// is dirty or not. (Optional, default to FALSE)
// Output : None
// Purpose : Unpin the page with page id = pid in the buffer. Mark
// the page dirty if dirty is TRUE.
// Condition: The page is already in the buffer and is pinned.
// PostCond : The page is unpinned and the number of pin on the
// page decrease by one.
// Return : OK if operation is successful. FAIL otherwise.
//------------------------
Status BufMgr::UnpinPage(PageID pid, Bool dirty)
{
int frameNo = -1;
frame *checkFrame = 0;
frameNo=bufferPool[pid].ge
if (frameNo == -1)
{
return FAIL;
}
// Get frame from buffer pool
checkFrame = &bufferPool[frameNo];
// Set dirty flag if dirty == TRUE
if (dirty)
{
checkFrame->setDirtyBit();
}
checkFrame->unpin();
return OK;
}
//------------------------
// BufMgr::FreePage
//
// Input : pid - page id of a particular page
// Output : None
// Purpose : Free the memory allocated for the page with
// page id = pid
// Condition: Either the page is already in the buffer and is pinned
// no more than once, or the page is not in the buffer.
// PostCond : The page is unpinned, and the frame where it resides in
// the buffer pool is freed. Also the page is deallocated
// from the database.
// Return : OK if operation is successful. FAIL otherwise.
// Note : You can call MINIBASE_DB->DeallocatePag
// deallocate a page.
//------------------------
Status BufMgr::FreePage(PageID pid)
{
return OK;
}
//------------------------
// BufMgr::NewPage
//
// Input : howMany - (optional, default to 1) how many pages to
// allocate.
// Output : pid - the page id of the first page (as output by
// DB::AllocatePage) allocated.
// page - a pointer to the page in memory.
// Purpose : Allocate howMany number of pages, and pin the first page
// into the buffer.
// Condition: howMany > 0 and there is at least one free buffer space
// to hold a page.
// PostCond : The page with page id = pid is pinned into the buffer.
// Return : OK if operation is successful. FAIL otherwise.
// Note : You can call MINIBASE_DB->AllocatePage(
// You should call MINIBASE_DB->DeallocatePag
// pages you allocate if you failed to pin the page in the
// buffer.
//------------------------
Status BufMgr::NewPage (int& pid, Page*& page, int howMany)
{
Status stat;
stat = MINIBASE_DB->AllocatePage(
if (stat != OK)
{
MINIBASE_FIRST_ERROR(BUFMG
return FAIL;
}
// Try to pin the first page allocated
stat = PinPage(pid, page);
if (stat != OK)
{
// Deallocate page
if (MINIBASE_DB->DeallocatePa
{
MINIBASE_FIRST_ERROR(BUFMG
return FAIL;
}
}
return OK;
}
//------------------------
// BufMgr::GetNumOfUnpinnedBu
//
// Input : None
// Output : None
// Purpose : Find out how many unpinned locations are in the buffer
// pool.
// Condition: None
// PostCond : None
// Return : The number of unpinned buffers in the buffer pool.
//------------------------
unsigned int BufMgr::GetNumOfUnpinnedBu
{
return 0;
}
//------------------------
// BufMgr::GetNumOfBuffers
//
// Input : None
// Output : None
// Purpose : Find out how many buffers are there in the buffer pool.
// PreCond : None
// PostCond : None
// Return : The number of buffers in the buffer pool.
//------------------------
unsigned int BufMgr::GetNumOfBuffers()
{
return 0;
}
//------------------------
// BufMgr::ResetStat
//
// Input : None
// Output : None
// Purpose : Reset the statistic variables
//------------------------
Status BufMgr::ResetStat( )
{
return OK;
}
//------------------------
// BufMgr::PrintStat
//
// Input : None
// Output : None
// Purpose : Print the statistic variables
//------------------------
Status BufMgr::PrintStat( )
{
return OK;
}
ASKER
I have asked for this kind of sample program, which I can modify.
Anyway Thanks for every one.
Since no one answered my code, I want to delete this question.
BR Dushan
Anyway Thanks for every one.
Since no one answered my code, I want to delete this question.
BR Dushan
ASKER
Sorry not to delete, to refund :).
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
Hi Dushan911,
Do u have the header files as well? And do u have the working database buffer manager now?
Do u have the header files as well? And do u have the working database buffer manager now?