BadgerDB
|
00001 00008 #include <cstring> 00009 #include "filescan.h" 00010 #include "exceptions/end_of_file_exception.h" 00011 #include "exceptions/file_not_found_exception.h" 00012 #include "exceptions/insufficient_space_exception.h" 00013 00014 namespace badgerdb { 00015 00016 FileScan::FileScan(const std::string &name, BufMgr *bufferMgr) 00017 { 00018 try 00019 { 00020 file = new PageFile(name, false); //dont create new file 00021 //std::cout << "File:" << name << " opened.\n"; 00022 } 00023 catch(FileNotFoundException e) 00024 { 00025 file = new PageFile(name, true); //dont create new file 00026 //std::cout << "File:" << name << " created.\n"; 00027 } 00028 00029 bufMgr = bufferMgr; 00030 curDirtyFlag = false; 00031 curPage = NULL; 00032 filePageIter = file->begin(); 00033 } 00034 00035 void FileScan::gotoMark(RecordId rid) 00036 { 00037 if(curPage != NULL) 00038 { 00039 bufMgr->unPinPage(file, (*filePageIter).page_number(), curDirtyFlag); 00040 } 00041 00042 curDirtyFlag = false; 00043 filePageIter = file->beginAt(rid.page_number); 00044 bufMgr->readPage(file, rid.page_number, curPage); 00045 pageRecordIter = curPage->beginAt(rid.slot_number); 00046 } 00047 00048 void FileScan::insertRecord(const std::string &rec, RecordId &outRid) 00049 { 00050 Page *iPage; 00051 PageId iPageNo; 00052 00053 for (FileIterator iter = file->begin(); iter != file->end(); ++iter) 00054 { 00055 iPageNo = iter.getCurrentPageNo(); 00056 00057 if(iPageNo == Page::INVALID_NUMBER) 00058 break; 00059 00060 bufMgr->readPage(file, iPageNo, iPage); 00061 00062 try 00063 { 00064 outRid = iPage->insertRecord(rec); 00065 bufMgr->unPinPage(file, iPageNo, true); 00066 return; 00067 } 00068 catch(InsufficientSpaceException &e) 00069 { 00070 bufMgr->unPinPage(file, iPageNo, false); 00071 } 00072 } 00073 00074 bufMgr->allocPage(file, iPageNo, iPage); 00075 outRid = iPage->insertRecord(rec); 00076 bufMgr->unPinPage(file, iPageNo, true); 00077 } 00078 00079 void FileScan::deleteRecord(RecordId rid) 00080 { 00081 Page *dPage; 00082 bufMgr->readPage(file, rid.page_number, dPage); 00083 dPage->deleteRecord(rid); 00084 bufMgr->unPinPage(file, rid.page_number, true); 00085 } 00086 00087 void FileScan::flushFile() 00088 { 00089 // generally must unpin last page of the scan 00090 if (curPage != NULL) 00091 { 00092 bufMgr->unPinPage(file, (*filePageIter).page_number(), curDirtyFlag); 00093 curPage = NULL; 00094 curDirtyFlag = false; 00095 filePageIter = file->begin(); 00096 } 00097 00098 bufMgr->flushFile(file); 00099 } 00100 00101 FileScan::~FileScan() 00102 { 00103 flushFile(); 00104 00105 delete file; 00106 } 00107 00108 void FileScan::startScan(int offsetIn, int lengthIn, Datatype typeIn, std::string filterIn, Operator opIn) 00109 { 00110 curPage = NULL; 00111 curDirtyFlag = false; 00112 filePageIter = file->begin(); 00113 00114 if (filterIn.empty()) { // no filtering requested 00115 filter.clear(); 00116 return; 00117 } 00118 00119 offset = offsetIn; 00120 length = lengthIn; 00121 type = typeIn; 00122 filter = filterIn; 00123 op = opIn; 00124 } 00125 00126 void FileScan::endScan() 00127 { 00128 if (curPage != NULL) 00129 { 00130 bufMgr->unPinPage(file, (*filePageIter).page_number(), curDirtyFlag); 00131 } 00132 00133 curPage = NULL; 00134 curDirtyFlag = false; 00135 filePageIter = file->begin(); 00136 filter.clear(); 00137 } 00138 00139 void FileScan::scanNext(RecordId& outRid) 00140 { 00141 std::string rec; 00142 00143 if(filePageIter == file->end()) 00144 { 00145 throw EndOfFileException(); 00146 } 00147 00148 // special case of the first record of the first page of the file 00149 if (curPage == NULL) 00150 { 00151 // need to get the first page of the file 00152 filePageIter = file->begin(); 00153 if(filePageIter == file->end()) 00154 { 00155 throw EndOfFileException(); 00156 } 00157 00158 // read the first page of the file 00159 bufMgr->readPage(file, (*filePageIter).page_number(), curPage); 00160 curDirtyFlag = false; 00161 00162 // get the first record off the page 00163 pageRecordIter = curPage->begin(); 00164 00165 if(pageRecordIter != curPage->end()) 00166 { 00167 // get pointer to record 00168 rec = *pageRecordIter; 00169 if(matchRec(rec)) 00170 { 00171 outRid = pageRecordIter.getCurrentRecord(); 00172 return; 00173 } 00174 } 00175 } 00176 00177 // Loop, looking for a record that satisfied the predicate. 00178 // First try and get the next record off the current page 00179 pageRecordIter++; 00180 00181 while(1) 00182 { 00183 while (pageRecordIter == curPage->end()) 00184 { 00185 // unpin the current page 00186 bufMgr->unPinPage(file, (*filePageIter).page_number(), curDirtyFlag); 00187 curPage = NULL; 00188 curDirtyFlag = false; 00189 00190 filePageIter++; 00191 if (filePageIter == file->end()) 00192 { 00193 curPage = NULL; 00194 throw EndOfFileException(); 00195 } 00196 00197 // read the next page of the file 00198 bufMgr->readPage(file, (*filePageIter).page_number(), curPage); 00199 00200 // get the first record off the page 00201 pageRecordIter = curPage->begin(); 00202 } 00203 00204 while (pageRecordIter != curPage->end()) 00205 { 00206 rec = *pageRecordIter; 00207 00208 if(matchRec(rec)) 00209 { 00210 // return rid of the record 00211 outRid = pageRecordIter.getCurrentRecord(); 00212 return; 00213 } 00214 pageRecordIter++; 00215 } 00216 } 00217 } 00218 00219 // returns pointer to the current record. page is left pinned 00220 // and the scan logic is required to unpin the page 00221 std::string FileScan::getRecord() 00222 { 00223 return *pageRecordIter; 00224 } 00225 00226 std::string FileScan::getRandomRecord(RecordId rid) 00227 { 00228 // Solution Starts 00229 Page* page; 00230 00231 bufMgr->readPage(file, rid.page_number, page); 00232 std::string retStr = page->getRecord(rid); 00233 bufMgr->unPinPage(file, rid.page_number, false); 00234 00235 return retStr; 00236 } 00237 00238 bool FileScan::matchRec(const std::string &rec) 00239 { 00240 // no filtering requested 00241 if (filter.empty()) return true; 00242 00243 // see if offset + length is beyond end of record 00244 // maybe this should be an error??? 00245 if ((offset + length -1 ) >= rec.size()) 00246 return false; 00247 00248 double diff = 0; // < 0 if attr < fltr 00249 switch(type) { 00250 00251 case INTEGER: 00252 int iattr, ifltr; // word-alignment problem possible 00253 memcpy(&iattr, rec.c_str() + offset, length); 00254 memcpy(&ifltr, filter.c_str(), length); 00255 //ifltr = atoi(filter.c_str()); 00256 diff = iattr - ifltr; 00257 break; 00258 00259 case DOUBLE: 00260 double fattr, ffltr; // word-alignment problem possible 00261 memcpy(&fattr, rec.c_str() + offset, length); 00262 memcpy(&ffltr, filter.c_str(), length); 00263 //ffltr = atof(filter.c_str()); 00264 diff = fattr - ffltr; 00265 break; 00266 00267 case STRING: 00268 diff = strncmp(rec.c_str() + offset, filter.c_str(), length); 00269 break; 00270 } 00271 00272 switch(op) { 00273 case LT: if (diff < 0.0) return true; break; 00274 case LTE: if (diff <= 0.0) return true; break; 00275 case EQ: if (diff == 0.0) return true; break; 00276 case GTE: if (diff >= 0.0) return true; break; 00277 case GT: if (diff > 0.0) return true; break; 00278 case NE: if (diff != 0.0) return true; break; 00279 default: break; 00280 } 00281 00282 return false; 00283 00284 } 00285 00286 // mark current page of scan dirty 00287 void FileScan::markDirty() 00288 { 00289 curDirtyFlag = true; 00290 } 00291 00292 }