WiscDB
|
00001 #include <iostream> 00002 #include <stdlib.h> 00003 #include <cstring> 00004 #include <memory> 00005 #include "include/page.h" 00006 #include "buffer.h" 00007 #include "include/file_iterator.h" 00008 #include "include/page_iterator.h" 00009 #include "exceptions/file_not_found_exception.h" 00010 #include "exceptions/invalid_page_exception.h" 00011 #include "exceptions/page_not_pinned_exception.h" 00012 #include "exceptions/page_pinned_exception.h" 00013 #include "exceptions/buffer_exceeded_exception.h" 00014 00015 #define PRINT_ERROR(str) \ 00016 { \ 00017 std::cerr << "On Line No:" << __LINE__ << "\n"; \ 00018 std::cerr << str << "\n"; \ 00019 exit(1); \ 00020 } 00021 00022 using namespace wiscdb; 00023 00024 const PageId num = 100; 00025 PageId pid[num], pageno1, pageno2, pageno3, i; 00026 RecordId rid[num], rid2, rid3; 00027 Page *page, *page2, *page3; 00028 char tmpbuf[100]; 00029 BufferManager* bufMgr; 00030 File *file1ptr, *file2ptr, *file3ptr, *file4ptr, *file5ptr; 00031 00032 void usePageFile(); 00033 00034 void test1(); 00035 void test2(); 00036 void test3(); 00037 void test4(); 00038 void test5(); 00039 void test6(); 00040 void testBufferManager(); 00041 00042 int main() 00043 { 00044 //usePageFile(); 00045 //This function tests buffer manager, comment this line if you don't wish to test buffer manager 00046 testBufferManager(); 00047 } 00048 00049 void usePageFile(){ 00050 //Following code shows how to use File and Page classes 00051 00052 const std::string& filename = "test.db"; 00053 // Clean up from any previous runs that crashed. 00054 try 00055 { 00056 File::remove(filename); 00057 } 00058 catch(FileNotFoundException) 00059 { 00060 } 00061 00062 // Create a new database file. 00063 File new_file = File::create(filename); 00064 00065 // Allocate some pages and put data on them. 00066 PageId third_page_number; 00067 for (int i = 0; i < 5; ++i) { 00068 Page new_page = new_file.allocatePage(); 00069 if (i == 3) { 00070 // Keep track of the identifier for the third page so we can read it 00071 // later. 00072 third_page_number = new_page.page_number(); 00073 } 00074 new_page.insertRecord("hello!"); 00075 // Write the page back to the file (with the new data). 00076 new_file.writePage(new_page); 00077 } 00078 00079 // Iterate through all pages in the file. 00080 for (FileIterator iter = new_file.begin(); iter != new_file.end(); ++iter) { 00081 // Iterate through all records on the page. 00082 for (PageIterator page_iter = (*iter).begin(); page_iter != (*iter).end(); 00083 ++page_iter) { 00084 std::cout << "Found record: " << *page_iter 00085 << " on page " << (*iter).page_number() << "\n"; 00086 } 00087 } 00088 00089 // Retrieve the third page and add another record to it. 00090 Page third_page = new_file.readPage(third_page_number); 00091 const RecordId& rid = third_page.insertRecord("world!"); 00092 new_file.writePage(third_page); 00093 00094 // Retrieve the record we just added to the third page. 00095 std::cout << "Third page has a new record: " 00096 << third_page.getRecord(rid) << "\n\n"; 00097 new_file.close(); 00098 // new_file goes out of scope here, so file is automatically closed. 00099 // Delete the file since we're done with it. 00100 File::remove(filename); 00101 } 00102 00103 void testBufferManager() 00104 { 00105 // create buffer manager 00106 bufMgr = new BufferManager(num); 00107 00108 // create dummy files 00109 const std::string& filename1 = "test.1"; 00110 const std::string& filename2 = "test.2"; 00111 const std::string& filename3 = "test.3"; 00112 const std::string& filename4 = "test.4"; 00113 const std::string& filename5 = "test.5"; 00114 00115 try 00116 { 00117 File::remove(filename1); 00118 File::remove(filename2); 00119 File::remove(filename3); 00120 File::remove(filename4); 00121 File::remove(filename5); 00122 } 00123 catch(FileNotFoundException e) 00124 { 00125 } 00126 00127 File file1 = File::create(filename1); 00128 File file2 = File::create(filename2); 00129 File file3 = File::create(filename3); 00130 File file4 = File::create(filename4); 00131 File file5 = File::create(filename5); 00132 00133 file1ptr = &file1; 00134 file2ptr = &file2; 00135 file3ptr = &file3; 00136 file4ptr = &file4; 00137 file5ptr = &file5; 00138 00139 //Test buffer manager 00140 //Comment tests which you do not wish to run now. Tests are dependent on their preceding tests. So, they have to be run in the following order. 00141 //Commenting a particular test requires commenting all tests that follow it else those tests would fail. 00142 test1(); 00143 test2(); 00144 test3(); 00145 test4(); 00146 test5(); 00147 test6(); 00148 00149 //Close files before deleting them 00150 file1.close(); 00151 file2.close(); 00152 file3.close(); 00153 file4.close(); 00154 file5.close(); 00155 00156 //Delete files 00157 File::remove(filename1); 00158 File::remove(filename2); 00159 File::remove(filename3); 00160 File::remove(filename4); 00161 File::remove(filename5); 00162 00163 delete bufMgr; 00164 00165 std::cout << "\n" << "Passed all tests." << "\n"; 00166 } 00167 00168 void test1() 00169 { 00170 //Allocating pages in a file... 00171 for (i = 0; i < num; i++) 00172 { 00173 bufMgr->allocatePage(file1ptr, pid[i], page); 00174 sprintf((char*)tmpbuf, "test.1 Page %d %7.1f", pid[i], (float)pid[i]); 00175 rid[i] = page->insertRecord(tmpbuf); 00176 bufMgr->unPinPage(file1ptr, pid[i], true); 00177 } 00178 00179 //Reading pages back... 00180 for (i = 0; i < num; i++) 00181 { 00182 bufMgr->readPage(file1ptr, pid[i], page); 00183 sprintf((char*)&tmpbuf, "test.1 Page %d %7.1f", pid[i], (float)pid[i]); 00184 if(strncmp(page->getRecord(rid[i]).c_str(), tmpbuf, strlen(tmpbuf)) != 0) 00185 { 00186 PRINT_ERROR("ERROR :: CONTENTS DID NOT MATCH"); 00187 } 00188 bufMgr->unPinPage(file1ptr, pid[i], false); 00189 } 00190 std::cout<< "Test 1 passed" << "\n"; 00191 } 00192 00193 void test2() 00194 { 00195 //Writing and reading back multiple files 00196 //The page number and the value should match 00197 00198 for (i = 0; i < num/3; i++) 00199 { 00200 bufMgr->allocatePage(file2ptr, pageno2, page2); 00201 sprintf((char*)tmpbuf, "test.2 Page %d %7.1f", pageno2, (float)pageno2); 00202 rid2 = page2->insertRecord(tmpbuf); 00203 00204 int index = random() % num; 00205 pageno1 = pid[index]; 00206 bufMgr->readPage(file1ptr, pageno1, page); 00207 sprintf((char*)tmpbuf, "test.1 Page %d %7.1f", pageno1, (float)pageno1); 00208 if(strncmp(page->getRecord(rid[index]).c_str(), tmpbuf, strlen(tmpbuf)) != 0) 00209 { 00210 PRINT_ERROR("ERROR :: CONTENTS DID NOT MATCH"); 00211 } 00212 00213 bufMgr->allocatePage(file3ptr, pageno3, page3); 00214 sprintf((char*)tmpbuf, "test.3 Page %d %7.1f", pageno3, (float)pageno3); 00215 rid3 = page3->insertRecord(tmpbuf); 00216 00217 bufMgr->readPage(file2ptr, pageno2, page2); 00218 sprintf((char*)&tmpbuf, "test.2 Page %d %7.1f", pageno2, (float)pageno2); 00219 if(strncmp(page2->getRecord(rid2).c_str(), tmpbuf, strlen(tmpbuf)) != 0) 00220 { 00221 PRINT_ERROR("ERROR :: CONTENTS DID NOT MATCH"); 00222 } 00223 00224 bufMgr->readPage(file3ptr, pageno3, page3); 00225 sprintf((char*)&tmpbuf, "test.3 Page %d %7.1f", pageno3, (float)pageno3); 00226 if(strncmp(page3->getRecord(rid3).c_str(), tmpbuf, strlen(tmpbuf)) != 0) 00227 { 00228 PRINT_ERROR("ERROR :: CONTENTS DID NOT MATCH"); 00229 } 00230 00231 bufMgr->unPinPage(file1ptr, pageno1, false); 00232 } 00233 00234 for (i = 0; i < num/3; i++) { 00235 bufMgr->unPinPage(file2ptr, i+1, true); 00236 bufMgr->unPinPage(file2ptr, i+1, true); 00237 bufMgr->unPinPage(file3ptr, i+1, true); 00238 bufMgr->unPinPage(file3ptr, i+1, true); 00239 } 00240 00241 std::cout << "Test 2 passed" << "\n"; 00242 } 00243 00244 void test3() 00245 { 00246 try 00247 { 00248 bufMgr->readPage(file4ptr, 1, page); 00249 PRINT_ERROR("ERROR :: File4 should not exist. Exception should have been thrown before execution reaches this point."); 00250 } 00251 catch(InvalidPageException e) 00252 { 00253 } 00254 00255 std::cout << "Test 3 passed" << "\n"; 00256 } 00257 00258 void test4() 00259 { 00260 bufMgr->allocatePage(file4ptr, i, page); 00261 bufMgr->unPinPage(file4ptr, i, true); 00262 try 00263 { 00264 bufMgr->unPinPage(file4ptr, i, false); 00265 PRINT_ERROR("ERROR :: Page is already unpinned. Exception should have been thrown before execution reaches this point."); 00266 } 00267 catch(PageNotPinnedException e) 00268 { 00269 } 00270 00271 std::cout << "Test 4 passed" << "\n"; 00272 } 00273 00274 void test5() 00275 { 00276 for (i = 0; i < num; i++) { 00277 bufMgr->allocatePage(file5ptr, pid[i], page); 00278 sprintf((char*)tmpbuf, "test.5 Page %d %7.1f", pid[i], (float)pid[i]); 00279 rid[i] = page->insertRecord(tmpbuf); 00280 } 00281 00282 PageId tmp; 00283 try 00284 { 00285 bufMgr->allocatePage(file5ptr, tmp, page); 00286 PRINT_ERROR("ERROR :: No more frames left for allocation. Exception should have been thrown before execution reaches this point."); 00287 } 00288 catch(BufferExceededException e) 00289 { 00290 } 00291 00292 std::cout << "Test 5 passed" << "\n"; 00293 00294 for (i = 1; i <= num; i++) 00295 bufMgr->unPinPage(file5ptr, i, true); 00296 } 00297 00298 void test6() 00299 { 00300 //flushing file with pages still pinned. Should generate an error 00301 for (i = 1; i <= num; i++) { 00302 bufMgr->readPage(file1ptr, i, page); 00303 } 00304 00305 try 00306 { 00307 bufMgr->flushFile(file1ptr); 00308 PRINT_ERROR("ERROR :: Pages pinned for file being flushed. Exception should have been thrown before execution reaches this point."); 00309 } 00310 catch(PagePinnedException e) 00311 { 00312 } 00313 00314 std::cout << "Test 6 passed" << "\n"; 00315 00316 for (i = 1; i <= num; i++) 00317 bufMgr->unPinPage(file1ptr, i, true); 00318 00319 bufMgr->flushFile(file1ptr); 00320 }