/*******************************************************************************
* 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;
/**
* This class manages the linked lists of logical rowid pages.
*/
final class LogicalRowIdManager {
// our record file and associated page manager
private final RecordFile file;
private final PageManager pageman;
private final FreeLogicalRowIdPageManager freeman;
final short ELEMS_PER_PAGE;
private int blockSize;
/**
* Creates a log rowid manager using the indicated record file and page manager
*/
LogicalRowIdManager(RecordFile file, PageManager pageman,FreeLogicalRowIdPageManager freeman) throws IOException {
this.file = file;
this.pageman = pageman;
this.freeman = freeman;
this.blockSize = file.BLOCK_SIZE;
this.ELEMS_PER_PAGE = (short)((blockSize - TranslationPage.O_TRANS) / TranslationPage.PhysicalRowId_SIZE);
}
/**
* Creates a new logical rowid pointing to the indicated physical id
*/
long insert(long loc) throws IOException {
// check whether there's a free rowid to reuse
long retval = freeman.get();
if (retval == 0) {
// no. This means that we bootstrap things by allocating
// a new translation page and freeing all the rowids on it.
long firstPage = pageman.allocate(Magic.TRANSLATION_PAGE);
short curOffset = TranslationPage.O_TRANS;
for (int i = 0; i < ELEMS_PER_PAGE; i++) {
freeman.put(Location.toLong(firstPage, curOffset));
curOffset += PageHeader.PhysicalRowId_SIZE;
}
retval = freeman.get();
if (retval == 0) {
throw new Error("couldn't obtain free translation");
}
}
// write the translation.
update(retval, loc);
return retval;
}
/**
* Insert at forced location, use only for defragmentation !!
* @param logicalRowId
* @param physLoc
* @throws IOException
*/
void forceInsert(long logicalRowId, long physLoc) throws IOException {
//create pages until we reach requested block
long lastBlock = pageman.getLast(Magic.TRANSLATION_PAGE);
while(lastBlock!=Location.getBlock(logicalRowId)){
lastBlock = pageman.allocate(Magic.TRANSLATION_PAGE);
if(lastBlock>Location.getBlock(logicalRowId))
throw new Error("outallocated");
}
if(fetch(logicalRowId) != 0)
throw new Error("can not forceInsert, record already exists: "+logicalRowId);
update(logicalRowId, physLoc);
}
/**
* Releases the indicated logical rowid.
*/
void delete(long rowid) throws IOException {
//zero out old location, is needed for defragmentation
TranslationPage xlatPage = TranslationPage.getTranslationPageView(file.get(Location.getBlock(rowid)),blockSize);
xlatPage.setLocationBlock(Location.getOffset(rowid), 0);
xlatPage.setLocationOffset(Location.getOffset(rowid), (short)0);
file.release(Location.getBlock(rowid), true);
freeman.put(rowid);
}
/**
* Updates the mapping
*
* @param rowid
* The logical rowid
* @param loc
* The physical rowid
*/
void update(long rowid, long loc) throws IOException {
TranslationPage xlatPage = TranslationPage.getTranslationPageView(file.get(Location.getBlock(rowid)),blockSize);
//make sure it is right type of page
// PhysicalRowId physid = xlatPage.get(rowid.getOffset());
// physid.setBlock(loc.getBlock());
// physid.setOffset(loc.getOffset());
xlatPage.setLocationBlock(Location.getOffset(rowid), Location.getBlock(loc));
xlatPage.setLocationOffset(Location.getOffset(rowid), Location.getOffset(loc));
file.release(Location.getBlock(rowid), true);
}
/**
* Returns a mapping
*
* @param rowid
* The logical rowid
* @return The physical rowid, 0 if does not exist
*/
long fetch(long rowid) throws IOException {
final long block = Location.getBlock(rowid);
long last = pageman.getLast(Magic.TRANSLATION_PAGE);
if(last+1<block)
return 0;
final short offset = Location.getOffset(rowid);
BlockIo bio = file.get(block);
TranslationPage xlatPage = TranslationPage.getTranslationPageView(bio,blockSize);
try {
long retval = Location.toLong(
xlatPage.getLocationBlock(offset),
xlatPage.getLocationOffset(offset));
return retval;
} finally {
file.release(block, false);
}
}
void commit() throws IOException{
freeman.commit();
}
}