| /* |
| * Copyright 2009-2010 by The Regents of the University of California |
| * 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 from |
| * |
| * 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 edu.uci.ics.hyracks.storage.am.common.frames; |
| |
| import java.nio.ByteBuffer; |
| |
| import edu.uci.ics.hyracks.storage.am.common.api.ITreeIndexMetaDataFrame; |
| import edu.uci.ics.hyracks.storage.common.buffercache.ICachedPage; |
| |
| // all meta pages of this kind have a negative level |
| // the first meta page has level -1, all other meta pages have level -2 |
| // the first meta page is special because it guarantees to have a correct max page |
| // other meta pages (i.e., with level -2) have junk in the max page field |
| |
| public class LIFOMetaDataFrame implements ITreeIndexMetaDataFrame { |
| |
| // Arbitrarily chosen magic integer. |
| protected static final int MAGIC_VALID_INT = 0x5bd1e995; |
| |
| protected static final int tupleCountOff = 0; //0 |
| protected static final int freeSpaceOff = tupleCountOff + 4; //4 |
| protected static final int maxPageOff = freeSpaceOff + 4; //8 |
| protected static final int levelOff = maxPageOff + 12; //20 |
| protected static final int nextPageOff = levelOff + 1; // 21 |
| protected static final int validOff = nextPageOff + 4; // 25 |
| protected static final int lsnOff = validOff + 4; // 29 |
| |
| protected ICachedPage page = null; |
| protected ByteBuffer buf = null; |
| |
| public int getMaxPage() { |
| return buf.getInt(maxPageOff); |
| } |
| |
| public void setMaxPage(int maxPage) { |
| buf.putInt(maxPageOff, maxPage); |
| } |
| |
| public int getFreePage() { |
| int tupleCount = buf.getInt(tupleCountOff); |
| if (tupleCount > 0) { |
| // return the last page from the linked list of free pages |
| // TODO: this is a dumb policy, but good enough for now |
| int lastPageOff = buf.getInt(freeSpaceOff) - 4; |
| buf.putInt(freeSpaceOff, lastPageOff); |
| buf.putInt(tupleCountOff, tupleCount - 1); |
| return buf.getInt(lastPageOff); |
| } else { |
| return -1; |
| } |
| } |
| |
| // must be checked before adding free page |
| // user of this class is responsible for getting a free page as a new meta |
| // page, latching it, etc. if there is no space on this page |
| public boolean hasSpace() { |
| return buf.getInt(freeSpaceOff) + 4 < buf.capacity(); |
| } |
| |
| // no bounds checking is done, there must be free space |
| public void addFreePage(int freePage) { |
| int freeSpace = buf.getInt(freeSpaceOff); |
| buf.putInt(freeSpace, freePage); |
| buf.putInt(freeSpaceOff, freeSpace + 4); |
| buf.putInt(tupleCountOff, buf.getInt(tupleCountOff) + 1); |
| } |
| |
| @Override |
| public byte getLevel() { |
| return buf.get(levelOff); |
| } |
| |
| @Override |
| public void setLevel(byte level) { |
| buf.put(levelOff, level); |
| } |
| |
| @Override |
| public ICachedPage getPage() { |
| return page; |
| } |
| |
| @Override |
| public void setPage(ICachedPage page) { |
| this.page = page; |
| this.buf = page.getBuffer(); |
| } |
| |
| @Override |
| public void initBuffer(byte level) { |
| buf.putInt(tupleCountOff, 0); |
| buf.putInt(freeSpaceOff, lsnOff + 4); |
| //buf.putInt(maxPageOff, -1); |
| buf.put(levelOff, level); |
| buf.putInt(nextPageOff, -1); |
| setValid(false); |
| } |
| |
| @Override |
| public int getNextPage() { |
| return buf.getInt(nextPageOff); |
| } |
| |
| @Override |
| public void setNextPage(int nextPage) { |
| buf.putInt(nextPageOff, nextPage); |
| } |
| |
| @Override |
| public boolean isValid() { |
| return buf.getInt(validOff) == MAGIC_VALID_INT; |
| } |
| |
| @Override |
| public void setValid(boolean isValid) { |
| if (isValid) { |
| buf.putInt(validOff, MAGIC_VALID_INT); |
| } else { |
| buf.putInt(validOff, 0); |
| } |
| } |
| |
| @Override |
| public long getLSN() { |
| return buf.getLong(lsnOff); |
| } |
| |
| @Override |
| public void setLSN(long lsn) { |
| buf.putLong(lsnOff, lsn); |
| } |
| } |