/*******************************************************************************
* 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;
/**
* Class describing a page that holds logical rowids that were freed. Note
* that the methods have *physical* rowids in their signatures - this is
* because logical and physical rowids are internally the same, only their
* external representation (i.e. in the client API) differs.
*/
final class FreeLogicalRowIdPage extends PageHeader {
// offsets
private static final short O_COUNT = PageHeader.SIZE; // short count
static final short O_FREE = (short)(O_COUNT + Magic.SZ_SHORT);
final short ELEMS_PER_PAGE;
private int previousFoundFree = 0; // keeps track of the most recent found free slot so we can locate it again quickly
private int previousFoundAllocated = 0; // keeps track of the most recent found allocated slot so we can locate it again quickly
// slots we returned.
//final PhysicalRowId[] slots = new PhysicalRowId[ELEMS_PER_PAGE];
/**
* Constructs a data page view from the indicated block.
*/
FreeLogicalRowIdPage(BlockIo block, int blockSize) {
super(block);
ELEMS_PER_PAGE = (short) ((blockSize - O_FREE) / PhysicalRowId_SIZE);
}
/**
* Factory method to create or return a data page for the
* indicated block.
*/
static FreeLogicalRowIdPage getFreeLogicalRowIdPageView(BlockIo block, int blockSize) {
BlockView view = block.getView();
if (view != null && view instanceof FreeLogicalRowIdPage)
return (FreeLogicalRowIdPage) view;
else
return new FreeLogicalRowIdPage(block,blockSize);
}
/** Returns the number of free rowids on this page. */
short getCount() {
return block.readShort(O_COUNT);
}
/** Sets the number of free rowids */
protected void setCount(short i) {
block.writeShort(O_COUNT, i);
}
/** Frees a slot */
void free(int slot) {
setLocationBlock(slotToOffset(slot), 0);
//get(slot).setBlock(0);
setCount((short) (getCount() - 1));
// update previousFoundFree if the freed slot is before what we've found in the past
if (slot < previousFoundFree)
previousFoundFree = slot;
}
/** Allocates a slot */
short alloc(int slot) {
setCount((short) (getCount() + 1));
short pos = slotToOffset(slot);
setLocationBlock(pos, -1);
//get(slot).setBlock(-1);
// update previousFoundAllocated if the newly allocated slot is before what we've found in the past
if (slot < previousFoundAllocated)
previousFoundAllocated = slot;
return pos;
}
/** Returns true if a slot is allocated */
boolean isAllocated(int slot) {
//return get(slot).getBlock() > 0;
return getLocationBlock(slotToOffset(slot)) > 0;
}
/** Returns true if a slot is free */
boolean isFree(int slot) {
return !isAllocated(slot);
}
// /** Returns the value of the indicated slot */
// PhysicalRowId get(int slot) {
// if (slots[slot] == null)
// slots[slot] = new PhysicalRowId(block, slotToOffset(slot));;
// return slots[slot];
// }
//
/** Converts slot to offset */
short slotToOffset(int slot) {
return (short) (O_FREE +
(slot * PhysicalRowId_SIZE));
}
/**
* Returns first free slot, -1 if no slots are available
*/
int getFirstFree() {
for (; previousFoundFree < ELEMS_PER_PAGE; previousFoundFree++) {
if (isFree(previousFoundFree))
return previousFoundFree;
}
return -1;
}
/**
* Returns first allocated slot, -1 if no slots are available.
*/
int getFirstAllocated() {
for (; previousFoundAllocated < ELEMS_PER_PAGE; previousFoundAllocated++) {
if (isAllocated(previousFoundAllocated))
return previousFoundAllocated;
}
return -1;
}
public long slotToLocation(int slot) {
short pos = slotToOffset(slot);
return Location.toLong(getLocationBlock(pos),getLocationOffset(pos));
}
}