Get the page number of the first empty page in this BTreeFile. Creates a new page if none of the existing pages are empty. @param tid - the transaction id @param dirtypages - the list of dirty pages which should be updated with all new dirty pages @return the page number of the first empty page @t
(TransactionId tid, Map<PageId, Page> dirtypages)
| 1109 | * @throws TransactionAbortedException |
| 1110 | */ |
| 1111 | public int getEmptyPageNo(TransactionId tid, Map<PageId, Page> dirtypages) |
| 1112 | throws DbException, IOException, TransactionAbortedException { |
| 1113 | // get a read lock on the root pointer page and use it to locate the first header page |
| 1114 | BTreeRootPtrPage rootPtr = getRootPtrPage(tid, dirtypages); |
| 1115 | BTreePageId headerId = rootPtr.getHeaderId(); |
| 1116 | int emptyPageNo = 0; |
| 1117 | |
| 1118 | if(headerId != null) { |
| 1119 | BTreeHeaderPage headerPage = (BTreeHeaderPage) getPage(tid, dirtypages, headerId, Permissions.READ_ONLY); |
| 1120 | int headerPageCount = 0; |
| 1121 | // try to find a header page with an empty slot |
| 1122 | while(headerPage != null && headerPage.getEmptySlot() == -1) { |
| 1123 | headerId = headerPage.getNextPageId(); |
| 1124 | if(headerId != null) { |
| 1125 | headerPage = (BTreeHeaderPage) getPage(tid, dirtypages, headerId, Permissions.READ_ONLY); |
| 1126 | headerPageCount++; |
| 1127 | } |
| 1128 | else { |
| 1129 | headerPage = null; |
| 1130 | } |
| 1131 | } |
| 1132 | |
| 1133 | // if headerPage is not null, it must have an empty slot |
| 1134 | if(headerPage != null) { |
| 1135 | headerPage = (BTreeHeaderPage) getPage(tid, dirtypages, headerId, Permissions.READ_WRITE); |
| 1136 | int emptySlot = headerPage.getEmptySlot(); |
| 1137 | headerPage.markSlotUsed(emptySlot, true); |
| 1138 | emptyPageNo = headerPageCount * BTreeHeaderPage.getNumSlots() + emptySlot; |
| 1139 | } |
| 1140 | } |
| 1141 | |
| 1142 | // at this point if headerId is null, either there are no header pages |
| 1143 | // or there are no free slots |
| 1144 | if(headerId == null) { |
| 1145 | synchronized(this) { |
| 1146 | // create the new page |
| 1147 | BufferedOutputStream bw = new BufferedOutputStream( |
| 1148 | new FileOutputStream(f, true)); |
| 1149 | byte[] emptyData = BTreeInternalPage.createEmptyPageData(); |
| 1150 | bw.write(emptyData); |
| 1151 | bw.close(); |
| 1152 | emptyPageNo = numPages(); |
| 1153 | } |
| 1154 | } |
| 1155 | |
| 1156 | return emptyPageNo; |
| 1157 | } |
| 1158 | |
| 1159 | /** |
| 1160 | * Method to encapsulate the process of creating a new page. It reuses old pages if possible, |