/******************************************************************************* * Copyright 2010 Cees De Groot, Alex Boisvert, Jan Kotek * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package de.mxro.thrd.jdbm2V22.recman; import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * This class manages free Logical rowid pages and provides methods * to free and allocate Logical rowids on a high level. */ final class FreeLogicalRowIdPageManager { // our record file private RecordFile file; // our page manager private PageManager pageman; private int blockSize; final List<Long> freeBlocksInTransactionRowid = new ArrayList<Long>(); /** * Creates a new instance using the indicated record file and * page manager. */ FreeLogicalRowIdPageManager(RecordFile file, PageManager pageman) throws IOException { this.file = file; this.pageman = pageman; this.blockSize = file.BLOCK_SIZE; } /** * Returns a free Logical rowid, or * 0 if nothing was found. */ long get() throws IOException { if(!freeBlocksInTransactionRowid.isEmpty()){ long first = freeBlocksInTransactionRowid.get(freeBlocksInTransactionRowid.size()-1); freeBlocksInTransactionRowid.remove(freeBlocksInTransactionRowid.size()-1); return first; } // Loop through the free Logical rowid list until we find // the first rowid. long retval = 0; PageCursor curs = new PageCursor(pageman, Magic.FREELOGIDS_PAGE); while (curs.next() != 0) { FreeLogicalRowIdPage fp = FreeLogicalRowIdPage .getFreeLogicalRowIdPageView(file.get(curs.getCurrent()),blockSize); int slot = fp.getFirstAllocated(); if (slot != -1) { // got one! retval = fp.slotToLocation(slot); fp.free(slot); if (fp.getCount() == 0) { // page became empty - free it file.release(curs.getCurrent(), false); pageman.free(Magic.FREELOGIDS_PAGE, curs.getCurrent()); } else file.release(curs.getCurrent(), true); return retval; } else { // no luck, go to next page file.release(curs.getCurrent(), false); } } return 0; } /** * Puts the indicated rowid on the free list */ void put(long rowid)throws IOException { freeBlocksInTransactionRowid.add(Long.valueOf(rowid)); } public void commit() throws IOException { //write all uncommited free records Iterator<Long> rowidIter = freeBlocksInTransactionRowid.iterator(); PageCursor curs = new PageCursor(pageman, Magic.FREELOGIDS_PAGE); //iterate over filled pages while (curs.next() != 0) { long freePage = curs.getCurrent(); BlockIo curBlock = file.get(freePage); FreeLogicalRowIdPage fp = FreeLogicalRowIdPage.getFreeLogicalRowIdPageView(curBlock, blockSize); int slot = fp.getFirstFree(); //iterate over free slots in page and fill them while(slot!=-1 && rowidIter.hasNext()){ long rowid = rowidIter.next(); short freePhysRowId = fp.alloc(slot); fp.setLocationBlock(freePhysRowId, Location.getBlock(rowid)); fp.setLocationOffset(freePhysRowId, Location.getOffset(rowid)); slot = fp.getFirstFree(); } file.release(freePage, true); if(!rowidIter.hasNext()) break; } //now we propably filled all already allocated pages, //time to start allocationg new pages while(rowidIter.hasNext()){ //allocate new page long freePage = pageman.allocate(Magic.FREELOGIDS_PAGE); BlockIo curBlock = file.get(freePage); FreeLogicalRowIdPage fp = FreeLogicalRowIdPage.getFreeLogicalRowIdPageView(curBlock, blockSize); int slot = fp.getFirstFree(); //iterate over free slots in page and fill them while(slot!=-1 && rowidIter.hasNext()){ long rowid = rowidIter.next(); short freePhysRowId = fp.alloc(slot); fp.setLocationBlock(freePhysRowId, Location.getBlock(rowid)); fp.setLocationOffset(freePhysRowId, Location.getOffset(rowid)); slot = fp.getFirstFree(); } file.release(freePage, true); if(!rowidIter.hasNext()) break; } if(rowidIter.hasNext()) throw new InternalError(); freeBlocksInTransactionRowid.clear(); } }